<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・SCI I/O 制御 @n
			Copyright 2013 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "rx63x/sci.hpp"
#include "rx63x/system.hpp"
#include "rx63x/icu.hpp"
#include "vect.h"
#include "fifo.hpp"

/// F_PCKB はボーレートパラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCKB
#  error "sci_io.hpp requires F_PCKB to be defined"
#endif

namespace device {

	static const uint32_t recv_size = 256;
	static const uint32_t send_size = 128;

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCI I/O 制御クラス
		@param[in]	SCI	SCIx 定義クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCIx>
	class sci_io {

		static utils::fifo<recv_size>	recv_;
		static utils::fifo<send_size>	send_;

		uint8_t	intr_level_;
		bool	crlf_;
		bool	polling_;

		// ※必要なら、実装する
		void sleep_() { }

		static INTERRUPT_FUNC void recv_task_()
		{
			bool err = false;
			if(SCIx::SSR.ORER()) {	///< 受信オーバランエラー状態確認
				SCIx::SSR = 0x00;	///< 受信オーバランエラークリア
				err = true;
			}
			///< フレーミングエラー/パリティエラー状態確認
			if(SCIx::SSR() & (SCIx::SSR.FER.b() | SCIx::SSR.PER.b())) {
				err = true;
			}
			if(!err) recv_.put(SCIx::RDR());
		}

		static INTERRUPT_FUNC void send_task_()
		{
			SCIx::TDR = send_.get();
			if(send_.length() == 0) {
				SCIx::SCR.TEIE = 0;
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		sci_io() : intr_level_(1), crlf_(true), polling_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  初期化 @n
					※ポーリングの場合は設定しなくても良い
			@param[in]	level	割り込みレベル
		*/
		//-----------------------------------------------------------------//
		void initialize(uint32_t level) {
			intr_level_ = level;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ボーレートを設定して、SCI を有効にする
			@param[in]	baud	ボーレート
			@param[in]	polling	ポーリングの場合「true」
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t baud, bool polling = false) {
			polling_ = polling;

			uint32_t brr = F_PCKB / baud / 16;
			uint8_t cks = 0;
			while(brr > 512) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3 || brr == 0) return false;
			bool abcs = true;
			if(brr > 256) { brr /= 2; abcs = false; }

			uint32_t chanel = SCIx::get_chanel();
			switch(chanel) {
			case 0:
				SYSTEM::MSTPCRB.MSTPB31 = 0;	// B31 (SCI0)のストップ状態解除
				break;
			case 1:
				SYSTEM::MSTPCRB.MSTPB30 = 0;	// B30 (SCI1)のストップ状態解除
				break;
			case 2:
				SYSTEM::MSTPCRB.MSTPB29 = 0;	// B29 (SCI2)のストップ状態解除
				break;
			case 3:
				SYSTEM::MSTPCRB.MSTPB28 = 0;	// B28 (SCI3)のストップ状態解除
				break;
			}

			SCIx::SCR = 0x00;			// TE, RE disable.

			if(polling_) {
				switch(chanel) {
				case 0:
					ICU::IER.TEI0 = false;
					ICU::IER.RXI0 = false;
					break;
				case 1:
					ICU::IER.TEI1 = false;
					ICU::IER.RXI1 = false;
					break;
				case 2:
					ICU::IER.TEI2 = false;
					ICU::IER.RXI2 = false;
					break;
				case 3:
					ICU::IER.TEI3 = false;
					ICU::IER.RXI3 = false;
					break;
				default:
					return false;
				}
			} else {
				switch(chanel) {
				case 0:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI0);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI0);
					ICU::IER.RXI0 = true;
					ICU::IER.TEI0 = true;
					ICU::IPR.SCI0 = intr_level_;
					break;
				case 1:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI1);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI1);
					ICU::IER.RXI1 = true;
					ICU::IER.TEI1 = true;
					ICU::IPR.SCI1 = intr_level_;
					break;
				case 2:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI2);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI2);
					ICU::IER.RXI2 = true;
					ICU::IER.TEI2 = true;
					ICU::IPR.SCI2 = intr_level_;
					break;
				case 3:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI3);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI3);
					ICU::IER.RXI3 = true;
					ICU::IER.TEI3 = true;
					ICU::IPR.SCI3 = intr_level_;
					break;
				default:
					return false;
				}
			}

			// 8 bits, 1 stop bit, no-parrity
			SCIx::SMR = cks;
			SCIx::SEMR.ABCS = abcs;
			SCIx::BRR = static_cast<uint8_t>(brr - 1);

			if(polling_) {
				SCIx::SCR = SCIx::SCR.TE.b() | SCIx::SCR.RE.b();
			} else {
				SCIx::SCR = SCIx::SCR.RIE.b() | SCIx::SCR.TE.b() | SCIx::SCR.RE.b();
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	CRLF 自動送出
			@param[in]	f	「false」なら無効
		 */
		//-----------------------------------------------------------------//
		void auto_crlf(bool f = true) { crlf_ = f; }

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字出力
			@param[in]	ch	文字コード
		 */
		//-----------------------------------------------------------------//
		void putch(char ch) {
			if(crlf_ && ch == '\n') {
				putch('\r');
			}

			if(polling_) {
				while(SCIx::SSR.TEND() == 0) sleep_();
				SCIx::TDR = ch;
			} else {
				/// ７／８ を超えてた場合は、バッファが空になるまで待つ。
				if(send_.length() >= (send_.size() * 7 / 8)) {
					while(send_.length() != 0) sleep_();
				}
				send_.put(ch);
				SCIx::SCR.TEIE = 1;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 入力文字数を取得
			@return	入力文字数
		 */
		//-----------------------------------------------------------------//
		uint32_t length() {
			if(polling_) {
				bool err = false;
				if(SCIx::SSR.ORER()) {		///< 受信オーバランエラー状態確認
					SCIx::SSR.ORER = 0;	///< 受信オーバランエラークリア
					err = true;
				}
				uint8_t sts = SCIx::SSR();	///< 受信ステータス取得
				///< フレーミングエラー、パリティエラー状態確認
				if(sts & (SCIx::SSR.FER.b() | SCIx::SSR.PER.b())) {
					err = true;
				}
//				if((sts & sci_.SSR.RDRF.b()) != 0 && err == 0) {
					return 1;	///< 受信データあり
//				} else {
//					return 0;	///< 受信データなし
//				}
			} else {
				return recv_.length();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字入力
			@return 文字コード
		 */
		//-----------------------------------------------------------------//
		char getch() {
			if(polling_) {
				char ch;
				while(length() == 0) sleep_();
				ch = SCIx::RDR();		///< 受信データ読み出し
///				sci_.SSR.RDRF = 0;	///< 受信フラグクリア
				return ch;
			} else {
				while(recv_.length() == 0) sleep_();
				return recv_.get();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	uart文字列出力
			@param[in]	s	出力ストリング
		 */
		//-----------------------------------------------------------------//
		void puts(const char* s) {
			char ch;
			while((ch = *s++) != 0) {
				putch(ch);
			}
		}
	};

	template<class SCIx> utils::fifo<recv_size> sci_io<SCIx>::recv_;
	template<class SCIx> utils::fifo<send_size> sci_io<SCIx>::send_;
}
<commit_msg>送信、受信バッファサイズをテンプレート化<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・SCI I/O 制御 @n
			Copyright 2013 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "rx63x/sci.hpp"
#include "rx63x/system.hpp"
#include "rx63x/icu.hpp"
#include "vect.h"
#include "fifo.hpp"

/// F_PCKB はボーレートパラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCKB
#  error "sci_io.hpp requires F_PCKB to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCI I/O 制御クラス
		@param[in]	SCI	SCIx 定義クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCIx, uint32_t recv_size, uint32_t send_size>
	class sci_io {

		static utils::fifo<recv_size>	recv_;
		static utils::fifo<send_size>	send_;

		uint8_t	intr_level_;
		bool	crlf_;
		bool	polling_;

		// ※必要なら、実装する
		void sleep_() { }

		static INTERRUPT_FUNC void recv_task_()
		{
			bool err = false;
			if(SCIx::SSR.ORER()) {	///< 受信オーバランエラー状態確認
				SCIx::SSR = 0x00;	///< 受信オーバランエラークリア
				err = true;
			}
			///< フレーミングエラー/パリティエラー状態確認
			if(SCIx::SSR() & (SCIx::SSR.FER.b() | SCIx::SSR.PER.b())) {
				err = true;
			}
			if(!err) recv_.put(SCIx::RDR());
		}

		static INTERRUPT_FUNC void send_task_()
		{
			SCIx::TDR = send_.get();
			if(send_.length() == 0) {
				SCIx::SCR.TEIE = 0;
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		sci_io() : intr_level_(1), crlf_(true), polling_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  初期化 @n
					※ポーリングの場合は設定しなくても良い
			@param[in]	level	割り込みレベル
		*/
		//-----------------------------------------------------------------//
		void initialize(uint32_t level) {
			intr_level_ = level;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ボーレートを設定して、SCI を有効にする
			@param[in]	baud	ボーレート
			@param[in]	polling	ポーリングの場合「true」
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t baud, bool polling = false) {
			polling_ = polling;

			uint32_t brr = F_PCKB / baud / 16;
			uint8_t cks = 0;
			while(brr > 512) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3 || brr == 0) return false;
			bool abcs = true;
			if(brr > 256) { brr /= 2; abcs = false; }

			uint32_t chanel = SCIx::get_chanel();
			switch(chanel) {
			case 0:
				SYSTEM::MSTPCRB.MSTPB31 = 0;	// B31 (SCI0)のストップ状態解除
				break;
			case 1:
				SYSTEM::MSTPCRB.MSTPB30 = 0;	// B30 (SCI1)のストップ状態解除
				break;
			case 2:
				SYSTEM::MSTPCRB.MSTPB29 = 0;	// B29 (SCI2)のストップ状態解除
				break;
			case 3:
				SYSTEM::MSTPCRB.MSTPB28 = 0;	// B28 (SCI3)のストップ状態解除
				break;
			}

			SCIx::SCR = 0x00;			// TE, RE disable.

			if(polling_) {
				switch(chanel) {
				case 0:
					ICU::IER.TEI0 = false;
					ICU::IER.RXI0 = false;
					break;
				case 1:
					ICU::IER.TEI1 = false;
					ICU::IER.RXI1 = false;
					break;
				case 2:
					ICU::IER.TEI2 = false;
					ICU::IER.RXI2 = false;
					break;
				case 3:
					ICU::IER.TEI3 = false;
					ICU::IER.RXI3 = false;
					break;
				default:
					return false;
				}
			} else {
				switch(chanel) {
				case 0:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI0);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI0);
					ICU::IER.RXI0 = true;
					ICU::IER.TEI0 = true;
					ICU::IPR.SCI0 = intr_level_;
					break;
				case 1:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI1);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI1);
					ICU::IER.RXI1 = true;
					ICU::IER.TEI1 = true;
					ICU::IPR.SCI1 = intr_level_;
					break;
				case 2:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI2);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI2);
					ICU::IER.RXI2 = true;
					ICU::IER.TEI2 = true;
					ICU::IPR.SCI2 = intr_level_;
					break;
				case 3:
					set_interrupt_task(recv_task_, ICU::VECTOR::RXI3);
					set_interrupt_task(send_task_, ICU::VECTOR::TEI3);
					ICU::IER.RXI3 = true;
					ICU::IER.TEI3 = true;
					ICU::IPR.SCI3 = intr_level_;
					break;
				default:
					return false;
				}
			}

			// 8 bits, 1 stop bit, no-parrity
			SCIx::SMR = cks;
			SCIx::SEMR.ABCS = abcs;
			SCIx::BRR = static_cast<uint8_t>(brr - 1);

			if(polling_) {
				SCIx::SCR = SCIx::SCR.TE.b() | SCIx::SCR.RE.b();
			} else {
				SCIx::SCR = SCIx::SCR.RIE.b() | SCIx::SCR.TE.b() | SCIx::SCR.RE.b();
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	CRLF 自動送出
			@param[in]	f	「false」なら無効
		 */
		//-----------------------------------------------------------------//
		void auto_crlf(bool f = true) { crlf_ = f; }

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字出力
			@param[in]	ch	文字コード
		 */
		//-----------------------------------------------------------------//
		void putch(char ch) {
			if(crlf_ && ch == '\n') {
				putch('\r');
			}

			if(polling_) {
				while(SCIx::SSR.TEND() == 0) sleep_();
				SCIx::TDR = ch;
			} else {
				/// ７／８ を超えてた場合は、バッファが空になるまで待つ。
				if(send_.length() >= (send_.size() * 7 / 8)) {
					while(send_.length() != 0) sleep_();
				}
				send_.put(ch);
				SCIx::SCR.TEIE = 1;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 入力文字数を取得
			@return	入力文字数
		 */
		//-----------------------------------------------------------------//
		uint32_t length() {
			if(polling_) {
				bool err = false;
				if(SCIx::SSR.ORER()) {	///< 受信オーバランエラー状態確認
					SCIx::SSR.ORER = 0;	///< 受信オーバランエラークリア
					err = true;
				}
				uint8_t sts = SCIx::SSR();	///< 受信ステータス取得
				///< フレーミングエラー、パリティエラー状態確認
				if(sts & (SCIx::SSR.FER.b() | SCIx::SSR.PER.b())) {
					err = true;
				}
//				if((sts & sci_.SSR.RDRF.b()) != 0 && err == 0) {
//					return 1;	///< 受信データあり
//				} else {
					return 0;	///< 受信データなし
//				}
			} else {
				return recv_.length();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字入力
			@return 文字コード
		 */
		//-----------------------------------------------------------------//
		char getch() {
			if(polling_) {
				char ch;
				while(length() == 0) sleep_();
				ch = SCIx::RDR();	///< 受信データ読み出し
///				SCIx::SSR.RDRF = 0;	///< 受信フラグクリア
				return ch;
			} else {
				while(recv_.length() == 0) sleep_();
				return recv_.get();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	uart文字列出力
			@param[in]	s	出力ストリング
		 */
		//-----------------------------------------------------------------//
		void puts(const char* s) {
			char ch;
			while((ch = *s++) != 0) {
				putch(ch);
			}
		}
	};

	template<class SCIx, uint32_t recv_size, uint32_t send_size>
		utils::fifo<recv_size> sci_io<SCIx, recv_size, send_size>::recv_;
	template<class SCIx, uint32_t recv_size, uint32_t send_size>
		utils::fifo<send_size> sci_io<SCIx, recv_size, send_size>::send_;
}
<|endoftext|>


<commit_before>#include "TrackingWorker.hpp"

#include <boost/chrono/duration.hpp>
#include <ros/console.h>
#include <opencv2/core/core.hpp>
#include <map>

#include "../../matlab/profiling.hpp"

TrackingWorker::TrackingWorker(IPositionReceiver *receiver) : errorGraph(100, "Difference")
{
	assert(receiver != 0);

	this->receiver = receiver;
	stop = false;

	std::map<int, cv::Scalar> colors;
	colors[0] = cv::Scalar(0, 255, 0);
	colors[1] = cv::Scalar(0, 255, 255);
	colors[2] = cv::Scalar(255, 0, 255);
	errorGraph.setColors(colors);

	thread = new boost::thread(boost::bind(&TrackingWorker::run, this));
}

TrackingWorker::~TrackingWorker()
{
	stop = true;
	thread->join();
}

void TrackingWorker::run()
{
	ROS_INFO("Started tracking thread");

	bool receivedFirstPosition = false;
	int emptyCount = 0;

	while (!stop) {
		std::vector<CameraData> data = dequeue();

		if (data.size() > 1) {
			emptyCount = 0;

			if (!receivedFirstPosition) {
				receivedFirstPosition = true;
				ROS_INFO("Found quadcopter %d", data[0].quadcopterId);
			}

			// ROS_DEBUG("Got info from camera %d: [%.2f, %.2f, %.2f]", data[0].camNo, data[0].cameraVector.getV1(), data[0].cameraVector.getV2(), data[0].cameraVector.getV3());

			double latency = 0;
			double currentTime = getNanoTime();

			for (std::vector<CameraData>::iterator it = data.begin(); it != data.end(); it++) {
				double newLatency = currentTime - it->time;

				if (newLatency > latency) {
					latency = newLatency;
				}
			}

			ROS_DEBUG("Latency is %.3fms", latency / 1e6);

			Vector position = tracker.updatePosition(data);

			for (size_t i = 0; i < data.size(); i++) {
				errorGraph.nextPoint(tracker.getDistance(), data[i].camNo);
			}

			if (position.isValid()) {
				// Invert x axis for controller
				position.setV1(-position.getV1());

				std::vector<Vector> positions;
				std::vector<int> ids;
				std::vector<int> updates;
				positions.push_back(position);
				ids.push_back(data[0].quadcopterId);
				updates.push_back(1);

				receiver->updatePositions(positions, ids, updates);
			}
		} else if (receivedFirstPosition) {
			emptyCount++;

			if (emptyCount == 50) {
				// TODO uncomment
				ROS_WARN("Position update buffer is empty!");
				emptyCount = 0;
			}

			boost::mutex::scoped_lock lock(queueMutex);
			queueEmpty.wait(lock);
		}
	}

	ROS_INFO("Stopped tracking thread");
}

void TrackingWorker::updatePosition(Vector cameraVector, int camNo, int quadcopterId, long int time)
{
	CameraData data;
	data.cameraVector = cameraVector;
	data.camNo = camNo;
	data.quadcopterId = quadcopterId;
	data.valid = true;
	data.time = time;

	updatePosition(data);
}

void TrackingWorker::updatePosition(CameraData data)
{
	enqueue(data);
}

void TrackingWorker::enqueue(CameraData data)
{
	boost::mutex::scoped_lock lock(queueMutex);

	queue.enqueue(data);

	queueEmpty.notify_all();
}

std::vector<CameraData> TrackingWorker::dequeue()
{
	boost::mutex::scoped_lock lock(queueMutex);

	if (!dataAvailable()) {
		queueEmpty.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(100));
	}

	if (dataAvailable()) {
		return queue.dequeue();
	} else {
		return std::vector<CameraData>();
	}
}

bool TrackingWorker::dataAvailable()
{
	return queue.dataAvailable();
}

bool TrackingWorker::calibrate(ChessboardData *chessboard, int camNo)
{
	return tracker.calibrate(chessboard, camNo);
}

Vector TrackingWorker::getCameraPosition(int camNo)
{
	return tracker.getPosition(camNo);
}

Matrix TrackingWorker::getRotationMatrix(int camNo)
{
	return tracker.getRotationMatrix(camNo);
}

cv::Mat TrackingWorker::getIntrinsicsMatrix(int camNo)
{
	return tracker.getIntrinsicsMatrix(camNo);
}

cv::Mat TrackingWorker::getDistortionCoefficients(int camNo)
{
	return tracker.getDistortionCoefficients(camNo);
}

void TrackingWorker::updateTrackingArea()
{
	receiver->setTrackingArea(tracker.getTrackingArea());
}
<commit_msg>Unflipped x axis<commit_after>#include "TrackingWorker.hpp"

#include <boost/chrono/duration.hpp>
#include <ros/console.h>
#include <opencv2/core/core.hpp>
#include <map>

#include "../../matlab/profiling.hpp"

TrackingWorker::TrackingWorker(IPositionReceiver *receiver) : errorGraph(100, "Difference")
{
	assert(receiver != 0);

	this->receiver = receiver;
	stop = false;

	std::map<int, cv::Scalar> colors;
	colors[0] = cv::Scalar(0, 255, 0);
	colors[1] = cv::Scalar(0, 255, 255);
	colors[2] = cv::Scalar(255, 0, 255);
	errorGraph.setColors(colors);

	thread = new boost::thread(boost::bind(&TrackingWorker::run, this));
}

TrackingWorker::~TrackingWorker()
{
	stop = true;
	thread->join();
}

void TrackingWorker::run()
{
	ROS_INFO("Started tracking thread");

	bool receivedFirstPosition = false;
	int emptyCount = 0;

	while (!stop) {
		std::vector<CameraData> data = dequeue();

		if (data.size() > 1) {
			emptyCount = 0;

			if (!receivedFirstPosition) {
				receivedFirstPosition = true;
				ROS_INFO("Found quadcopter %d", data[0].quadcopterId);
			}

			// ROS_DEBUG("Got info from camera %d: [%.2f, %.2f, %.2f]", data[0].camNo, data[0].cameraVector.getV1(), data[0].cameraVector.getV2(), data[0].cameraVector.getV3());

			double latency = 0;
			double currentTime = getNanoTime();

			for (std::vector<CameraData>::iterator it = data.begin(); it != data.end(); it++) {
				double newLatency = currentTime - it->time;

				if (newLatency > latency) {
					latency = newLatency;
				}
			}

			ROS_DEBUG("Latency is %.3fms", latency / 1e6);

			Vector position = tracker.updatePosition(data);

			for (size_t i = 0; i < data.size(); i++) {
				errorGraph.nextPoint(tracker.getDistance(), data[i].camNo);
			}

			if (position.isValid()) {
				// Invert x axis for controller
				// position.setV1(-position.getV1());

				std::vector<Vector> positions;
				std::vector<int> ids;
				std::vector<int> updates;
				positions.push_back(position);
				ids.push_back(data[0].quadcopterId);
				updates.push_back(1);

				receiver->updatePositions(positions, ids, updates);
			}
		} else if (receivedFirstPosition) {
			emptyCount++;

			if (emptyCount == 50) {
				// TODO uncomment
				ROS_WARN("Position update buffer is empty!");
				emptyCount = 0;
			}

			boost::mutex::scoped_lock lock(queueMutex);
			queueEmpty.wait(lock);
		}
	}

	ROS_INFO("Stopped tracking thread");
}

void TrackingWorker::updatePosition(Vector cameraVector, int camNo, int quadcopterId, long int time)
{
	CameraData data;
	data.cameraVector = cameraVector;
	data.camNo = camNo;
	data.quadcopterId = quadcopterId;
	data.valid = true;
	data.time = time;

	updatePosition(data);
}

void TrackingWorker::updatePosition(CameraData data)
{
	enqueue(data);
}

void TrackingWorker::enqueue(CameraData data)
{
	boost::mutex::scoped_lock lock(queueMutex);

	queue.enqueue(data);

	queueEmpty.notify_all();
}

std::vector<CameraData> TrackingWorker::dequeue()
{
	boost::mutex::scoped_lock lock(queueMutex);

	if (!dataAvailable()) {
		queueEmpty.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(100));
	}

	if (dataAvailable()) {
		return queue.dequeue();
	} else {
		return std::vector<CameraData>();
	}
}

bool TrackingWorker::dataAvailable()
{
	return queue.dataAvailable();
}

bool TrackingWorker::calibrate(ChessboardData *chessboard, int camNo)
{
	return tracker.calibrate(chessboard, camNo);
}

Vector TrackingWorker::getCameraPosition(int camNo)
{
	return tracker.getPosition(camNo);
}

Matrix TrackingWorker::getRotationMatrix(int camNo)
{
	return tracker.getRotationMatrix(camNo);
}

cv::Mat TrackingWorker::getIntrinsicsMatrix(int camNo)
{
	return tracker.getIntrinsicsMatrix(camNo);
}

cv::Mat TrackingWorker::getDistortionCoefficients(int camNo)
{
	return tracker.getDistortionCoefficients(camNo);
}

void TrackingWorker::updateTrackingArea()
{
	receiver->setTrackingArea(tracker.getTrackingArea());
}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision: 11316 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "QmitkSliderDialogBar.h"
#include "QmitkSliderNavigator.h"
#include "QmitkStepperAdapter.h"
#include "QmitkStdMultiWidget.h"

#include <qaction.h>
#include <qlabel.h>
#include <qvbox.h>
#include <qgrid.h>

QmitkSliderDialogBar
::QmitkSliderDialogBar(
  QObject *parent, const char *name, QmitkStdMultiWidget *multiWidget,
  mitk::DataTreeIteratorBase *dataIt )
: QmitkDialogBar( "Slider", parent, name, multiWidget, dataIt )
{
}

QmitkSliderDialogBar
::~QmitkSliderDialogBar()
{
}

QString
QmitkSliderDialogBar
::GetFunctionalityName()
{
  return "SliderDialogBar";
}

QAction *
QmitkSliderDialogBar
::CreateAction( QObject *parent )
{
  QAction* action;
  action = new QAction(
    tr( "Mitralyzer" ),
    QPixmap((const char**)QmitkSliderDialogBar_xpm),
    tr( "MenueEintrag" ),
    0,
    parent,
    "QmitkMitralyzer" );

  return action;
}

QWidget *
QmitkSliderDialogBar
::CreateDialogBar( QWidget *parent )
{
  QGrid *grid = new QGrid( 2, Qt::Horizontal, parent );

  QLabel *label1 = new QLabel( "Transversal", grid );
  QmitkSliderNavigator *sliderNavigator1 = new QmitkSliderNavigator( grid );

  QLabel *label2 = new QLabel( "Sagittal", grid );
  QmitkSliderNavigator *sliderNavigator2 = new QmitkSliderNavigator( grid );

  QLabel *label3 = new QLabel( "Coronal", grid );
  QmitkSliderNavigator *sliderNavigator3 = new QmitkSliderNavigator( grid );

  QLabel *label4 = new QLabel( "Time", grid );
  QmitkSliderNavigator *sliderNavigatorTime = new QmitkSliderNavigator( grid );

  QmitkStepperAdapter *stepperAdapter1 = new QmitkStepperAdapter(
    sliderNavigator1,
    m_MultiWidget->GetRenderWindow1()->GetController()->GetSlice(),
    "SpatialStepperAdaptor1"
  );

  QmitkStepperAdapter *stepperAdapter2 = new QmitkStepperAdapter(
    sliderNavigator2,
    m_MultiWidget->GetRenderWindow2()->GetController()->GetSlice(),
    "SpatialStepperAdaptor2"
  );

  QmitkStepperAdapter *stepperAdapter3 = new QmitkStepperAdapter(
    sliderNavigator3,
    m_MultiWidget->GetRenderWindow3()->GetController()->GetSlice(),
    "SpatialStepperAdaptor3"
  );

  QmitkStepperAdapter *stepperAdapterTime = new QmitkStepperAdapter(
    sliderNavigatorTime,
    m_MultiWidget->GetTimeNavigationController()->GetTime(),
    "TimeStepperAdaptor"
  );

  return grid;
}
<commit_msg>ENH: Slider labels (range, unit) enabled by default for QmitkSliderDialogBar<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision: 11316 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "QmitkSliderDialogBar.h"
#include "QmitkSliderNavigator.h"
#include "QmitkStepperAdapter.h"
#include "QmitkStdMultiWidget.h"

#include <qaction.h>
#include <qlabel.h>
#include <qvbox.h>
#include <qgrid.h>

QmitkSliderDialogBar
::QmitkSliderDialogBar(
  QObject *parent, const char *name, QmitkStdMultiWidget *multiWidget,
  mitk::DataTreeIteratorBase *dataIt )
: QmitkDialogBar( "Slider", parent, name, multiWidget, dataIt )
{
}

QmitkSliderDialogBar
::~QmitkSliderDialogBar()
{
}

QString
QmitkSliderDialogBar
::GetFunctionalityName()
{
  return "SliderDialogBar";
}

QAction *
QmitkSliderDialogBar
::CreateAction( QObject *parent )
{
  QAction* action;
  action = new QAction(
    tr( "Mitralyzer" ),
    QPixmap((const char**)QmitkSliderDialogBar_xpm),
    tr( "MenueEintrag" ),
    0,
    parent,
    "QmitkMitralyzer" );

  return action;
}

QWidget *
QmitkSliderDialogBar
::CreateDialogBar( QWidget *parent )
{
  QGrid *grid = new QGrid( 2, Qt::Horizontal, parent );

  QLabel *label1 = new QLabel( "Transversal", grid );
  QmitkSliderNavigator *sliderNavigator1 = new QmitkSliderNavigator( grid );

  QLabel *label2 = new QLabel( "Sagittal", grid );
  QmitkSliderNavigator *sliderNavigator2 = new QmitkSliderNavigator( grid );

  QLabel *label3 = new QLabel( "Coronal", grid );
  QmitkSliderNavigator *sliderNavigator3 = new QmitkSliderNavigator( grid );

  QLabel *label4 = new QLabel( "Time", grid );
  QmitkSliderNavigator *sliderNavigatorTime = new QmitkSliderNavigator( grid );

  sliderNavigator1->ShowLabels( true );
  sliderNavigator2->ShowLabels( true );
  sliderNavigator3->ShowLabels( true );
  sliderNavigatorTime->ShowLabels( true );

  QmitkStepperAdapter *stepperAdapter1 = new QmitkStepperAdapter(
    sliderNavigator1,
    m_MultiWidget->GetRenderWindow1()->GetController()->GetSlice(),
    "SpatialStepperAdaptor1"
  );

  QmitkStepperAdapter *stepperAdapter2 = new QmitkStepperAdapter(
    sliderNavigator2,
    m_MultiWidget->GetRenderWindow2()->GetController()->GetSlice(),
    "SpatialStepperAdaptor2"
  );

  QmitkStepperAdapter *stepperAdapter3 = new QmitkStepperAdapter(
    sliderNavigator3,
    m_MultiWidget->GetRenderWindow3()->GetController()->GetSlice(),
    "SpatialStepperAdaptor3"
  );

  QmitkStepperAdapter *stepperAdapterTime = new QmitkStepperAdapter(
    sliderNavigatorTime,
    m_MultiWidget->GetTimeNavigationController()->GetTime(),
    "TimeStepperAdaptor"
  );

  return grid;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "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 Nokia Corporation and its Subsidiary(-ies) 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."
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/qdir.h>
#include <QtGui/qfiledialog.h>

#include <qaudiocapturesource.h>
#include <qmediarecorder.h>

#include "audiorecorder.h"
#include "ui_audiorecorder.h"

AudioRecorder::AudioRecorder(QWidget *parent)
    :  QMainWindow(parent),
       ui(new Ui::AudioRecorder)
{
    ui->setupUi(this);

    audiosource = new QAudioCaptureSource(this);
    capture = new QMediaRecorder(audiosource, this);

    // set a default file
    capture->setOutputLocation(QUrl("test.raw"));

    //audio devices
    ui->audioDeviceBox->addItem(tr("Default"), QVariant(QString()));
    foreach(const QString &device, audiosource->audioInputs()) {
        ui->audioDeviceBox->addItem(device, QVariant(device));
    }

    //audio codecs
    ui->audioCodecBox->addItem(tr("Default"), QVariant(QString()));
    foreach(const QString &codecName, capture->supportedAudioCodecs()) {
        ui->audioCodecBox->addItem(codecName, QVariant(codecName));
    }

    //containers
    ui->containerBox->addItem(tr("Default"), QVariant(QString()));
    foreach(const QString &containerName, capture->supportedContainers()) {
        ui->containerBox->addItem(containerName, QVariant(containerName));
    }

    //sample rate:
    ui->sampleRateBox->addItem(tr("Default"), QVariant(0));
    foreach(int sampleRate, capture->supportedAudioSampleRates()) {
        ui->sampleRateBox->addItem(QString::number(sampleRate), QVariant(sampleRate));
    }

    ui->qualitySlider->setRange(0, int(QtMultimediaKit::VeryHighQuality));
    ui->qualitySlider->setValue(int(QtMultimediaKit::NormalQuality));

    //bitrates:
    ui->bitrateBox->addItem(QString("Default"), QVariant(0));
    ui->bitrateBox->addItem(QString("32000"), QVariant(32000));
    ui->bitrateBox->addItem(QString("64000"), QVariant(64000));
    ui->bitrateBox->addItem(QString("96000"), QVariant(96000));
    ui->bitrateBox->addItem(QString("128000"), QVariant(128000));

    connect(capture, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress(qint64)));
    connect(capture, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(updateState(QMediaRecorder::State)));
    connect(capture, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayErrorMessage()));
}

AudioRecorder::~AudioRecorder()
{
    delete capture;
    delete audiosource;
}

void AudioRecorder::updateProgress(qint64 duration)
{
    if (capture->error() != QMediaRecorder::NoError)
        return;

    ui->statusbar->showMessage(tr("Recorded %1 sec").arg(duration/1000));
}

void AudioRecorder::updateState(QMediaRecorder::State state)
{
    QString statusMessage;

    switch(state) {
        case QMediaRecorder::RecordingState:
            ui->recordButton->setText(tr("Stop"));
            ui->pauseButton->setText(tr("Pause"));
            statusMessage = tr("Recording");
            break;
        case QMediaRecorder::PausedState:
            ui->recordButton->setText(tr("Stop"));
            ui->pauseButton->setText(tr("Resume"));
            statusMessage = tr("Paused");
            break;
        case QMediaRecorder::StoppedState:
            ui->recordButton->setText(tr("Record"));
            ui->pauseButton->setText(tr("Pause"));
            statusMessage = tr("Stopped");
    }

    ui->pauseButton->setEnabled(state != QMediaRecorder::StoppedState);

    if (capture->error() == QMediaRecorder::NoError)
        ui->statusbar->showMessage(statusMessage);
}

static QVariant boxValue(const QComboBox *box)
{
    int idx = box->currentIndex();
    if (idx == -1)
        return QVariant();

    return box->itemData(idx);
}

void AudioRecorder::toggleRecord()
{
    if (capture->state() == QMediaRecorder::StoppedState) {
        audiosource->setAudioInput(boxValue(ui->audioDeviceBox).toString());

        QAudioEncoderSettings settings;
        settings.setCodec(boxValue(ui->audioCodecBox).toString());
        settings.setSampleRate(boxValue(ui->sampleRateBox).toInt());
        settings.setBitRate(boxValue(ui->bitrateBox).toInt());
        settings.setQuality(QtMultimediaKit::EncodingQuality(ui->qualitySlider->value()));
        settings.setEncodingMode(ui->constantQualityRadioButton->isChecked() ?
                                 QtMultimediaKit::ConstantQualityEncoding :
                                 QtMultimediaKit::ConstantBitRateEncoding);

        QString container = boxValue(ui->containerBox).toString();

        capture->setEncodingSettings(settings, QVideoEncoderSettings(), container);
        capture->record();
    } else {
        capture->stop();
    }
}

void AudioRecorder::togglePause()
{
    if (capture->state() != QMediaRecorder::PausedState)
        capture->pause();
    else
        capture->record();
}

void AudioRecorder::setOutputLocation()
{
    QString fileName = QFileDialog::getSaveFileName();

    capture->setOutputLocation(QUrl(fileName));
}

void AudioRecorder::displayErrorMessage()
{
    ui->statusbar->showMessage(capture->errorString());
}
<commit_msg>Audio recorder example: don't set the default output file but display the actual file to user.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "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 Nokia Corporation and its Subsidiary(-ies) 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."
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/qdir.h>
#include <QtGui/qfiledialog.h>

#include <qaudiocapturesource.h>
#include <qmediarecorder.h>

#include "audiorecorder.h"
#include "ui_audiorecorder.h"

AudioRecorder::AudioRecorder(QWidget *parent)
    :  QMainWindow(parent),
       ui(new Ui::AudioRecorder)
{
    ui->setupUi(this);

    audiosource = new QAudioCaptureSource(this);
    capture = new QMediaRecorder(audiosource, this);

    //audio devices
    ui->audioDeviceBox->addItem(tr("Default"), QVariant(QString()));
    foreach(const QString &device, audiosource->audioInputs()) {
        ui->audioDeviceBox->addItem(device, QVariant(device));
    }

    //audio codecs
    ui->audioCodecBox->addItem(tr("Default"), QVariant(QString()));
    foreach(const QString &codecName, capture->supportedAudioCodecs()) {
        ui->audioCodecBox->addItem(codecName, QVariant(codecName));
    }

    //containers
    ui->containerBox->addItem(tr("Default"), QVariant(QString()));
    foreach(const QString &containerName, capture->supportedContainers()) {
        ui->containerBox->addItem(containerName, QVariant(containerName));
    }

    //sample rate:
    ui->sampleRateBox->addItem(tr("Default"), QVariant(0));
    foreach(int sampleRate, capture->supportedAudioSampleRates()) {
        ui->sampleRateBox->addItem(QString::number(sampleRate), QVariant(sampleRate));
    }

    ui->qualitySlider->setRange(0, int(QtMultimediaKit::VeryHighQuality));
    ui->qualitySlider->setValue(int(QtMultimediaKit::NormalQuality));

    //bitrates:
    ui->bitrateBox->addItem(QString("Default"), QVariant(0));
    ui->bitrateBox->addItem(QString("32000"), QVariant(32000));
    ui->bitrateBox->addItem(QString("64000"), QVariant(64000));
    ui->bitrateBox->addItem(QString("96000"), QVariant(96000));
    ui->bitrateBox->addItem(QString("128000"), QVariant(128000));

    connect(capture, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress(qint64)));
    connect(capture, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(updateState(QMediaRecorder::State)));
    connect(capture, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayErrorMessage()));
}

AudioRecorder::~AudioRecorder()
{
    delete capture;
    delete audiosource;
}

void AudioRecorder::updateProgress(qint64 duration)
{
    if (capture->error() != QMediaRecorder::NoError || duration < 2000)
        return;

    ui->statusbar->showMessage(tr("Recorded %1 sec").arg(qRound(duration/1000)));
}

void AudioRecorder::updateState(QMediaRecorder::State state)
{
    QString statusMessage;

    switch(state) {
        case QMediaRecorder::RecordingState:
            ui->recordButton->setText(tr("Stop"));
            ui->pauseButton->setText(tr("Pause"));
            if (capture->outputLocation().isEmpty())
                statusMessage = tr("Recording");
            else
                statusMessage = tr("Recording to %1").arg(capture->outputLocation().toString());
            break;
        case QMediaRecorder::PausedState:
            ui->recordButton->setText(tr("Stop"));
            ui->pauseButton->setText(tr("Resume"));
            statusMessage = tr("Paused");
            break;
        case QMediaRecorder::StoppedState:
            ui->recordButton->setText(tr("Record"));
            ui->pauseButton->setText(tr("Pause"));
            statusMessage = tr("Stopped");
    }

    ui->pauseButton->setEnabled(state != QMediaRecorder::StoppedState);

    if (capture->error() == QMediaRecorder::NoError)
        ui->statusbar->showMessage(statusMessage);
}

static QVariant boxValue(const QComboBox *box)
{
    int idx = box->currentIndex();
    if (idx == -1)
        return QVariant();

    return box->itemData(idx);
}

void AudioRecorder::toggleRecord()
{
    if (capture->state() == QMediaRecorder::StoppedState) {
        audiosource->setAudioInput(boxValue(ui->audioDeviceBox).toString());

        QAudioEncoderSettings settings;
        settings.setCodec(boxValue(ui->audioCodecBox).toString());
        settings.setSampleRate(boxValue(ui->sampleRateBox).toInt());
        settings.setBitRate(boxValue(ui->bitrateBox).toInt());
        settings.setQuality(QtMultimediaKit::EncodingQuality(ui->qualitySlider->value()));
        settings.setEncodingMode(ui->constantQualityRadioButton->isChecked() ?
                                 QtMultimediaKit::ConstantQualityEncoding :
                                 QtMultimediaKit::ConstantBitRateEncoding);

        QString container = boxValue(ui->containerBox).toString();

        capture->setEncodingSettings(settings, QVideoEncoderSettings(), container);
        capture->record();
    } else {
        capture->stop();
    }
}

void AudioRecorder::togglePause()
{
    if (capture->state() != QMediaRecorder::PausedState)
        capture->pause();
    else
        capture->record();
}

void AudioRecorder::setOutputLocation()
{
    QString fileName = QFileDialog::getSaveFileName();

    capture->setOutputLocation(QUrl(fileName));
}

void AudioRecorder::displayErrorMessage()
{
    ui->statusbar->showMessage(capture->errorString());
}
<|endoftext|>


<commit_before>#include <cassert>
#include <vector>

#include <llvm/IR/Constant.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_os_ostream.h>

#include "dg/llvm/PointerAnalysis/PointerGraph.h"

#include "llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h"
#include "llvm/llvm-utils.h"

namespace dg {
namespace dda {

static void reportIncompatibleCalls(
        const std::set<const llvm::Function *> &incompatibleCalls,
        const llvm::CallInst *CInst, size_t tried_num) {
    if (incompatibleCalls.empty()) {
        return;
    }

#ifndef NDEBUG
    llvm::errs() << "[RWG] warning: incompatible function pointers for "
                 << ValInfo(CInst) << "\n";

    for (auto *F : incompatibleCalls) {
        llvm::errs() << "   Tried: " << F->getName() << " of type "
                     << *F->getType() << "\n";
    }
#endif
    if (incompatibleCalls.size() == tried_num) {
        llvm::errs() << "[RWG] error: did not find any compatible function "
                        "pointer for "
                     << ValInfo(CInst) << "\n";
    }
}

NodesSeq<RWNode> LLVMReadWriteGraphBuilder::createCallToFunctions(
        const std::vector<const llvm::Function *> &functions,
        const llvm::CallInst *CInst) {
    assert(!functions.empty() && "No functions to call");

    std::set<const llvm::Function *> incompatibleCalls;
    std::vector<RWNode *> called_values;
    std::vector<RWSubgraph *> called_subgraphs;
    for (const auto *F : functions) {
        if (!llvmutils::callIsCompatible(F, CInst)) {
            incompatibleCalls.insert(F);
            continue;
        }

        if (const auto *model = _options.getFunctionModel(F->getName().str())) {
            called_values.push_back(funcFromModel(model, CInst));
        } else if (F->isDeclaration()) {
            called_values.push_back(createCallToUndefinedFunction(F, CInst));
        } else {
            auto *s = getSubgraph(F);
            assert(s && "Do not have a subgraph for a function");
            called_subgraphs.push_back(s);
        }
    }

    reportIncompatibleCalls(incompatibleCalls, CInst, functions.size());

    // if we call just one undefined function, simplify the graph and
    // do not create a CALL node -- just put the already created node there
    if (called_subgraphs.empty() && called_values.size() == 1) {
        return {called_values[0]};
    }
    RWNodeCall *callNode = RWNodeCall::get(&create(RWNodeType::CALL));
    for (auto *item : called_subgraphs)
        callNode->addCallee(item);
    for (auto *item : called_values)
        callNode->addCallee(item);
    return {callNode};
}

RWNode *
LLVMReadWriteGraphBuilder::createUnknownCall(const llvm::CallInst *CInst) {
    using namespace llvm;

    RWNode *node = &create(RWNodeType::GENERIC);

    // if we assume that undefined functions are pure
    // (have no side effects), we can bail out here
    if (_options.undefinedArePure())
        return node;

    bool args = false;
    if (_options.undefinedFunsReadAny()) {
        node->addUse(UNKNOWN_MEMORY);
    } else {
        args |= _options.undefinedFunsReadArgs();
    }

    if (_options.undefinedFunsWriteAny()) {
        node->addDef(UNKNOWN_MEMORY);
    } else {
        args |= _options.undefinedFunsWriteArgs();
    }

    if (!args)
        return node;

    // every pointer we pass into the undefined call may be defined
    // in the function
    for (unsigned int i = 0; i < CInst->getNumArgOperands(); ++i) {
        const Value *llvmOp = CInst->getArgOperand(i);

        // constants cannot be redefined except for global variables
        // (that are constant, but may point to non constant memory
        const Value *strippedValue = llvmOp->stripPointerCasts();
        if (isa<Constant>(strippedValue)) {
            const GlobalVariable *GV = dyn_cast<GlobalVariable>(strippedValue);
            // if the constant is not global variable,
            // or the global variable points to constant memory
            if (!GV || GV->isConstant())
                continue;
        }

        auto pts = PTA->getLLVMPointsToChecked(llvmOp);
        // if we do not have a pts, this is not pointer
        // relevant instruction. We must do it this way
        // instead of type checking, due to the inttoptr.
        if (!pts.first)
            continue;

        for (const auto &ptr : pts.second) {
            if (llvm::isa<llvm::Function>(ptr.value))
                // function may not be redefined
                continue;

            RWNode *target = getOperand(ptr.value);
            assert(target && "Don't have pointer target for call argument");

            // this call may use and define this memory
            if (_options.undefinedFunsWriteArgs() &&
                !_options.undefinedFunsWriteAny())
                node->addDef(target, Offset::UNKNOWN, Offset::UNKNOWN);
            if (_options.undefinedFunsReadArgs() &&
                !_options.undefinedFunsReadAny())
                node->addUse(target, Offset::UNKNOWN, Offset::UNKNOWN);
        }
    }

    return node;
}

/*
void LLVMReadWriteGraphBuilder::matchForksAndJoins()
{
    using namespace llvm;
    using namespace pta;

    ForkJoinAnalysis FJA{PTA};

    for (auto& it : threadJoinCalls) {
        // it.first -> llvm::CallInst, it.second -> RWNode *
        auto functions = FJA.joinFunctions(it.first);
        for (auto llvmFunction : functions) {
            auto graphIterator = subgraphs_map.find(llvmFunction);
            for (auto returnNode : graphIterator->second.returns) {
                makeEdge(returnNode, it.second);
            }
        }
    }
}
*/

RWNode *
LLVMReadWriteGraphBuilder::createIntrinsicCall(const llvm::CallInst *CInst) {
    using namespace llvm;

    const IntrinsicInst *I = cast<IntrinsicInst>(CInst);
    const Value *dest;
    const Value *lenVal;

    RWNode *ret;
    switch (I->getIntrinsicID()) {
    case Intrinsic::memmove:
    case Intrinsic::memcpy:
    case Intrinsic::memset:
        // memcpy/set <dest>, <src/val>, <len>
        dest = I->getOperand(0);
        lenVal = I->getOperand(2);
        break;
    case Intrinsic::vastart:
        // we create this node because this nodes works
        // as ALLOC in points-to, so we can have
        // reaching definitions to that
        ret = &create(RWNodeType::ALLOC);
        ret->addDef(ret, 0, Offset::UNKNOWN);
        return ret;
    default:
        return createUnknownCall(CInst);
    }

    ret = &create(RWNodeType::GENERIC);

    auto pts = PTA->getLLVMPointsToChecked(dest);
    if (!pts.first) {
        llvm::errs()
                << "[RWG] Error: No points-to information for destination in\n";
        llvm::errs() << ValInfo(I) << "\n";
        // continue, the points-to set is {unknown}
    }

    uint64_t len = Offset::UNKNOWN;
    if (const ConstantInt *C = dyn_cast<ConstantInt>(lenVal))
        len = C->getLimitedValue();

    for (const auto &ptr : pts.second) {
        if (llvm::isa<llvm::Function>(ptr.value))
            continue;

        Offset from, to;
        if (ptr.offset.isUnknown()) {
            // if the offset is UNKNOWN, use whole memory
            from = Offset::UNKNOWN;
            len = Offset::UNKNOWN;
        } else {
            from = *ptr.offset;
        }

        // do not allow overflow
        if (Offset::UNKNOWN - *from > len)
            to = from + len;
        else
            to = Offset::UNKNOWN;

        RWNode *target = getOperand(ptr.value);
        // assert(target && "Don't have pointer target for intrinsic call");
        if (!target) {
            // keeping such set is faster then printing it all to terminal
            // ... and we don't flood the terminal that way
            static std::set<const llvm::Value *> warned;
            if (warned.insert(ptr.value).second) {
                llvm::errs() << "[RWG] error at " << ValInfo(CInst) << "\n"
                             << "[RWG] error: Haven't created node for: "
                             << ValInfo(ptr.value) << "\n";
            }
            target = UNKNOWN_MEMORY;
        }

        // add the definition
        ret->addDef(target, from, to,
                    !from.isUnknown() && !to.isUnknown() /* strong update */);
    }

    return ret;
}

template <typename T>
std::pair<Offset, Offset> getFromTo(const llvm::CallInst *CInst, T what) {
    auto from = what->from.isOperand()
                        ? llvmutils::getConstantValue(
                                  CInst->getArgOperand(what->from.getOperand()))
                        : what->from.getOffset();
    auto to = what->to.isOperand()
                      ? llvmutils::getConstantValue(
                                CInst->getArgOperand(what->to.getOperand()))
                      : what->to.getOffset();

    return {from, to};
}

RWNode *LLVMReadWriteGraphBuilder::funcFromModel(const FunctionModel *model,
                                                 const llvm::CallInst *CInst) {
    RWNode *node = &create(RWNodeType::GENERIC);

    for (unsigned int i = 0; i < CInst->getNumArgOperands(); ++i) {
        if (!model->handles(i))
            continue;

        auto *const llvmOp = CInst->getArgOperand(i);
        auto pts = PTA->getLLVMPointsToChecked(llvmOp);
        // if we do not have a pts, this is not pointer
        // relevant instruction. We must do it this way
        // instead of type checking, due to the inttoptr.
        if (!pts.first) {
            llvm::errs()
                    << "[Warning]: did not find pt-set for modeled function\n";
            llvm::errs() << "           Func: " << model->name << ", operand "
                         << i << "\n";
            continue;
        }

        for (const auto &ptr : pts.second) {
            if (llvm::isa<llvm::Function>(ptr.value))
                // functions may not be redefined
                continue;

            RWNode *target = getOperand(ptr.value);
            assert(target && "Don't have pointer target for call argument");

            Offset from, to;
            if (const auto *defines = model->defines(i)) {
                std::tie(from, to) = getFromTo(CInst, defines);
                // this call may define this memory
                bool strong_updt = pts.second.size() == 1 &&
                                   !ptr.offset.isUnknown() &&
                                   !(ptr.offset + from).isUnknown() &&
                                   !(ptr.offset + to).isUnknown() &&
                                   !llvm::isa<llvm::CallInst>(ptr.value);
                // FIXME: what about vars in recursive functions?
                node->addDef(target, ptr.offset + from, ptr.offset + to,
                             strong_updt);
            }
            if (const auto *uses = model->uses(i)) {
                std::tie(from, to) = getFromTo(CInst, uses);
                // this call uses this memory
                node->addUse(target, ptr.offset + from, ptr.offset + to);
            }
        }
    }

    return node;
}
RWNode *LLVMReadWriteGraphBuilder::createCallToUndefinedFunction(
        const llvm::Function *function, const llvm::CallInst *CInst) {
    if (function->isIntrinsic()) {
        return createIntrinsicCall(CInst);
    }
    if (_options.threads) {
        // assert(false && "Threads unsupported yet");
        if (function->getName() == "pthread_create") {
            return createPthreadCreateCalls(CInst);
        } else if (function->getName() == "pthread_join") {
            return createPthreadJoinCall(CInst);
        } else if (function->getName() == "pthread_exit") {
            return createPthreadExitCall(CInst);
        }
    }

    auto type = _options.getAllocationFunction(function->getName().str());
    if (type != AllocationFunction::NONE) {
        if (type == AllocationFunction::REALLOC)
            return createRealloc(CInst);
        return createDynAlloc(CInst, type);
    }
    return createUnknownCall(CInst);

    assert(false && "Unreachable");
    abort();
}

RWNode *LLVMReadWriteGraphBuilder::createPthreadCreateCalls(const llvm::CallInst
*CInst) { using namespace llvm;

    RWNode *rootNode = &create(RWNodeType::FORK);
    threadCreateCalls.emplace(CInst, rootNode);

    Value *calledValue = CInst->getArgOperand(2);
    const auto& functions = getCalledFunctions(calledValue, PTA);

    for (const Function *function : functions) {
        if (function->isDeclaration()) {
            llvm::errs()
                    << "[RWG] error: phtread_create spawns undefined function: "
                    << function->getName() << "\n";
            continue;
        }
    }
    return rootNode;
}

RWNode *LLVMReadWriteGraphBuilder::createPthreadJoinCall(const llvm::CallInst
*CInst)
{
    // TODO later change this to create join node and set data correctly
    // we need just to create one node;
    // undefined call is overapproximation, so its ok
    RWNode *node = createUnknownCall(CInst);
    threadJoinCalls.emplace(CInst, node);
    return node;
}

RWNode *LLVMReadWriteGraphBuilder::createPthreadExitCall(const llvm::CallInst
*CInst)
{
    return createReturn(CInst);
}

} // namespace dda
} // namespace dg
<commit_msg>RWG: clang-format Calls.cpp<commit_after>#include <cassert>
#include <vector>

#include <llvm/IR/Constant.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_os_ostream.h>

#include "dg/llvm/PointerAnalysis/PointerGraph.h"

#include "llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h"
#include "llvm/llvm-utils.h"

namespace dg {
namespace dda {

static void reportIncompatibleCalls(
        const std::set<const llvm::Function *> &incompatibleCalls,
        const llvm::CallInst *CInst, size_t tried_num) {
    if (incompatibleCalls.empty()) {
        return;
    }

#ifndef NDEBUG
    llvm::errs() << "[RWG] warning: incompatible function pointers for "
                 << ValInfo(CInst) << "\n";

    for (auto *F : incompatibleCalls) {
        llvm::errs() << "   Tried: " << F->getName() << " of type "
                     << *F->getType() << "\n";
    }
#endif
    if (incompatibleCalls.size() == tried_num) {
        llvm::errs() << "[RWG] error: did not find any compatible function "
                        "pointer for "
                     << ValInfo(CInst) << "\n";
    }
}

NodesSeq<RWNode> LLVMReadWriteGraphBuilder::createCallToFunctions(
        const std::vector<const llvm::Function *> &functions,
        const llvm::CallInst *CInst) {
    assert(!functions.empty() && "No functions to call");

    std::set<const llvm::Function *> incompatibleCalls;
    std::vector<RWNode *> called_values;
    std::vector<RWSubgraph *> called_subgraphs;
    for (const auto *F : functions) {
        if (!llvmutils::callIsCompatible(F, CInst)) {
            incompatibleCalls.insert(F);
            continue;
        }

        if (const auto *model = _options.getFunctionModel(F->getName().str())) {
            called_values.push_back(funcFromModel(model, CInst));
        } else if (F->isDeclaration()) {
            called_values.push_back(createCallToUndefinedFunction(F, CInst));
        } else {
            auto *s = getSubgraph(F);
            assert(s && "Do not have a subgraph for a function");
            called_subgraphs.push_back(s);
        }
    }

    reportIncompatibleCalls(incompatibleCalls, CInst, functions.size());

    // if we call just one undefined function, simplify the graph and
    // do not create a CALL node -- just put the already created node there
    if (called_subgraphs.empty() && called_values.size() == 1) {
        return {called_values[0]};
    }
    RWNodeCall *callNode = RWNodeCall::get(&create(RWNodeType::CALL));
    for (auto *item : called_subgraphs)
        callNode->addCallee(item);
    for (auto *item : called_values)
        callNode->addCallee(item);
    return {callNode};
}

RWNode *
LLVMReadWriteGraphBuilder::createUnknownCall(const llvm::CallInst *CInst) {
    using namespace llvm;

    RWNode *node = &create(RWNodeType::GENERIC);

    // if we assume that undefined functions are pure
    // (have no side effects), we can bail out here
    if (_options.undefinedArePure())
        return node;

    bool args = false;
    if (_options.undefinedFunsReadAny()) {
        node->addUse(UNKNOWN_MEMORY);
    } else {
        args |= _options.undefinedFunsReadArgs();
    }

    if (_options.undefinedFunsWriteAny()) {
        node->addDef(UNKNOWN_MEMORY);
    } else {
        args |= _options.undefinedFunsWriteArgs();
    }

    if (!args)
        return node;

    // every pointer we pass into the undefined call may be defined
    // in the function
    for (unsigned int i = 0; i < CInst->getNumArgOperands(); ++i) {
        const Value *llvmOp = CInst->getArgOperand(i);

        // constants cannot be redefined except for global variables
        // (that are constant, but may point to non constant memory
        const Value *strippedValue = llvmOp->stripPointerCasts();
        if (isa<Constant>(strippedValue)) {
            const GlobalVariable *GV = dyn_cast<GlobalVariable>(strippedValue);
            // if the constant is not global variable,
            // or the global variable points to constant memory
            if (!GV || GV->isConstant())
                continue;
        }

        auto pts = PTA->getLLVMPointsToChecked(llvmOp);
        // if we do not have a pts, this is not pointer
        // relevant instruction. We must do it this way
        // instead of type checking, due to the inttoptr.
        if (!pts.first)
            continue;

        for (const auto &ptr : pts.second) {
            if (llvm::isa<llvm::Function>(ptr.value))
                // function may not be redefined
                continue;

            RWNode *target = getOperand(ptr.value);
            assert(target && "Don't have pointer target for call argument");

            // this call may use and define this memory
            if (_options.undefinedFunsWriteArgs() &&
                !_options.undefinedFunsWriteAny())
                node->addDef(target, Offset::UNKNOWN, Offset::UNKNOWN);
            if (_options.undefinedFunsReadArgs() &&
                !_options.undefinedFunsReadAny())
                node->addUse(target, Offset::UNKNOWN, Offset::UNKNOWN);
        }
    }

    return node;
}

/*
void LLVMReadWriteGraphBuilder::matchForksAndJoins()
{
    using namespace llvm;
    using namespace pta;

    ForkJoinAnalysis FJA{PTA};

    for (auto& it : threadJoinCalls) {
        // it.first -> llvm::CallInst, it.second -> RWNode *
        auto functions = FJA.joinFunctions(it.first);
        for (auto llvmFunction : functions) {
            auto graphIterator = subgraphs_map.find(llvmFunction);
            for (auto returnNode : graphIterator->second.returns) {
                makeEdge(returnNode, it.second);
            }
        }
    }
}
*/

RWNode *
LLVMReadWriteGraphBuilder::createIntrinsicCall(const llvm::CallInst *CInst) {
    using namespace llvm;

    const IntrinsicInst *I = cast<IntrinsicInst>(CInst);
    const Value *dest;
    const Value *lenVal;

    RWNode *ret;
    switch (I->getIntrinsicID()) {
    case Intrinsic::memmove:
    case Intrinsic::memcpy:
    case Intrinsic::memset:
        // memcpy/set <dest>, <src/val>, <len>
        dest = I->getOperand(0);
        lenVal = I->getOperand(2);
        break;
    case Intrinsic::vastart:
        // we create this node because this nodes works
        // as ALLOC in points-to, so we can have
        // reaching definitions to that
        ret = &create(RWNodeType::ALLOC);
        ret->addDef(ret, 0, Offset::UNKNOWN);
        return ret;
    default:
        return createUnknownCall(CInst);
    }

    ret = &create(RWNodeType::GENERIC);

    auto pts = PTA->getLLVMPointsToChecked(dest);
    if (!pts.first) {
        llvm::errs()
                << "[RWG] Error: No points-to information for destination in\n";
        llvm::errs() << ValInfo(I) << "\n";
        // continue, the points-to set is {unknown}
    }

    uint64_t len = Offset::UNKNOWN;
    if (const ConstantInt *C = dyn_cast<ConstantInt>(lenVal))
        len = C->getLimitedValue();

    for (const auto &ptr : pts.second) {
        if (llvm::isa<llvm::Function>(ptr.value))
            continue;

        Offset from, to;
        if (ptr.offset.isUnknown()) {
            // if the offset is UNKNOWN, use whole memory
            from = Offset::UNKNOWN;
            len = Offset::UNKNOWN;
        } else {
            from = *ptr.offset;
        }

        // do not allow overflow
        if (Offset::UNKNOWN - *from > len)
            to = from + len;
        else
            to = Offset::UNKNOWN;

        RWNode *target = getOperand(ptr.value);
        // assert(target && "Don't have pointer target for intrinsic call");
        if (!target) {
            // keeping such set is faster then printing it all to terminal
            // ... and we don't flood the terminal that way
            static std::set<const llvm::Value *> warned;
            if (warned.insert(ptr.value).second) {
                llvm::errs() << "[RWG] error at " << ValInfo(CInst) << "\n"
                             << "[RWG] error: Haven't created node for: "
                             << ValInfo(ptr.value) << "\n";
            }
            target = UNKNOWN_MEMORY;
        }

        // add the definition
        ret->addDef(target, from, to,
                    !from.isUnknown() && !to.isUnknown() /* strong update */);
    }

    return ret;
}

template <typename T>
std::pair<Offset, Offset> getFromTo(const llvm::CallInst *CInst, T what) {
    auto from = what->from.isOperand()
                        ? llvmutils::getConstantValue(
                                  CInst->getArgOperand(what->from.getOperand()))
                        : what->from.getOffset();
    auto to = what->to.isOperand()
                      ? llvmutils::getConstantValue(
                                CInst->getArgOperand(what->to.getOperand()))
                      : what->to.getOffset();

    return {from, to};
}

RWNode *LLVMReadWriteGraphBuilder::funcFromModel(const FunctionModel *model,
                                                 const llvm::CallInst *CInst) {
    RWNode *node = &create(RWNodeType::GENERIC);

    for (unsigned int i = 0; i < CInst->getNumArgOperands(); ++i) {
        if (!model->handles(i))
            continue;

        auto *const llvmOp = CInst->getArgOperand(i);
        auto pts = PTA->getLLVMPointsToChecked(llvmOp);
        // if we do not have a pts, this is not pointer
        // relevant instruction. We must do it this way
        // instead of type checking, due to the inttoptr.
        if (!pts.first) {
            llvm::errs()
                    << "[Warning]: did not find pt-set for modeled function\n";
            llvm::errs() << "           Func: " << model->name << ", operand "
                         << i << "\n";
            continue;
        }

        for (const auto &ptr : pts.second) {
            if (llvm::isa<llvm::Function>(ptr.value))
                // functions may not be redefined
                continue;

            RWNode *target = getOperand(ptr.value);
            assert(target && "Don't have pointer target for call argument");

            Offset from, to;
            if (const auto *defines = model->defines(i)) {
                std::tie(from, to) = getFromTo(CInst, defines);
                // this call may define this memory
                bool strong_updt = pts.second.size() == 1 &&
                                   !ptr.offset.isUnknown() &&
                                   !(ptr.offset + from).isUnknown() &&
                                   !(ptr.offset + to).isUnknown() &&
                                   !llvm::isa<llvm::CallInst>(ptr.value);
                // FIXME: what about vars in recursive functions?
                node->addDef(target, ptr.offset + from, ptr.offset + to,
                             strong_updt);
            }
            if (const auto *uses = model->uses(i)) {
                std::tie(from, to) = getFromTo(CInst, uses);
                // this call uses this memory
                node->addUse(target, ptr.offset + from, ptr.offset + to);
            }
        }
    }

    return node;
}
RWNode *LLVMReadWriteGraphBuilder::createCallToUndefinedFunction(
        const llvm::Function *function, const llvm::CallInst *CInst) {
    if (function->isIntrinsic()) {
        return createIntrinsicCall(CInst);
    }
    if (_options.threads) {
        // assert(false && "Threads unsupported yet");
        if (function->getName() == "pthread_create") {
            return createPthreadCreateCalls(CInst);
        } else if (function->getName() == "pthread_join") {
            return createPthreadJoinCall(CInst);
        } else if (function->getName() == "pthread_exit") {
            return createPthreadExitCall(CInst);
        }
    }

    auto type = _options.getAllocationFunction(function->getName().str());
    if (type != AllocationFunction::NONE) {
        if (type == AllocationFunction::REALLOC)
            return createRealloc(CInst);
        return createDynAlloc(CInst, type);
    }
    return createUnknownCall(CInst);

    assert(false && "Unreachable");
    abort();
}

RWNode *LLVMReadWriteGraphBuilder::createPthreadCreateCalls(
        const llvm::CallInst *CInst) {
    using namespace llvm;

    RWNode *rootNode = &create(RWNodeType::FORK);
    threadCreateCalls.emplace(CInst, rootNode);

    Value *calledValue = CInst->getArgOperand(2);
    const auto &functions = getCalledFunctions(calledValue, PTA);

    for (const Function *function : functions) {
        if (function->isDeclaration()) {
            llvm::errs()
                    << "[RWG] error: phtread_create spawns undefined function: "
                    << function->getName() << "\n";
            continue;
        }
    }
    return rootNode;
}

RWNode *
LLVMReadWriteGraphBuilder::createPthreadJoinCall(const llvm::CallInst *CInst) {
    // TODO later change this to create join node and set data correctly
    // we need just to create one node;
    // undefined call is overapproximation, so its ok
    RWNode *node = createUnknownCall(CInst);
    threadJoinCalls.emplace(CInst, node);
    return node;
}

RWNode *
LLVMReadWriteGraphBuilder::createPthreadExitCall(const llvm::CallInst *CInst) {
    return createReturn(CInst);
}

} // namespace dda
} // namespace dg
<|endoftext|>


<commit_before>// TODO(carpenter): move this into test/unit/command
//                  it's here now because it won't compile there

#include <gtest/gtest.h>
#include <stan/lang/compiler.hpp>
#include <stan/command/stanc_helper.hpp>
#include <test/unit/util.hpp>
#include <fstream>
#include <sstream>

void expect_find(const std::string& str, const std::string& target) {
  EXPECT_TRUE(str.find(target) != std::string::npos)
    << str << " does not contain " << target << std::endl;
}

TEST(commandStancHelper, printVersion) {
  std::stringstream ss;
  print_version(&ss);
  expect_find(ss.str(), "stanc version 2.");
}

TEST(commandStancHelper, printStancHelp) {
  std::stringstream ss;
  print_stanc_help(&ss);
  expect_find(ss.str(), "USAGE:  stanc [options] <model_file>");
  expect_find(ss.str(), "OPTIONS:");
}

bool create_test_file(const std::string& path, const std::string& program) {
  std::string cmd = "echo \"";
  cmd += program;
  cmd += "\" > ";
  cmd += path;
  cmd += "; chmod 444 ";
  cmd += path;
  int return_code = system(cmd.c_str());
  return return_code == 0;
}

bool create_test_file() {
  std::string program
    = "parameters { real y; } model { y ~ normal(0, 1); }";
  return create_test_file("test/test-models/temp-bar.stan", program);
}

TEST(commandStancHelper, deleteFile) {
  if (!create_test_file()) return;
  std::stringstream ss;
  delete_file(&ss, "test/test-models/temp-bar.stan");
  // test there's no error message
  EXPECT_EQ(0, ss.str().size());
  // and then test the file stream can't be opened
  std::fstream fs;
  fs.open("test/test-models/temp-bar.stan", std::fstream::in);
  EXPECT_FALSE(fs.is_open());
  fs.close();
}

int run_helper(const std::string& path,
               std::ostream& out, std::ostream& err) {
  int argc = 2;
  std::vector<const char*> argv_vec;
  argv_vec.push_back("main");
  argv_vec.push_back(path.c_str());
  const char** argv = &argv_vec[0];
  return stanc_helper(argc, argv, &out, &err);
}

TEST(commandStancHelper, readOnlyOK) {
  if (!create_test_file()) return;

  std::stringstream out;
  std::stringstream err;
  int rc = run_helper("test/test-models/temp-bar.stan", out, err);

  EXPECT_EQ(0, rc);
  expect_find(out.str(), "Model name=temp_bar_model");
  expect_find(out.str(), "Input file=test/test-models/temp-bar.stan");
  expect_find(out.str(), "Output file=temp_bar_model.cpp");
  EXPECT_EQ(0, err.str().size());

  delete_file(&err, "test/test-models/temp-bar.stan");
  delete_file(&err, "bar_model.cpp");
}

TEST(commandStancHelper, failRC) {
  std::string path = "test/test-models/temp-bar.stan";
  std::string prog
    = "parameters { real y; } model { y ~ ormal(0, 1); }";
  if (!create_test_file(path, prog)) return;

  std::stringstream out;
  std::stringstream err;
  int rc = run_helper(path, out, err);

  // TODO(carpenter): This should be -2 but it's -3 so
  // I only tested that it's != 0 to contrast with earlier success
  EXPECT_TRUE(rc != 0);

  delete_file(&err, "test/test-models/temp-bar.stan");
}

<commit_msg>test error output to help in Windows<commit_after>// TODO(carpenter): move this into test/unit/command
//                  it's here now because it won't compile there

#include <gtest/gtest.h>
#include <stan/lang/compiler.hpp>
#include <stan/command/stanc_helper.hpp>
#include <test/unit/util.hpp>
#include <fstream>
#include <sstream>

void expect_find(const std::string& str, const std::string& target) {
  EXPECT_TRUE(str.find(target) != std::string::npos)
    << str << " does not contain " << target << std::endl;
}

TEST(commandStancHelper, printVersion) {
  std::stringstream ss;
  print_version(&ss);
  expect_find(ss.str(), "stanc version 2.");
}

TEST(commandStancHelper, printStancHelp) {
  std::stringstream ss;
  print_stanc_help(&ss);
  expect_find(ss.str(), "USAGE:  stanc [options] <model_file>");
  expect_find(ss.str(), "OPTIONS:");
}

bool create_test_file(const std::string& path, const std::string& program) {
  std::string cmd = "echo \"";
  cmd += program;
  cmd += "\" > ";
  cmd += path;
  cmd += "; chmod 444 ";
  cmd += path;
  int return_code = system(cmd.c_str());
  return return_code == 0;
}

bool create_test_file() {
  std::string program
    = "parameters { real y; } model { y ~ normal(0, 1); }";
  return create_test_file("test/test-models/temp-bar.stan", program);
}

TEST(commandStancHelper, deleteFile) {
  if (!create_test_file()) return;
  std::stringstream ss;
  delete_file(&ss, "test/test-models/temp-bar.stan");
  // test there's no error message
  EXPECT_EQ(0, ss.str().size());
  // and then test the file stream can't be opened
  std::fstream fs;
  fs.open("test/test-models/temp-bar.stan", std::fstream::in);
  EXPECT_FALSE(fs.is_open());
  fs.close();
}

int run_helper(const std::string& path,
               std::ostream& out, std::ostream& err) {
  int argc = 2;
  std::vector<const char*> argv_vec;
  argv_vec.push_back("main");
  argv_vec.push_back(path.c_str());
  const char** argv = &argv_vec[0];
  return stanc_helper(argc, argv, &out, &err);
}

TEST(commandStancHelper, readOnlyOK) {
  if (!create_test_file()) return;

  std::stringstream out;
  std::stringstream err;
  int rc = run_helper("test/test-models/temp-bar.stan", out, err);

  EXPECT_EQ(0, rc)
    << "out=" << out.str() << std::endl << "err=" << err.str() << std::endl;
  expect_find(out.str(), "Model name=temp_bar_model");
  expect_find(out.str(), "Input file=test/test-models/temp-bar.stan");
  expect_find(out.str(), "Output file=temp_bar_model.cpp");
  EXPECT_EQ(0, err.str().size())
    << "error=" << err.str() << std::endl;

  delete_file(&err, "test/test-models/temp-bar.stan");
  delete_file(&err, "bar_model.cpp");
}

TEST(commandStancHelper, failRC) {
  std::string path = "test/test-models/temp-bar.stan";
  std::string prog
    = "parameters { real y; } model { y ~ ormal(0, 1); }";
  if (!create_test_file(path, prog)) return;

  std::stringstream out;
  std::stringstream err;
  int rc = run_helper(path, out, err);

  // TODO(carpenter): This should be -2 but it's -3 so
  // I only tested that it's != 0 to contrast with earlier success
  EXPECT_TRUE(rc != 0);

  delete_file(&err, "test/test-models/temp-bar.stan");
}

<|endoftext|>


<commit_before><commit_msg>Basic unit tests for the quasi-newton updates.<commit_after><|endoftext|>


<commit_before>#pragma once
#include <cstring>
#include <string>

class StringView {
public:
	using iterator = const char*;

	constexpr StringView() : data_(nullptr), length_(0) {}

	constexpr StringView(const StringView&) = default;
	constexpr StringView(StringView&&) = default;
	StringView& operator =(const StringView&) = default;
	StringView& operator =(StringView&&) = default;

	StringView(const char* begin, const char* end) : data_(begin), length_(static_cast<size_t>(end - begin)) {}
	StringView(const char* data, size_t length) : data_(data), length_(length) {}
	StringView(const char* data) : data_(data), length_(strlen(data)) {}
	StringView(const std::string& data) : data_(data.c_str()), length_(data.length()) {}

	constexpr char operator[](const size_t index) const {
		return data_[index];
	}

	constexpr const char* data() const {
		return data_;
	}

	constexpr const char* c_str() const {
		return data_;
	}

	constexpr size_t length() const {
		return length_;
	}

	constexpr bool empty() const {
		return length_ == 0;
	}

	constexpr char front() const {
		return data_[0];
	}

	constexpr char back() const {
		return data_[length_ - 1];
	}

	std::string to_string() const {
		return{ begin(), end() };
	}

	constexpr iterator begin() const {
		return data_;
	}

	constexpr iterator end() const {
		return data_ + length_;
	}

	StringView substr(const size_t pos) const {
		return StringView(data_ + pos, length_ - pos);
	}

	StringView substr(const size_t pos, const size_t len) const {
		return StringView(data_ + pos, len);
	}

	size_t find(const char ch, const size_t pos) const {
		for (size_t i = pos; i < length_; ++i) {
			if (data_[i] == ch) {
				return i;
			}
		}
		return std::string::npos;
	}

	std::string operator +(const StringView& rhs) const;

	friend bool operator ==(const StringView& lhs, const StringView& rhs);
	friend bool operator ==(const StringView& lhs, const char* rhs);
	friend bool operator ==(const char* lhs, const StringView& rhs);
	friend bool operator !=(const StringView& lhs, const StringView& rhs);
	friend bool operator !=(const StringView& lhs, const char* rhs);
	friend bool operator !=(const char* lhs, const StringView& rhs);

private:
	const char* data_;
	size_t length_;

};

bool operator ==(const StringView& lhs, const StringView& rhs) {
	if (lhs.length_ != rhs.length_) {
		return false;
	}
	for (size_t i = 0; i < lhs.length_; ++i) {
		if (lhs.data_[i] != rhs.data_[i]) {
			return false;
		}
	}
	return true;
}

bool operator ==(const StringView& lhs, const char* rhs) {
	for (size_t i = 0; i < lhs.length_; ++i) {
		if (rhs[i] == 0 || rhs[i] != lhs.data_[i]) {
			return false;
		}
	}
	return rhs[lhs.length_] == 0;
}

bool operator ==(const char* lhs, const StringView& rhs) {
	return rhs == lhs;
}

bool operator !=(const StringView& lhs, const StringView& rhs) {
	return !(lhs == rhs);
}

bool operator !=(const StringView& lhs, const char* rhs) {
	return !(lhs == rhs);
}

bool operator !=(const char* lhs, const StringView& rhs) {
	return !(rhs == lhs);
}
<commit_msg>Added caide keep instruction to constexpr ctor for StringView.<commit_after>#pragma once
#include <cstring>
#include <string>

class StringView {
public:
	using iterator = const char*;

	/// caide keep
	constexpr StringView() : data_(nullptr), length_(0) {}

	constexpr StringView(const StringView&) = default;
	constexpr StringView(StringView&&) = default;
	StringView& operator =(const StringView&) = default;
	StringView& operator =(StringView&&) = default;

	StringView(const char* begin, const char* end) : data_(begin), length_(static_cast<size_t>(end - begin)) {}
	StringView(const char* data, size_t length) : data_(data), length_(length) {}
	StringView(const char* data) : data_(data), length_(strlen(data)) {}
	StringView(const std::string& data) : data_(data.c_str()), length_(data.length()) {}

	constexpr char operator[](const size_t index) const {
		return data_[index];
	}

	constexpr const char* data() const {
		return data_;
	}

	constexpr const char* c_str() const {
		return data_;
	}

	constexpr size_t length() const {
		return length_;
	}

	constexpr bool empty() const {
		return length_ == 0;
	}

	constexpr char front() const {
		return data_[0];
	}

	constexpr char back() const {
		return data_[length_ - 1];
	}

	std::string to_string() const {
		return{ begin(), end() };
	}

	constexpr iterator begin() const {
		return data_;
	}

	constexpr iterator end() const {
		return data_ + length_;
	}

	StringView substr(const size_t pos) const {
		return StringView(data_ + pos, length_ - pos);
	}

	StringView substr(const size_t pos, const size_t len) const {
		return StringView(data_ + pos, len);
	}

	size_t find(const char ch, const size_t pos) const {
		for (size_t i = pos; i < length_; ++i) {
			if (data_[i] == ch) {
				return i;
			}
		}
		return std::string::npos;
	}

	std::string operator +(const StringView& rhs) const;

	friend bool operator ==(const StringView& lhs, const StringView& rhs);
	friend bool operator ==(const StringView& lhs, const char* rhs);
	friend bool operator ==(const char* lhs, const StringView& rhs);
	friend bool operator !=(const StringView& lhs, const StringView& rhs);
	friend bool operator !=(const StringView& lhs, const char* rhs);
	friend bool operator !=(const char* lhs, const StringView& rhs);

private:
	const char* data_;
	size_t length_;

};

bool operator ==(const StringView& lhs, const StringView& rhs) {
	if (lhs.length_ != rhs.length_) {
		return false;
	}
	for (size_t i = 0; i < lhs.length_; ++i) {
		if (lhs.data_[i] != rhs.data_[i]) {
			return false;
		}
	}
	return true;
}

bool operator ==(const StringView& lhs, const char* rhs) {
	for (size_t i = 0; i < lhs.length_; ++i) {
		if (rhs[i] == 0 || rhs[i] != lhs.data_[i]) {
			return false;
		}
	}
	return rhs[lhs.length_] == 0;
}

bool operator ==(const char* lhs, const StringView& rhs) {
	return rhs == lhs;
}

bool operator !=(const StringView& lhs, const StringView& rhs) {
	return !(lhs == rhs);
}

bool operator !=(const StringView& lhs, const char* rhs) {
	return !(lhs == rhs);
}

bool operator !=(const char* lhs, const StringView& rhs) {
	return !(rhs == lhs);
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2017 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2014 - 2017)
//   Rene Milk       (2014, 2016 - 2017)
//   Tobias Leibner  (2014)

#ifndef DUNE_GDT_SPACES_BLOCK_HH
#define DUNE_GDT_SPACES_BLOCK_HH

#include <dune/xt/common/exceptions.hh>
#include <dune/xt/common/type_traits.hh>
#include <dune/xt/grid/type_traits.hh>
#include <dune/xt/grid/dd/subdomains/grid.hh>
#include <dune/gdt/type_traits.hh>

#include "mapper/block.hh"

#include "../../spaces/interface.hh"

namespace Dune {
namespace GDT {

template <class LocalSpaceImp>
class BlockSpace;

namespace internal {

template <class LocalSpaceType>
class BlockSpaceTraits
{
  static_assert(is_space<LocalSpaceType>::value, "LocalSpaceType has to be derived from SpaceInterface!");
  typedef XT::Grid::DD::SubdomainGrid<XT::Grid::extract_grid_t<typename LocalSpaceType::GridLayerType>>
      DdSubdomainsGridType;

public:
  typedef BlockSpace<LocalSpaceType> derived_type;
  static const int polOrder = LocalSpaceType::polOrder;
  static const bool continuous = false;
  typedef std::vector<std::shared_ptr<const LocalSpaceType>> BackendType;
  typedef BlockMapper<LocalSpaceType> MapperType;
  typedef typename LocalSpaceType::BaseFunctionSetType BaseFunctionSetType;
  typedef typename DdSubdomainsGridType::GlobalGridPartType GridLayerType;
  typedef typename LocalSpaceType::RangeFieldType RangeFieldType;

  static const XT::Grid::Backends layer_backend = XT::Grid::Backends::part;
  static const constexpr Backends backend_type{Backends::gdt};
  using CommunicationChooserType = CommunicationChooser<GridLayerType, true>;
  using CommunicatorType = typename CommunicationChooserType::type;

  static const bool needs_grid_view = false;
}; // class BlockSpaceTraits

} // namespace internal

template <class LocalSpaceImp>
class BlockSpace : public SpaceInterface<internal::BlockSpaceTraits<LocalSpaceImp>,
                                         LocalSpaceImp::dimDomain,
                                         LocalSpaceImp::dimRange,
                                         LocalSpaceImp::dimRangeCols>
{
  typedef SpaceInterface<internal::BlockSpaceTraits<LocalSpaceImp>,
                         LocalSpaceImp::dimDomain,
                         LocalSpaceImp::dimRange,
                         LocalSpaceImp::dimRangeCols>
      BaseType;
  typedef BlockSpace<LocalSpaceImp> ThisType;

public:
  typedef internal::BlockSpaceTraits<LocalSpaceImp> Traits;
  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef LocalSpaceImp LocalSpaceType;

  typedef typename BaseType::PatternType PatternType;
  typedef typename BaseType::GridLayerType GridLayerType;
  typedef typename BaseType::EntityType EntityType;
  typedef CommunicationChooser<GridLayerType, true> CommunicationChooserType;
  typedef typename CommunicationChooserType::Type CommunicatorType;

  typedef XT::Grid::DD::SubdomainGrid<typename XT::Grid::extract_grid<GridLayerType>::type> DdSubdomainsGridType;
  static const constexpr Backends backend_type{Backends::gdt};

  BlockSpace(const DdSubdomainsGridType& grid, const std::vector<std::shared_ptr<const LocalSpaceType>>& spaces)
    : dd_grid_(grid)
    , entity_to_subdomain_map_(dd_grid_.entityToSubdomainMap())
    , global_grid_part_(new GridLayerType(dd_grid_.globalGridPart()))
    , local_spaces_(new std::vector<std::shared_ptr<const LocalSpaceType>>(spaces))
    , mapper_(new MapperType(dd_grid_, global_grid_part_, local_spaces_))
    , communicator_(Traits::CommunicationChooserType::create(*global_grid_part_))
    , communicator_prepared_(false)
  {
    if (local_spaces_->size() != dd_grid_.size())
      DUNE_THROW(XT::Common::Exceptions::shapes_do_not_match,
                 "You have to provide a local space (or a nullptr) for each subdomain of the DD subdomains grid!\n"
                     << "  Number of subdomains: "
                     << dd_grid_.size()
                     << "\n"
                     << "  Number of local spaces given: "
                     << local_spaces_->size());
  } // BlockSpace(...)

  BlockSpace(const ThisType& other) = default;
  BlockSpace(ThisType&& source) = default;

  ThisType& operator=(const ThisType& other) = delete;
  ThisType& operator=(ThisType&& source) = delete;

  const GridLayerType& grid_layer() const
  {
    return *global_grid_part_;
  }

  GridLayerType& grid_layer()
  {
    return *global_grid_part_;
  }

  const BackendType& backend() const
  {
    return *local_spaces_;
  }

  const MapperType& mapper() const
  {
    return *mapper_;
  }

  BaseFunctionSetType base_function_set(const EntityType& entity) const
  {
    const size_t block = find_block_of(entity);
    if (backend()[block] == nullptr)
      DUNE_THROW(InvalidStateException, "You did not provide a local space for block " << block << "!");
    return backend()[block]->base_function_set(entity);
  }

  template <class ConstraintsType>
  void local_constraints(const EntityType& /*entity*/, ConstraintsType& /*ret*/) const
  {
    DUNE_THROW(NotImplemented, "I am not sure yet how to implement this!");
  }

  template <class G, class S, size_t d, size_t r, size_t rC>
  PatternType compute_pattern(const GridView<G>& /*local_grid_layer*/,
                              const SpaceInterface<S, d, r, rC>& /*ansatz_space*/) const
  {
    DUNE_THROW(NotImplemented, "I am not sure yet how to implement this!");
    return PatternType();
  }

  typename Traits::CommunicatorType& communicator() const
  {
    if (!communicator_prepared_)
      communicator_prepared_ = CommunicationChooserType::prepare(*this, *communicator_);
    return *communicator_;
    return *communicator_;
  }

  const DdSubdomainsGridType& dd_grid() const
  {
    return dd_grid_;
  }

  size_t num_blocks() const
  {
    return local_spaces_->size();
  }

  const LocalSpaceType& local_space(const size_t block) const
  {
    if (block >= num_blocks())
      DUNE_THROW(XT::Common::Exceptions::index_out_of_range,
                 "  num_blocks: " << num_blocks() << "\n  block: " << block);
    return *(local_spaces_->at(block));
  }

private:
  template <class EntityType>
  size_t find_block_of(const EntityType& entity) const
  {
    const auto global_entity_index = global_grid_part_->indexSet().index(entity);
    const auto result = entity_to_subdomain_map_->find(global_entity_index);
#ifndef NDEBUG
    if (result == entity_to_subdomain_map_->end())
      DUNE_THROW(XT::Common::Exceptions::internal_error,
                 "Entity " << global_entity_index << " of the global grid part was not found in the multiscale grid!");
#endif // NDEBUG
    const size_t subdomain = result->second;
#ifndef NDEBUG
    if (subdomain >= dd_grid_.size())
      DUNE_THROW(XT::Common::Exceptions::internal_error,
                 "The DD subdomains grid is corrupted!\nIt reports Entity " << global_entity_index
                                                                            << " to be in subdomain "
                                                                            << subdomain
                                                                            << " while only having "
                                                                            << dd_grid_.size()
                                                                            << " subdomains!");
#endif // NDEBUG
    return subdomain;
  } // ... find_block_of(...)

  const DdSubdomainsGridType& dd_grid_;
  const std::shared_ptr<const typename DdSubdomainsGridType::EntityToSubdomainMapType> entity_to_subdomain_map_;
  const std::shared_ptr<GridLayerType> global_grid_part_;
  const std::shared_ptr<std::vector<std::shared_ptr<const LocalSpaceType>>> local_spaces_;
  const std::shared_ptr<MapperType> mapper_;
  mutable std::shared_ptr<typename Traits::CommunicatorType> communicator_;
  mutable bool communicator_prepared_;
}; // class BlockSpace

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_BLOCK_HH
<commit_msg>[block.space] add missing associates_data_with(int codim)<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2017 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2014 - 2017)
//   Rene Milk       (2014, 2016 - 2017)
//   Tobias Leibner  (2014)

#ifndef DUNE_GDT_SPACES_BLOCK_HH
#define DUNE_GDT_SPACES_BLOCK_HH

#include <dune/xt/common/exceptions.hh>
#include <dune/xt/common/type_traits.hh>
#include <dune/xt/grid/type_traits.hh>
#include <dune/xt/grid/dd/subdomains/grid.hh>
#include <dune/gdt/type_traits.hh>

#include "mapper/block.hh"

#include "../../spaces/interface.hh"

namespace Dune {
namespace GDT {

template <class LocalSpaceImp>
class BlockSpace;

namespace internal {

template <class LocalSpaceType>
class BlockSpaceTraits
{
  static_assert(is_space<LocalSpaceType>::value, "LocalSpaceType has to be derived from SpaceInterface!");
  typedef XT::Grid::DD::SubdomainGrid<XT::Grid::extract_grid_t<typename LocalSpaceType::GridLayerType>>
      DdSubdomainsGridType;

public:
  typedef BlockSpace<LocalSpaceType> derived_type;
  static const int polOrder = LocalSpaceType::polOrder;
  static const bool continuous = false;
  typedef std::vector<std::shared_ptr<const LocalSpaceType>> BackendType;
  typedef BlockMapper<LocalSpaceType> MapperType;
  typedef typename LocalSpaceType::BaseFunctionSetType BaseFunctionSetType;
  typedef typename DdSubdomainsGridType::GlobalGridPartType GridLayerType;
  typedef typename LocalSpaceType::RangeFieldType RangeFieldType;

  static const XT::Grid::Backends layer_backend = XT::Grid::Backends::part;
  static const constexpr Backends backend_type{Backends::gdt};
  using CommunicationChooserType = CommunicationChooser<GridLayerType, true>;
  using CommunicatorType = typename CommunicationChooserType::type;

  static const bool needs_grid_view = false;
}; // class BlockSpaceTraits

} // namespace internal

template <class LocalSpaceImp>
class BlockSpace : public SpaceInterface<internal::BlockSpaceTraits<LocalSpaceImp>,
                                         LocalSpaceImp::dimDomain,
                                         LocalSpaceImp::dimRange,
                                         LocalSpaceImp::dimRangeCols>
{
  typedef SpaceInterface<internal::BlockSpaceTraits<LocalSpaceImp>,
                         LocalSpaceImp::dimDomain,
                         LocalSpaceImp::dimRange,
                         LocalSpaceImp::dimRangeCols>
      BaseType;
  typedef BlockSpace<LocalSpaceImp> ThisType;

public:
  typedef internal::BlockSpaceTraits<LocalSpaceImp> Traits;
  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef LocalSpaceImp LocalSpaceType;

  typedef typename BaseType::PatternType PatternType;
  typedef typename BaseType::GridLayerType GridLayerType;
  typedef typename BaseType::EntityType EntityType;
  typedef CommunicationChooser<GridLayerType, true> CommunicationChooserType;
  typedef typename CommunicationChooserType::Type CommunicatorType;

  typedef XT::Grid::DD::SubdomainGrid<typename XT::Grid::extract_grid<GridLayerType>::type> DdSubdomainsGridType;
  static const constexpr Backends backend_type{Backends::gdt};

  BlockSpace(const DdSubdomainsGridType& grid, const std::vector<std::shared_ptr<const LocalSpaceType>>& spaces)
    : dd_grid_(grid)
    , entity_to_subdomain_map_(dd_grid_.entityToSubdomainMap())
    , global_grid_part_(new GridLayerType(dd_grid_.globalGridPart()))
    , local_spaces_(new std::vector<std::shared_ptr<const LocalSpaceType>>(spaces))
    , mapper_(new MapperType(dd_grid_, global_grid_part_, local_spaces_))
    , communicator_(Traits::CommunicationChooserType::create(*global_grid_part_))
    , communicator_prepared_(false)
  {
    if (local_spaces_->size() != dd_grid_.size())
      DUNE_THROW(XT::Common::Exceptions::shapes_do_not_match,
                 "You have to provide a local space (or a nullptr) for each subdomain of the DD subdomains grid!\n"
                     << "  Number of subdomains: "
                     << dd_grid_.size()
                     << "\n"
                     << "  Number of local spaces given: "
                     << local_spaces_->size());
  } // BlockSpace(...)

  BlockSpace(const ThisType& other) = default;
  BlockSpace(ThisType&& source) = default;

  ThisType& operator=(const ThisType& other) = delete;
  ThisType& operator=(ThisType&& source) = delete;

  const GridLayerType& grid_layer() const
  {
    return *global_grid_part_;
  }

  GridLayerType& grid_layer()
  {
    return *global_grid_part_;
  }

  const BackendType& backend() const
  {
    return *local_spaces_;
  }

  const MapperType& mapper() const
  {
    return *mapper_;
  }

  BaseFunctionSetType base_function_set(const EntityType& entity) const
  {
    const size_t block = find_block_of(entity);
    if (backend()[block] == nullptr)
      DUNE_THROW(InvalidStateException, "You did not provide a local space for block " << block << "!");
    return backend()[block]->base_function_set(entity);
  }

  template <class ConstraintsType>
  void local_constraints(const EntityType& /*entity*/, ConstraintsType& /*ret*/) const
  {
    DUNE_THROW(NotImplemented, "I am not sure yet how to implement this!");
  }

  template <class G, class S, size_t d, size_t r, size_t rC>
  PatternType compute_pattern(const GridView<G>& /*local_grid_layer*/,
                              const SpaceInterface<S, d, r, rC>& /*ansatz_space*/) const
  {
    DUNE_THROW(NotImplemented, "I am not sure yet how to implement this!");
    return PatternType();
  }

  typename Traits::CommunicatorType& communicator() const
  {
    if (!communicator_prepared_)
      communicator_prepared_ = CommunicationChooserType::prepare(*this, *communicator_);
    return *communicator_;
    return *communicator_;
  }

  const DdSubdomainsGridType& dd_grid() const
  {
    return dd_grid_;
  }

  size_t num_blocks() const
  {
    return local_spaces_->size();
  }

  const LocalSpaceType& local_space(const size_t block) const
  {
    if (block >= num_blocks())
      DUNE_THROW(XT::Common::Exceptions::index_out_of_range,
                 "  num_blocks: " << num_blocks() << "\n  block: " << block);
    return *(local_spaces_->at(block));
  }

  static constexpr bool associates_data_with(int codim)
  {
    return LocalSpaceType::associates_data_with(codim);
  }

private:
  template <class EntityType>
  size_t find_block_of(const EntityType& entity) const
  {
    const auto global_entity_index = global_grid_part_->indexSet().index(entity);
    const auto result = entity_to_subdomain_map_->find(global_entity_index);
#ifndef NDEBUG
    if (result == entity_to_subdomain_map_->end())
      DUNE_THROW(XT::Common::Exceptions::internal_error,
                 "Entity " << global_entity_index << " of the global grid part was not found in the multiscale grid!");
#endif // NDEBUG
    const size_t subdomain = result->second;
#ifndef NDEBUG
    if (subdomain >= dd_grid_.size())
      DUNE_THROW(XT::Common::Exceptions::internal_error,
                 "The DD subdomains grid is corrupted!\nIt reports Entity " << global_entity_index
                                                                            << " to be in subdomain "
                                                                            << subdomain
                                                                            << " while only having "
                                                                            << dd_grid_.size()
                                                                            << " subdomains!");
#endif // NDEBUG
    return subdomain;
  } // ... find_block_of(...)

  const DdSubdomainsGridType& dd_grid_;
  const std::shared_ptr<const typename DdSubdomainsGridType::EntityToSubdomainMapType> entity_to_subdomain_map_;
  const std::shared_ptr<GridLayerType> global_grid_part_;
  const std::shared_ptr<std::vector<std::shared_ptr<const LocalSpaceType>>> local_spaces_;
  const std::shared_ptr<MapperType> mapper_;
  mutable std::shared_ptr<typename Traits::CommunicatorType> communicator_;
  mutable bool communicator_prepared_;
}; // class BlockSpace

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_BLOCK_HH
<|endoftext|>


<commit_before><commit_msg>Remove TODO comment.<commit_after><|endoftext|>