<commit_before>
/*
 *  Stream.cpp
 *  sfeMovie project
 *
 *  Copyright (C) 2010-2014 Lucas Soltic
 *  lucas.soltic@orange.fr
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

#include "Demuxer.hpp"
#include "VideoStream.hpp"
#include "AudioStream.hpp"
#include "SubtitleStream.hpp"
#include "Threads.hpp"
#include "Log.hpp"
#include "Utilities.hpp"
#include <iostream>
#include <stdexcept>

namespace sfe {
	std::list<Demuxer::DemuxerInfo> Demuxer::g_availableDemuxers;
	std::list<Demuxer::DecoderInfo> Demuxer::g_availableDecoders;

	static void loadFFmpeg(void)
	{
		ONCE(av_register_all());
		ONCE(avcodec_register_all());
	}

	static MediaType AVMediaTypeToMediaType(AVMediaType type)
	{
		switch (type) {
			case AVMEDIA_TYPE_AUDIO:	return MEDIA_TYPE_AUDIO;
			case AVMEDIA_TYPE_SUBTITLE:	return MEDIA_TYPE_SUBTITLE;
			case AVMEDIA_TYPE_VIDEO:	return MEDIA_TYPE_VIDEO;
			default:					return MEDIA_TYPE_UNKNOWN;
		}
	}

	const std::list<Demuxer::DemuxerInfo>& Demuxer::getAvailableDemuxers(void)
	{
		AVInputFormat* demuxer = NULL;
		loadFFmpeg();

		if (g_availableDemuxers.empty()) {
			while (NULL != (demuxer = av_iformat_next(demuxer))) {
				DemuxerInfo info = {
					.name = std::string(demuxer->name),
					.description = std::string(demuxer->long_name)
				};

				g_availableDemuxers.push_back(info);
			}
		}

		return g_availableDemuxers;
	}

	const std::list<Demuxer::DecoderInfo>& Demuxer::getAvailableDecoders(void)
	{
		AVCodecRef codec = NULL;
		loadFFmpeg();

		if (g_availableDecoders.empty()) {
			while (NULL != (codec = av_codec_next(codec))) {
				DecoderInfo info = {
					.name = avcodec_get_name(codec->id),
					.description = codec->long_name,
					.type = AVMediaTypeToMediaType(codec->type)
				};

				g_availableDecoders.push_back(info);
			}
		}

		return g_availableDecoders;
	}

	Demuxer::Demuxer(const std::string& sourceFile, Timer& timer) :
	m_avFormatCtx(NULL),
	m_eofReached(false),
	m_streams(),
	m_ignoredStreams(),
	m_synchronized(),
	m_timer(timer)
	{
		CHECK(sourceFile.size(), "Demuxer::Demuxer() - invalid argument: sourceFile");

		int err = 0;

		// Load all the decoders
		loadFFmpeg();

		// Open the movie file
		err = avformat_open_input(&m_avFormatCtx, sourceFile.c_str(), NULL, NULL);
		CHECK0(err, "Demuxer::Demuxer() - error while opening media: " + sourceFile);
		CHECK(m_avFormatCtx, "Demuxer() - inconsistency: media context cannot be null");

		// Read the general movie informations
		err = avformat_find_stream_info(m_avFormatCtx, NULL);
		CHECK0(err, "Demuxer::Demuxer() - error while retreiving media information");

		// Find all interesting streams
		for (int i = 0; i < m_avFormatCtx->nb_streams; i++) {
			AVStreamRef ffstream = m_avFormatCtx->streams[i];

			try {
				switch (ffstream->codec->codec_type) {
					case AVMEDIA_TYPE_VIDEO:
						m_streams[ffstream->index] = new VideoStream(ffstream, *this, timer);
						sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " video stream");
						break;

					case AVMEDIA_TYPE_AUDIO:
						m_streams[ffstream->index] = new AudioStream(ffstream, *this, timer);
						sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " audio stream");
						break;

						/** TODO
						 case AVMEDIA_TYPE_SUBTITLE:
						 m_streams.push_back(new SubtitleStream(ffstream));
						 break;
						 */

					default:
						m_ignoredStreams[ffstream->index] = std::string(std::string(av_get_media_type_string(ffstream->codec->codec_type)) + "/" + avcodec_get_name(ffstream->codec->codec_id));
						sfeLogWarning(m_ignoredStreams[ffstream->index] + "' stream ignored");
						break;
				}
			} catch (std::runtime_error& e) {
				std::cerr << "Demuxer::Demuxer() - " << e.what() << std::endl;
			}
		}
	}

	Demuxer::~Demuxer(void)
	{
		if (m_timer.getStatus() != Timer::Stopped)
			m_timer.stop();

		while (m_streams.size()) {
			delete m_streams.begin()->second;
			m_streams.erase(m_streams.begin());
		}

		if (m_avFormatCtx) {
			avformat_close_input(&m_avFormatCtx);
		}
	}

	const std::map<int, Stream*>& Demuxer::getStreams(void) const
	{
		return m_streams;
	}

	std::set<Stream*> Demuxer::getStreamsOfType(MediaType type) const
	{
		std::set<Stream*> streamSet;

		std::map<int, Stream*>::const_iterator it;

		for (it = m_streams.begin(); it != m_streams.end(); it++) {
			if (it->second->getStreamKind() == type)
				streamSet.insert(it->second);
		}

		return streamSet;
	}

	void Demuxer::feedStream(Stream& stream)
	{
		sf::Lock l(m_synchronized);

//		sfeLogDebug(Threads::currentThreadName());

		while (!didReachEndOfFile() && stream.needsMoreData()) {
			AVPacketRef pkt = readPacket();

			if (!pkt) {
				m_eofReached = true;
			} else {
				if (!distributePacket(pkt)) {
					sfeLogWarning(m_ignoredStreams[pkt->stream_index] + " packet not handled and dropped");
					av_free_packet(pkt);
					av_free(pkt);
				}
			}
		}
	}

	void Demuxer::updateVideoStreams(void)
	{
		std::set<Stream*> streams = getStreamsOfType(MEDIA_TYPE_VIDEO);
		std::set<Stream*>::iterator it;

		for (it = streams.begin();it != streams.end(); it++) {
			VideoStream* vStream = dynamic_cast<VideoStream*>(*it);
			CHECK(vStream, "Demuxer::updateVideoStreams() - got non video streams");

			vStream->updateTexture();
		}
	}

	bool Demuxer::didReachEndOfFile(void) const
	{
		return m_eofReached;
	}

	AVPacketRef Demuxer::readPacket(void)
	{
		sf::Lock l(m_synchronized);
//		sfeLogDebug(Threads::currentThreadName());

		AVPacket *pkt = NULL;
		int err = 0;

		pkt = (AVPacket *)av_malloc(sizeof(*pkt));
		CHECK(pkt, "Demuxer::readPacket() - out of memory");
		av_init_packet(pkt);

		err = av_read_frame(m_avFormatCtx, pkt);

		if (err < 0) {
			av_free_packet(pkt);
			av_free(pkt);
			pkt = NULL;
		}

		return pkt;
	}

	bool Demuxer::distributePacket(AVPacketRef packet)
	{
		sf::Lock l(m_synchronized);
		CHECK(packet, "Demuxer::distributePacket() - invalid argument");
//		sfeLogDebug(Threads::currentThreadName());

		bool result = false;
		std::map<int, Stream*>::iterator it = m_streams.find(packet->stream_index);

		if (it != m_streams.end()) {
			it->second->pushEncodedData(packet);
			result = true;
		}

		return result;
	}

	void Demuxer::requestMoreData(Stream& starvingStream)
	{
		sf::Lock l(m_synchronized);
//		sfeLogDebug(Threads::currentThreadName());

		feedStream(starvingStream);
	}
}
<commit_msg>#34 Removed dot struct notation<commit_after>
/*
 *  Stream.cpp
 *  sfeMovie project
 *
 *  Copyright (C) 2010-2014 Lucas Soltic
 *  lucas.soltic@orange.fr
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

#include "Demuxer.hpp"
#include "VideoStream.hpp"
#include "AudioStream.hpp"
#include "SubtitleStream.hpp"
#include "Threads.hpp"
#include "Log.hpp"
#include "Utilities.hpp"
#include <iostream>
#include <stdexcept>

namespace sfe {
	std::list<Demuxer::DemuxerInfo> Demuxer::g_availableDemuxers;
	std::list<Demuxer::DecoderInfo> Demuxer::g_availableDecoders;

	static void loadFFmpeg(void)
	{
		ONCE(av_register_all());
		ONCE(avcodec_register_all());
	}

	static MediaType AVMediaTypeToMediaType(AVMediaType type)
	{
		switch (type) {
			case AVMEDIA_TYPE_AUDIO:	return MEDIA_TYPE_AUDIO;
			case AVMEDIA_TYPE_SUBTITLE:	return MEDIA_TYPE_SUBTITLE;
			case AVMEDIA_TYPE_VIDEO:	return MEDIA_TYPE_VIDEO;
			default:					return MEDIA_TYPE_UNKNOWN;
		}
	}

	const std::list<Demuxer::DemuxerInfo>& Demuxer::getAvailableDemuxers(void)
	{
		AVInputFormat* demuxer = NULL;
		loadFFmpeg();

		if (g_availableDemuxers.empty()) {
			while (NULL != (demuxer = av_iformat_next(demuxer))) {
				DemuxerInfo info = {
					std::string(demuxer->name),
					std::string(demuxer->long_name)
				};

				g_availableDemuxers.push_back(info);
			}
		}

		return g_availableDemuxers;
	}

	const std::list<Demuxer::DecoderInfo>& Demuxer::getAvailableDecoders(void)
	{
		AVCodecRef codec = NULL;
		loadFFmpeg();

		if (g_availableDecoders.empty()) {
			while (NULL != (codec = av_codec_next(codec))) {
				DecoderInfo info = {
					avcodec_get_name(codec->id),
					codec->long_name,
					AVMediaTypeToMediaType(codec->type)
				};

				g_availableDecoders.push_back(info);
			}
		}

		return g_availableDecoders;
	}

	Demuxer::Demuxer(const std::string& sourceFile, Timer& timer) :
	m_avFormatCtx(NULL),
	m_eofReached(false),
	m_streams(),
	m_ignoredStreams(),
	m_synchronized(),
	m_timer(timer)
	{
		CHECK(sourceFile.size(), "Demuxer::Demuxer() - invalid argument: sourceFile");

		int err = 0;

		// Load all the decoders
		loadFFmpeg();

		// Open the movie file
		err = avformat_open_input(&m_avFormatCtx, sourceFile.c_str(), NULL, NULL);
		CHECK0(err, "Demuxer::Demuxer() - error while opening media: " + sourceFile);
		CHECK(m_avFormatCtx, "Demuxer() - inconsistency: media context cannot be null");

		// Read the general movie informations
		err = avformat_find_stream_info(m_avFormatCtx, NULL);
		CHECK0(err, "Demuxer::Demuxer() - error while retreiving media information");

		// Find all interesting streams
		for (int i = 0; i < m_avFormatCtx->nb_streams; i++) {
			AVStreamRef ffstream = m_avFormatCtx->streams[i];

			try {
				switch (ffstream->codec->codec_type) {
//					case AVMEDIA_TYPE_VIDEO:
//						m_streams[ffstream->index] = new VideoStream(ffstream, *this, timer);
//						sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " video stream");
//						break;

					case AVMEDIA_TYPE_AUDIO:
						m_streams[ffstream->index] = new AudioStream(ffstream, *this, timer);
						sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " audio stream");
						break;

						/** TODO
						 case AVMEDIA_TYPE_SUBTITLE:
						 m_streams.push_back(new SubtitleStream(ffstream));
						 break;
						 */

					default:
						m_ignoredStreams[ffstream->index] = std::string(std::string(av_get_media_type_string(ffstream->codec->codec_type)) + "/" + avcodec_get_name(ffstream->codec->codec_id));
						sfeLogWarning(m_ignoredStreams[ffstream->index] + "' stream ignored");
						break;
				}
			} catch (std::runtime_error& e) {
				std::cerr << "Demuxer::Demuxer() - " << e.what() << std::endl;
			}
		}
	}

	Demuxer::~Demuxer(void)
	{
		if (m_timer.getStatus() != Timer::Stopped)
			m_timer.stop();

		while (m_streams.size()) {
			delete m_streams.begin()->second;
			m_streams.erase(m_streams.begin());
		}

		if (m_avFormatCtx) {
			avformat_close_input(&m_avFormatCtx);
		}
	}

	const std::map<int, Stream*>& Demuxer::getStreams(void) const
	{
		return m_streams;
	}

	std::set<Stream*> Demuxer::getStreamsOfType(MediaType type) const
	{
		std::set<Stream*> streamSet;

		std::map<int, Stream*>::const_iterator it;

		for (it = m_streams.begin(); it != m_streams.end(); it++) {
			if (it->second->getStreamKind() == type)
				streamSet.insert(it->second);
		}

		return streamSet;
	}

	void Demuxer::feedStream(Stream& stream)
	{
		sf::Lock l(m_synchronized);

//		sfeLogDebug(Threads::currentThreadName());

		while (!didReachEndOfFile() && stream.needsMoreData()) {
			AVPacketRef pkt = readPacket();

			if (!pkt) {
				m_eofReached = true;
			} else {
				if (!distributePacket(pkt)) {
					sfeLogWarning(m_ignoredStreams[pkt->stream_index] + " packet not handled and dropped");
					av_free_packet(pkt);
					av_free(pkt);
				}
			}
		}
	}

	void Demuxer::updateVideoStreams(void)
	{
		std::set<Stream*> streams = getStreamsOfType(MEDIA_TYPE_VIDEO);
		std::set<Stream*>::iterator it;

		for (it = streams.begin();it != streams.end(); it++) {
			VideoStream* vStream = dynamic_cast<VideoStream*>(*it);
			CHECK(vStream, "Demuxer::updateVideoStreams() - got non video streams");

			vStream->updateTexture();
		}
	}

	bool Demuxer::didReachEndOfFile(void) const
	{
		return m_eofReached;
	}

	AVPacketRef Demuxer::readPacket(void)
	{
		sf::Lock l(m_synchronized);
//		sfeLogDebug(Threads::currentThreadName());

		AVPacket *pkt = NULL;
		int err = 0;

		pkt = (AVPacket *)av_malloc(sizeof(*pkt));
		CHECK(pkt, "Demuxer::readPacket() - out of memory");
		av_init_packet(pkt);

		err = av_read_frame(m_avFormatCtx, pkt);

		if (err < 0) {
			av_free_packet(pkt);
			av_free(pkt);
			pkt = NULL;
		}

		return pkt;
	}

	bool Demuxer::distributePacket(AVPacketRef packet)
	{
		sf::Lock l(m_synchronized);
		CHECK(packet, "Demuxer::distributePacket() - invalid argument");
//		sfeLogDebug(Threads::currentThreadName());

		bool result = false;
		std::map<int, Stream*>::iterator it = m_streams.find(packet->stream_index);

		if (it != m_streams.end()) {
			it->second->pushEncodedData(packet);
			result = true;
		}

		return result;
	}

	void Demuxer::requestMoreData(Stream& starvingStream)
	{
		sf::Lock l(m_synchronized);
//		sfeLogDebug(Threads::currentThreadName());

		feedStream(starvingStream);
	}
}
<|endoftext|>


<commit_before>// DibView.cpp : implementation file
//

#include "stdafx.h"
#include "DibView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDibView

CDibView::CDibView()
	: m_pDoc(NULL),
		m_pDib(NULL),
		m_pTransform(NULL),
		m_pInverseTransform(NULL),
		m_nDataSet(-1),
		m_nDraggingLandmark(-1),
		m_bDrawMarks(TRUE)
{
}

CDibView::~CDibView()
{
}

// sets the document that is being displayed by this CDibView
void CDibView::SetDocument(CDocument *pDoc)
{
	m_pDoc = pDoc;
}

// sets the DIB to be displayed
void CDibView::SetDib(CDib *pDib)
{
	m_pDib = pDib;
}

// sets the transform to be managed
void CDibView::SetTransform(CTPSTransform *pForwardTransform, CTPSTransform *pInverseTransform, int nDataSet)
{
	m_pTransform = pForwardTransform;
	m_pInverseTransform = pInverseTransform;
	m_nDataSet = nDataSet;
}

BEGIN_MESSAGE_MAP(CDibView, CWnd)
	//{{AFX_MSG_MAP(CDibView)
	ON_WM_PAINT()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDibView message handlers

static COLORREF g_arrColors[] =
{
	RGB(255, 128, 255),
	RGB(255,   0, 255),
	RGB(255, 255,   0),
	RGB(  0, 255, 255),
	RGB(255,   0,   0),
	RGB(  0, 255,   0),
	RGB(  0,   0, 255),
	RGB(128, 255, 128),
};

void CDibView::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	if (m_pDib)
	{
		CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);
		CRect rectDst = GetDstRect();

		// draw the image
		m_pDib->Draw(dc, &rectDst, &rectSrc,
		    FALSE, /*bUseDrawDib*/
			NULL,
			FALSE /*bForeground*/
			);

		// draw the landmarks
		if (m_nDataSet >= 0 && m_bDrawMarks)
		{
			CBrush *pOldBrush = (CBrush *) dc.SelectStockObject(HOLLOW_BRUSH);

			for (int nAt = 0; nAt < m_pTransform->GetLandmarkCount(); nAt++)
			{
				int nColorCount = sizeof(g_arrColors) / sizeof(COLORREF);
				CPen pen(PS_SOLID, 1, g_arrColors[nAt % nColorCount]);
				CPen *pOldPen = (CPen *) dc.SelectObject(&pen);

				CPoint pt;
				switch (m_nDataSet)
				{
				case 0:
					pt = Image2Client(m_pTransform->GetLandmark<0>(nAt));
					break;
				case 1:
					pt = Image2Client(m_pTransform->GetLandmark<1>(nAt));
					break;
				default:
					throw invalid_argument("data set must be 0 or 1");
				}

				// dc.Ellipse(pt.x - 5, pt.y - 5, pt.x + 6, pt.y + 6);

				dc.MoveTo(pt.x - 5, pt.y);
				dc.LineTo(pt.x + 6, pt.y);

				dc.MoveTo(pt.x, pt.y - 5);
				dc.LineTo(pt.x, pt.y + 6);

				dc.SelectObject(pOldPen);
			}

			dc.SelectObject(pOldBrush);
		}
	}

	// Do not call CWnd::OnPaint() for painting messages
}

void CDibView::OnLButtonDown(UINT nFlags, CPoint point)
{
	if (NULL != m_pTransform)
	{
		// find the landmark that we are dragging
		for (int nAt = 0; nAt < m_pTransform->GetLandmarkCount(); nAt++)
		{
			CPoint ptLandmark;
			switch (m_nDataSet)
			{
			case 0:
				ptLandmark = Image2Client(m_pTransform->GetLandmark<0>(nAt));
				break;
			case 1:
				ptLandmark = Image2Client(m_pTransform->GetLandmark<1>(nAt));
				break;
			default:
				throw invalid_argument("data set must be 0 or 1");
			}

			CSize size = point - ptLandmark;

			if (-5 < size.cx && size.cx < 5
				&& -5 < size.cy && size.cy < 5)
			{
				m_nDraggingLandmark = nAt;
			}
		}

		// create a new point
		if (-1 == m_nDraggingLandmark)
		{
			int nOldSize = m_pTransform->GetLandmarkCount();
			m_nDraggingLandmark = m_pTransform->AddLandmark(Client2Image(point));
			int nNewSize = m_pTransform->GetLandmarkCount();
			ASSERT(nOldSize+1 == nNewSize);

			// add the inverse landmark
			int inverseLandmark = m_pInverseTransform->AddLandmark(Client2Image(point));

			// check that the inverse landmark is at the same position
			ASSERT(m_nDraggingLandmark == inverseLandmark);

			// redraw the segment the warping
			Invalidate(FALSE);
		}

		// store the mouse point
		m_ptPrev = point;
	}

	CWnd::OnLButtonDown(nFlags, point);
}

void CDibView::OnMouseMove(UINT nFlags, CPoint point)
{
	if (-1 != m_nDraggingLandmark)
	{
		Point_t forwardl0, forwardl1;
		std:tie(forwardl0, forwardl1) = m_pTransform->GetLandmarkTuple(m_nDraggingLandmark);
		Point_t reversel0, reversel1;
		std:tie(reversel0, reversel1) = m_pInverseTransform->GetLandmarkTuple(m_nDraggingLandmark);
		switch (m_nDataSet)
		{
		case 0:
			bg::add_point(reversel0, Client2Image(point).point());
			bg::subtract_point(reversel0, Client2Image(m_ptPrev));

			bg::add_point(forwardl1, Client2Image(point).point());
			bg::subtract_point(forwardl1, Client2Image(m_ptPrev).point());
			break;
		case 1:
			bg::add_point(forwardl0, Client2Image(point).point());
			bg::subtract_point(forwardl0, Client2Image(m_ptPrev));

			bg::add_point(reversel1, Client2Image(point).point());
			bg::subtract_point(reversel1, Client2Image(m_ptPrev).point());
			break;
		default:
			throw new invalid_argument("dataset must be 0 or 1");
		}
		m_pTransform->SetLandmarkTuple(m_nDraggingLandmark, std::make_tuple(forwardl0, forwardl1));
		m_pInverseTransform->SetLandmarkTuple(m_nDraggingLandmark, std::make_tuple(reversel0, reversel1));

		Invalidate(FALSE);

		// store the mouse point
		m_ptPrev = point;
	}

	CWnd::OnMouseMove(nFlags, point);
}

BOOL CheckInverse(CTPSTransform* pForward, CTPSTransform* pInverse)
{
	// now check to ensure the offsets at each landmark is correct
	for (int nAtLandmark = 0; nAtLandmark < pForward->GetLandmarkCount(); nAtLandmark++)
	{
		const CVectorD<3>& vL0 = pForward->GetLandmark<0>(nAtLandmark);
		const CVectorD<3>& vL0_other = pInverse->GetLandmark<1>(nAtLandmark);
		if (!vL0.IsApproxEqual(vL0_other))
			return FALSE;

		const CVectorD<3>& vL1 = pForward->GetLandmark<1>(nAtLandmark);
		const CVectorD<3>& vL1_other = pInverse->GetLandmark<0>(nAtLandmark);
		if (!vL1.IsApproxEqual(vL1_other))
			return FALSE;
	}

	return TRUE;
}

void CDibView::OnLButtonUp(UINT nFlags, CPoint point)
{
	m_nDraggingLandmark = -1;

	// Check if both inverse and forward are consistent
	ASSERT(CheckInverse(m_pTransform, m_pInverseTransform));
	ASSERT(CheckInverse(m_pInverseTransform, m_pTransform));

	if (m_pDoc)
	{
		m_pDoc->UpdateAllViews(NULL);
	}

	CWnd::OnLButtonUp(nFlags, point);
}

CVectorD<3> CDibView::Client2Image(const CPoint &ptClient)
{
	// source (DIB) image size
	CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);

	// destination (window) image size
	CRect rectDst = GetDstRect();

	// ratio of source / destination heights
	REAL ratio = (REAL) rectSrc.Height() / (REAL) rectDst.Height();

	// offset to center and scale
	CVectorD<3> vImage(ptClient);
	vImage -= CVectorD<3>(rectDst.CenterPoint());
	vImage[0] *= ratio;
	vImage[1] *= ratio;
	vImage[2] *= ratio;
	vImage += CVectorD<3>(rectSrc.CenterPoint());

	return vImage;
}

CPoint CDibView::Image2Client(const CVectorD<3>&vImage)
{
	// source (DIB) image size
	CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);

	// destination (window) image size
	CRect rectDst = GetDstRect();

	// ratio of destination / source heights
	REAL ratio = (REAL) rectDst.Height() / (REAL) rectSrc.Height();

	// offset to center and scale
	CPoint ptClient(vImage - CVectorD<3>(rectSrc.CenterPoint()));
	ptClient.x = (int)(ratio * (REAL) ptClient.x);
	ptClient.y = (int)(ratio * (REAL) ptClient.y);
	ptClient += rectDst.CenterPoint();

	return ptClient;
}

CRect CDibView::GetDstRect()
{
	CRect rectDst;
	GetClientRect(&rectDst);

	CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);

	// set the client rectangle to the same aspect ratio
	int nClientWidth = rectDst.Height() * rectSrc.Width()
		/ rectSrc.Height();
	CPoint ptCenter = rectDst.CenterPoint();
	rectDst.left = ptCenter.x - nClientWidth / 2;
	rectDst.right = ptCenter.x + nClientWidth / 2;

	return rectDst;
}
<commit_msg>switch dib to bg::point from cvectord<commit_after>// DibView.cpp : implementation file
//

#include "stdafx.h"
#include "DibView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDibView

CDibView::CDibView()
	: m_pDoc(NULL),
		m_pDib(NULL),
		m_pTransform(NULL),
		m_pInverseTransform(NULL),
		m_nDataSet(-1),
		m_nDraggingLandmark(-1),
		m_bDrawMarks(TRUE)
{
}

CDibView::~CDibView()
{
}

// sets the document that is being displayed by this CDibView
void CDibView::SetDocument(CDocument *pDoc)
{
	m_pDoc = pDoc;
}

// sets the DIB to be displayed
void CDibView::SetDib(CDib *pDib)
{
	m_pDib = pDib;
}

// sets the transform to be managed
void CDibView::SetTransform(CTPSTransform *pForwardTransform, CTPSTransform *pInverseTransform, int nDataSet)
{
	m_pTransform = pForwardTransform;
	m_pInverseTransform = pInverseTransform;
	m_nDataSet = nDataSet;
}

BEGIN_MESSAGE_MAP(CDibView, CWnd)
	//{{AFX_MSG_MAP(CDibView)
	ON_WM_PAINT()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDibView message handlers

static COLORREF g_arrColors[] =
{
	RGB(255, 128, 255),
	RGB(255,   0, 255),
	RGB(255, 255,   0),
	RGB(  0, 255, 255),
	RGB(255,   0,   0),
	RGB(  0, 255,   0),
	RGB(  0,   0, 255),
	RGB(128, 255, 128),
};

void CDibView::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	if (m_pDib)
	{
		CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);
		CRect rectDst = GetDstRect();

		// draw the image
		m_pDib->Draw(dc, &rectDst, &rectSrc,
		    FALSE, /*bUseDrawDib*/
			NULL,
			FALSE /*bForeground*/
			);

		// draw the landmarks
		if (m_nDataSet >= 0 && m_bDrawMarks)
		{
			CBrush *pOldBrush = (CBrush *) dc.SelectStockObject(HOLLOW_BRUSH);

			for (int nAt = 0; nAt < m_pTransform->GetLandmarkCount(); nAt++)
			{
				int nColorCount = sizeof(g_arrColors) / sizeof(COLORREF);
				CPen pen(PS_SOLID, 1, g_arrColors[nAt % nColorCount]);
				CPen *pOldPen = (CPen *) dc.SelectObject(&pen);

				CPoint pt;
				switch (m_nDataSet)
				{
				case 0:
					pt = Image2Client(m_pTransform->GetLandmark<0>(nAt));
					break;
				case 1:
					pt = Image2Client(m_pTransform->GetLandmark<1>(nAt));
					break;
				default:
					throw invalid_argument("data set must be 0 or 1");
				}

				// dc.Ellipse(pt.x - 5, pt.y - 5, pt.x + 6, pt.y + 6);

				dc.MoveTo(pt.x - 5, pt.y);
				dc.LineTo(pt.x + 6, pt.y);

				dc.MoveTo(pt.x, pt.y - 5);
				dc.LineTo(pt.x, pt.y + 6);

				dc.SelectObject(pOldPen);
			}

			dc.SelectObject(pOldBrush);
		}
	}

	// Do not call CWnd::OnPaint() for painting messages
}

void CDibView::OnLButtonDown(UINT nFlags, CPoint point)
{
	if (NULL != m_pTransform)
	{
		// find the landmark that we are dragging
		for (int nAt = 0; nAt < m_pTransform->GetLandmarkCount(); nAt++)
		{
			CPoint ptLandmark;
			switch (m_nDataSet)
			{
			case 0:
				ptLandmark = Image2Client(m_pTransform->GetLandmark<0>(nAt));
				break;
			case 1:
				ptLandmark = Image2Client(m_pTransform->GetLandmark<1>(nAt));
				break;
			default:
				throw invalid_argument("data set must be 0 or 1");
			}

			CSize size = point - ptLandmark;

			if (-5 < size.cx && size.cx < 5
				&& -5 < size.cy && size.cy < 5)
			{
				m_nDraggingLandmark = nAt;
			}
		}

		// create a new point
		if (-1 == m_nDraggingLandmark)
		{
			int nOldSize = m_pTransform->GetLandmarkCount();
			m_nDraggingLandmark = m_pTransform->AddLandmark(Client2Image(point));
			int nNewSize = m_pTransform->GetLandmarkCount();
			ASSERT(nOldSize+1 == nNewSize);

			// add the inverse landmark
			int inverseLandmark = m_pInverseTransform->AddLandmark(Client2Image(point));

			// check that the inverse landmark is at the same position
			ASSERT(m_nDraggingLandmark == inverseLandmark);

			// redraw the segment the warping
			Invalidate(FALSE);
		}

		// store the mouse point
		m_ptPrev = point;
	}

	CWnd::OnLButtonDown(nFlags, point);
}

void CDibView::OnMouseMove(UINT nFlags, CPoint point)
{
	if (-1 != m_nDraggingLandmark)
	{
		Point_t forwardl0, forwardl1;
		std::tie(forwardl0, forwardl1) = m_pTransform->GetLandmarkTuple(m_nDraggingLandmark);
		Point_t reversel0, reversel1;
		std::tie(reversel0, reversel1) = m_pInverseTransform->GetLandmarkTuple(m_nDraggingLandmark);
		switch (m_nDataSet)
		{
		case 0:
			bg::add_point(reversel0, Client2Image(point).point());
			bg::subtract_point(reversel0, Client2Image(m_ptPrev));

			bg::add_point(forwardl1, Client2Image(point).point());
			bg::subtract_point(forwardl1, Client2Image(m_ptPrev).point());
			break;
		case 1:
			bg::add_point(forwardl0, Client2Image(point).point());
			bg::subtract_point(forwardl0, Client2Image(m_ptPrev));

			bg::add_point(reversel1, Client2Image(point).point());
			bg::subtract_point(reversel1, Client2Image(m_ptPrev).point());
			break;
		default:
			throw new invalid_argument("dataset must be 0 or 1");
		}
		m_pTransform->SetLandmarkTuple(m_nDraggingLandmark, std::make_tuple(forwardl0, forwardl1));
		m_pInverseTransform->SetLandmarkTuple(m_nDraggingLandmark, std::make_tuple(reversel0, reversel1));

		Invalidate(FALSE);

		// store the mouse point
		m_ptPrev = point;
	}

	CWnd::OnMouseMove(nFlags, point);
}

BOOL CheckInverse(CTPSTransform* pForward, CTPSTransform* pInverse)
{
	// now check to ensure the offsets at each landmark is correct
	for (int nAtLandmark = 0; nAtLandmark < pForward->GetLandmarkCount(); nAtLandmark++)
	{
		const CVectorD<3>& vL0 = pForward->GetLandmark<0>(nAtLandmark);
		const CVectorD<3>& vL0_other = pInverse->GetLandmark<1>(nAtLandmark);
		if (!vL0.IsApproxEqual(vL0_other))
			return FALSE;

		const CVectorD<3>& vL1 = pForward->GetLandmark<1>(nAtLandmark);
		const CVectorD<3>& vL1_other = pInverse->GetLandmark<0>(nAtLandmark);
		if (!vL1.IsApproxEqual(vL1_other))
			return FALSE;
	}

	return TRUE;
}

void CDibView::OnLButtonUp(UINT nFlags, CPoint point)
{
	m_nDraggingLandmark = -1;

	// Check if both inverse and forward are consistent
	ASSERT(CheckInverse(m_pTransform, m_pInverseTransform));
	ASSERT(CheckInverse(m_pInverseTransform, m_pTransform));

	if (m_pDoc)
	{
		m_pDoc->UpdateAllViews(NULL);
	}

	CWnd::OnLButtonUp(nFlags, point);
}

CVectorD<3> CDibView::Client2Image(const CPoint &ptClient)
{
	// source (DIB) image size
	CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);

	// destination (window) image size
	CRect rectDst = GetDstRect();

	// ratio of source / destination heights
	REAL ratio = (REAL) rectSrc.Height() / (REAL) rectDst.Height();

	// offset to center and scale
	CVectorD<3> vImage(ptClient);
	vImage -= CVectorD<3>(rectDst.CenterPoint());
	vImage[0] *= ratio;
	vImage[1] *= ratio;
	vImage[2] *= ratio;
	vImage += CVectorD<3>(rectSrc.CenterPoint());

	return vImage;
}

CPoint CDibView::Image2Client(const CVectorD<3>&vImage)
{
	// source (DIB) image size
	CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);

	// destination (window) image size
	CRect rectDst = GetDstRect();

	// ratio of destination / source heights
	REAL ratio = (REAL) rectDst.Height() / (REAL) rectSrc.Height();

	// offset to center and scale
	CPoint ptClient(vImage - CVectorD<3>(rectSrc.CenterPoint()));
	ptClient.x = (int)(ratio * (REAL) ptClient.x);
	ptClient.y = (int)(ratio * (REAL) ptClient.y);
	ptClient += rectDst.CenterPoint();

	return ptClient;
}

CRect CDibView::GetDstRect()
{
	CRect rectDst;
	GetClientRect(&rectDst);

	CRect rectSrc(0, 0, m_pDib->GetSize().cx, m_pDib->GetSize().cy);

	// set the client rectangle to the same aspect ratio
	int nClientWidth = rectDst.Height() * rectSrc.Width()
		/ rectSrc.Height();
	CPoint ptCenter = rectDst.CenterPoint();
	rectDst.left = ptCenter.x - nClientWidth / 2;
	rectDst.right = ptCenter.x + nClientWidth / 2;

	return rectDst;
}
<|endoftext|>


<commit_before>///
/// @file   EratBig.cpp
/// @brief  EratBig is a segmented sieve of Eratosthenes
///         implementation optimized for big sieving primes. EratBig
///         is a highly optimized implementation of Tomas Oliveira e
///         Silva's cache-friendly bucket sieve algorithm:
///         http://www.ieeta.pt/~tos/software/prime_sieve.html
///         The idea is that for each segment we keep a list of buckets
///         which contain the sieving primes that have a multiple
///         occurrence in that segment. When we then cross off the
///         multiples from the current segment we avoid processing
///         sieving primes that do not have a multiple occurrence in
///         the current segment.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/EratBig.hpp>
#include <primesieve/Bucket.hpp>
#include <primesieve/MemoryPool.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve/primesieve_error.hpp>
#include <primesieve/Wheel.hpp>

#include <stdint.h>
#include <cassert>
#include <algorithm>
#include <vector>

namespace primesieve {

/// @stop:      Upper bound for sieving
/// @sieveSize: Sieve size in bytes
/// @maxPrime:  Sieving primes <= maxPrime
///
void EratBig::init(uint64_t stop, uint64_t sieveSize, uint64_t maxPrime)
{
  // '>> log2SieveSize' requires power of 2 sieveSize
  if (!isPow2(sieveSize))
    throw primesieve_error("EratBig: sieveSize is not a power of 2");

  Wheel::init(stop, sieveSize);

  enabled_ = true;
  maxPrime_ = maxPrime;
  log2SieveSize_ = ilog2(sieveSize);
  moduloSieveSize_ = sieveSize - 1;

  uint64_t maxSievingPrime = maxPrime_ / 30;
  uint64_t maxNextMultiple = maxSievingPrime * getMaxFactor() + getMaxFactor();
  uint64_t maxMultipleIndex = sieveSize - 1 + maxNextMultiple;
  uint64_t maxSegmentCount = maxMultipleIndex >> log2SieveSize_;
  uint64_t size = maxSegmentCount + 1;

  sievingPrimes_.resize(size, nullptr);
}

/// Add a new sieving prime
void EratBig::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex)
{
  assert(prime <= maxPrime_);
  uint64_t sievingPrime = prime / 30;
  uint64_t segment = multipleIndex >> log2SieveSize_;
  multipleIndex &= moduloSieveSize_;

  if (memoryPool_.isFullBucket(sievingPrimes_[segment]))
    memoryPool_.addBucket(sievingPrimes_[segment]);

  sievingPrimes_[segment]++->set(sievingPrime, multipleIndex, wheelIndex);
}

/// Iterate over the buckets related to the current segment
/// and for each bucket execute crossOff() to remove
/// the multiples of its sieving primes.
///
void EratBig::crossOff(uint8_t* sieve)
{
  while (sievingPrimes_[0])
  {
    Bucket* bucket = memoryPool_.getBucket(sievingPrimes_[0]);
    bucket->setEnd(sievingPrimes_[0]);
    sievingPrimes_[0] = nullptr;

    while (bucket)
    {
      crossOff(sieve, bucket);
      Bucket* processed = bucket;
      bucket = bucket->next();
      memoryPool_.freeBucket(processed);
    }
  }

  // Move the sieving primes related to the next segment to
  // the 1st position so that they will be used when
  // sieving the next segment.
  std::rotate(sievingPrimes_.begin(),
              sievingPrimes_.begin() + 1,
              sievingPrimes_.end());
}

/// Segmented sieve of Eratosthenes with wheel factorization
/// optimized for big sieving primes that have very few
/// multiples per segment. Cross-off the next multiple of
/// each sieving prime in the current bucket.
///
void EratBig::crossOff(uint8_t* sieve, Bucket* bucket)
{
  SievingPrime* prime = bucket->begin();
  SievingPrime* end = bucket->end();
  SievingPrime** sievingPrimes = &sievingPrimes_[0];
  uint64_t moduloSieveSize = moduloSieveSize_;
  uint64_t log2SieveSize = log2SieveSize_;

  // Process 2 sieving primes per loop iteration to
  // increase instruction level parallelism.
  for (; prime <= end - 2; prime += 2)
  {
    uint64_t multipleIndex0 = prime[0].getMultipleIndex();
    uint64_t wheelIndex0    = prime[0].getWheelIndex();
    uint64_t sievingPrime0  = prime[0].getSievingPrime();
    uint64_t multipleIndex1 = prime[1].getMultipleIndex();
    uint64_t wheelIndex1    = prime[1].getWheelIndex();
    uint64_t sievingPrime1  = prime[1].getSievingPrime();

    // Cross-off the current multiple (unset bit)
    // and calculate the next multiple.
    unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0);
    unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1);
    uint64_t segment0 = multipleIndex0 >> log2SieveSize;
    uint64_t segment1 = multipleIndex1 >> log2SieveSize;
    multipleIndex0 &= moduloSieveSize;
    multipleIndex1 &= moduloSieveSize;

    if (memoryPool_.isFullBucket(sievingPrimes[segment0]))
      memoryPool_.addBucket(sievingPrimes[segment0]);

    // The next multiple of the sieving prime will
    // occur in segment0. Hence we move the
    // sieving prime to the list which corresponds
    // to that segment.
    sievingPrimes[segment0]++->set(sievingPrime0, multipleIndex0, wheelIndex0);

    if (memoryPool_.isFullBucket(sievingPrimes[segment1]))
      memoryPool_.addBucket(sievingPrimes[segment1]);

    sievingPrimes[segment1]++->set(sievingPrime1, multipleIndex1, wheelIndex1);
  }

  if (prime != end)
  {
    uint64_t multipleIndex = prime->getMultipleIndex();
    uint64_t wheelIndex    = prime->getWheelIndex();
    uint64_t sievingPrime  = prime->getSievingPrime();

    unsetBit(sieve, sievingPrime, &multipleIndex, &wheelIndex);
    uint64_t segment = multipleIndex >> log2SieveSize;
    multipleIndex &= moduloSieveSize;

    if (memoryPool_.isFullBucket(sievingPrimes[segment]))
      memoryPool_.addBucket(sievingPrimes[segment]);

    sievingPrimes[segment]++->set(sievingPrime, multipleIndex, wheelIndex);
  }
}

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file   EratBig.cpp
/// @brief  EratBig is a segmented sieve of Eratosthenes
///         implementation optimized for big sieving primes. EratBig
///         is a highly optimized implementation of Tomas Oliveira e
///         Silva's cache-friendly bucket sieve algorithm:
///         http://www.ieeta.pt/~tos/software/prime_sieve.html
///         The idea is that for each segment we keep a list of buckets
///         which contain the sieving primes that have a multiple
///         occurrence in that segment. When we then cross off the
///         multiples from the current segment we avoid processing
///         sieving primes that do not have a multiple occurrence in
///         the current segment.
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/EratBig.hpp>
#include <primesieve/Bucket.hpp>
#include <primesieve/MemoryPool.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve/primesieve_error.hpp>
#include <primesieve/Wheel.hpp>

#include <stdint.h>
#include <cassert>
#include <algorithm>
#include <vector>

namespace primesieve {

/// @stop:      Upper bound for sieving
/// @sieveSize: Sieve size in bytes
/// @maxPrime:  Sieving primes <= maxPrime
///
void EratBig::init(uint64_t stop, uint64_t sieveSize, uint64_t maxPrime)
{
  // '>> log2SieveSize' requires power of 2 sieveSize
  if (!isPow2(sieveSize))
    throw primesieve_error("EratBig: sieveSize is not a power of 2");

  Wheel::init(stop, sieveSize);

  enabled_ = true;
  maxPrime_ = maxPrime;
  log2SieveSize_ = ilog2(sieveSize);
  moduloSieveSize_ = sieveSize - 1;

  uint64_t maxSievingPrime = maxPrime_ / 30;
  uint64_t maxNextMultiple = maxSievingPrime * getMaxFactor() + getMaxFactor();
  uint64_t maxMultipleIndex = sieveSize - 1 + maxNextMultiple;
  uint64_t maxSegmentCount = maxMultipleIndex >> log2SieveSize_;
  uint64_t size = maxSegmentCount + 1;

  sievingPrimes_.resize(size);
}

/// Add a new sieving prime
void EratBig::storeSievingPrime(uint64_t prime, uint64_t multipleIndex, uint64_t wheelIndex)
{
  assert(prime <= maxPrime_);
  uint64_t sievingPrime = prime / 30;
  uint64_t segment = multipleIndex >> log2SieveSize_;
  multipleIndex &= moduloSieveSize_;

  if (memoryPool_.isFullBucket(sievingPrimes_[segment]))
    memoryPool_.addBucket(sievingPrimes_[segment]);

  sievingPrimes_[segment]++->set(sievingPrime, multipleIndex, wheelIndex);
}

/// Iterate over the buckets related to the current segment
/// and for each bucket execute crossOff() to remove
/// the multiples of its sieving primes.
///
void EratBig::crossOff(uint8_t* sieve)
{
  while (sievingPrimes_[0])
  {
    Bucket* bucket = memoryPool_.getBucket(sievingPrimes_[0]);
    bucket->setEnd(sievingPrimes_[0]);
    sievingPrimes_[0] = nullptr;

    while (bucket)
    {
      crossOff(sieve, bucket);
      Bucket* processed = bucket;
      bucket = bucket->next();
      memoryPool_.freeBucket(processed);
    }
  }

  // Move the sieving primes related to the next segment to
  // the 1st position so that they will be used when
  // sieving the next segment.
  std::rotate(sievingPrimes_.begin(),
              sievingPrimes_.begin() + 1,
              sievingPrimes_.end());
}

/// Segmented sieve of Eratosthenes with wheel factorization
/// optimized for big sieving primes that have very few
/// multiples per segment. Cross-off the next multiple of
/// each sieving prime in the current bucket.
///
void EratBig::crossOff(uint8_t* sieve, Bucket* bucket)
{
  SievingPrime* prime = bucket->begin();
  SievingPrime* end = bucket->end();
  SievingPrime** sievingPrimes = &sievingPrimes_[0];
  uint64_t moduloSieveSize = moduloSieveSize_;
  uint64_t log2SieveSize = log2SieveSize_;

  // Process 2 sieving primes per loop iteration to
  // increase instruction level parallelism.
  for (; prime <= end - 2; prime += 2)
  {
    uint64_t multipleIndex0 = prime[0].getMultipleIndex();
    uint64_t wheelIndex0    = prime[0].getWheelIndex();
    uint64_t sievingPrime0  = prime[0].getSievingPrime();
    uint64_t multipleIndex1 = prime[1].getMultipleIndex();
    uint64_t wheelIndex1    = prime[1].getWheelIndex();
    uint64_t sievingPrime1  = prime[1].getSievingPrime();

    // Cross-off the current multiple (unset bit)
    // and calculate the next multiple.
    unsetBit(sieve, sievingPrime0, &multipleIndex0, &wheelIndex0);
    unsetBit(sieve, sievingPrime1, &multipleIndex1, &wheelIndex1);
    uint64_t segment0 = multipleIndex0 >> log2SieveSize;
    uint64_t segment1 = multipleIndex1 >> log2SieveSize;
    multipleIndex0 &= moduloSieveSize;
    multipleIndex1 &= moduloSieveSize;

    if (memoryPool_.isFullBucket(sievingPrimes[segment0]))
      memoryPool_.addBucket(sievingPrimes[segment0]);

    // The next multiple of the sieving prime will
    // occur in segment0. Hence we move the
    // sieving prime to the list which corresponds
    // to that segment.
    sievingPrimes[segment0]++->set(sievingPrime0, multipleIndex0, wheelIndex0);

    if (memoryPool_.isFullBucket(sievingPrimes[segment1]))
      memoryPool_.addBucket(sievingPrimes[segment1]);

    sievingPrimes[segment1]++->set(sievingPrime1, multipleIndex1, wheelIndex1);
  }

  if (prime != end)
  {
    uint64_t multipleIndex = prime->getMultipleIndex();
    uint64_t wheelIndex    = prime->getWheelIndex();
    uint64_t sievingPrime  = prime->getSievingPrime();

    unsetBit(sieve, sievingPrime, &multipleIndex, &wheelIndex);
    uint64_t segment = multipleIndex >> log2SieveSize;
    multipleIndex &= moduloSieveSize;

    if (memoryPool_.isFullBucket(sievingPrimes[segment]))
      memoryPool_.addBucket(sievingPrimes[segment]);

    sievingPrimes[segment]++->set(sievingPrime, multipleIndex, wheelIndex);
  }
}

} // namespace
<|endoftext|>


<commit_before>// App.hh
// Copyright (c) 2002 Henrik Kinnunen (fluxgen at linuxmail.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef FBTK_APP_HH
#define FBTK_APP_HH

#include <X11/Xlib.h>

namespace FbTk {

///   Main class for applications, every application must create an instance of this class
/**
 * Usage: \n
 * App app; \n
 * ... \n
 * init some other stuff; \n
 * ... \n
 *  main loop starts here: \n
 * app.eventLoop(); \n
 *
 * To end main loop you call App::instance()->end()
 */
class App {
public:
    /// @return singleton instance of App
    static App *instance();
    /// creates a display connection
    explicit App(const char *displayname=0);
    virtual ~App();
    /// display connection
    Display *display() const { return m_display; }
    void sync(bool discard);
    /// starts event loop
    virtual void eventLoop();
    /// forces an end to event loop
    void end();
    bool done() const { return m_done; }
private:
    static App *s_app;
    bool m_done;
    Display *m_display;
};

} // end namespace FbTk

#endif // FBTK_APP_HH
<commit_msg>inline display<commit_after>// App.hh
// Copyright (c) 2002 Henrik Kinnunen (fluxgen at linuxmail.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef FBTK_APP_HH
#define FBTK_APP_HH

#include <X11/Xlib.h>

namespace FbTk {

///   Main class for applications, every application must create an instance of this class
/**
 * Usage: \n
 * App app; \n
 * ... \n
 * init some other stuff; \n
 * ... \n
 *  main loop starts here: \n
 * app.eventLoop(); \n
 *
 * To end main loop you call App::instance()->end()
 */
class App {
public:
    /// @return singleton instance of App
    static App *instance();
    /// creates a display connection
    explicit App(const char *displayname=0);
    virtual ~App();
    /// display connection
    inline Display *display() const { return m_display; }
    void sync(bool discard);
    /// starts event loop
    virtual void eventLoop();
    /// forces an end to event loop
    void end();
    bool done() const { return m_done; }
private:
    static App *s_app;
    bool m_done;
    Display *m_display;
};

} // end namespace FbTk

#endif // FBTK_APP_HH
<|endoftext|>


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

   Flexbar - flexible barcode and adapter removal

   Version 3.5.0

   BSD 3-Clause License

   uses SeqAn library release 2.4.0
   and TBB library 4.0 or later

             Developer:  Johannes Roehr

   Former contributors:  Matthias Dodt
                         Benjamin Menkuec
                         Sebastian Roskosch

   https://github.com/seqan/flexbar

===================================================*/

#include "Flexbar.h"

int main(int argc, const char* argv[]){

	using namespace std;
	using namespace seqan;

	const string version = "3.5 beta";
	const string date    = "October 2018";

	ArgumentParser parser("flexbar");

	defineOptions(parser, version, date);
	parseCmdLine(parser, version, argc, argv);

	Options o;

	initOptions(o, parser);
	loadOptions(o, parser);

	startComputation(o);

	return 0;
}
<commit_msg>Update date<commit_after>/*==================================================

   Flexbar - flexible barcode and adapter removal

   Version 3.5.0

   BSD 3-Clause License

   uses SeqAn library release 2.4.0
   and TBB library 4.0 or later

             Developer:  Johannes Roehr

   Former contributors:  Matthias Dodt
                         Benjamin Menkuec
                         Sebastian Roskosch

   https://github.com/seqan/flexbar

===================================================*/

#include "Flexbar.h"

int main(int argc, const char* argv[]){

	using namespace std;
	using namespace seqan;

	const string version = "3.5 beta";
	const string date    = "November 2018";

	ArgumentParser parser("flexbar");

	defineOptions(parser, version, date);
	parseCmdLine(parser, version, argc, argv);

	Options o;

	initOptions(o, parser);
	loadOptions(o, parser);

	startComputation(o);

	return 0;
}
<|endoftext|>


<commit_before>#include "General.h"

#include "KBot.h"

namespace KBot {

    using namespace BWAPI;

    General::General(KBot &kBot) : m_kBot(kBot) {}

    void General::update() {
        std::string squadSizes;
        for (auto &squad : m_squads)
            squadSizes += ", " + std::to_string(squad.size());
        squadSizes = squadSizes.empty() ? "No squads" : squadSizes.substr(2);

        const auto enemiesNearBase = Broodwar->getUnitsInRadius(Position(Broodwar->self()->getStartLocation()), 1000, Filter::IsEnemy);

        // Display debug information
        Broodwar->drawTextScreen(2, 100, "General: -");
        Broodwar->drawTextScreen(2, 110, "Squad sizes: %s", squadSizes.c_str());
        Broodwar->drawTextScreen(2, 120, "Enemies near base: %d", enemiesNearBase.size());

        // Remove empty squads
        decltype(m_squads)::const_iterator it;
        while ((it = std::find_if(m_squads.begin(), m_squads.end(), [](const Squad &squad) { return squad.empty(); })) != m_squads.end())
            m_squads.erase(it);

        // Merge nearby and defensive squads
        bool merge = true;
        while (merge) {
            for (auto it = m_squads.begin(); it != m_squads.end(); ++it) {
                auto hit = std::find_if(it + 1, m_squads.end(), [it](const Squad &squad) {
                    return (it->getPosition().getApproxDistance(squad.getPosition()) < 200)
                        || (it->getPosition().getApproxDistance(squad.getPosition()) < 500
                            && it->getState() == SquadState::defend && squad.getState() == SquadState::defend);
                });

                if (hit != m_squads.end()) {
                    // Hold all units as some of them might have old, invalid orders.
                    it->stop();
                    hit->stop();
                    // Merge squad *hit into *it.
                    std::copy(hit->begin(), hit->end(), std::inserter(*it, it->end()));
                    // Remove empty squad *hit.
                    m_squads.erase(hit);
                    // This invalidates all container iterators, so we have to start all over again!
                    break;
                }
            }
            // No squads to merge left.
            merge = false;
        }

        // Update squads
        for (auto &squad : m_squads)
            squad.update();
    }

    void General::transferOwnership(const Unit &unit) {
        Broodwar->registerEvent([unit](Game*) {
            Broodwar->drawTextMap(Position(unit->getPosition()), "General: %s", unit->getType().c_str());
        }, [unit](Game*) { return unit->exists(); }, 250);

        for (auto &squad : m_squads) {
            if (unit->getPosition().getApproxDistance(squad.getPosition()) < 400) {
                // Join squad
                squad.insert(unit);
                return;
            }
        }

        // Create new squad
        Squad squad(m_kBot);
        squad.insert(unit);
        m_squads.push_back(squad);
    }

    void General::onUnitDestroy(const Unit &unit) {
        for (auto &squad : m_squads)
            squad.erase(unit);
    }

} // namespace
<commit_msg>Update squads (merge / delete) more rarely.<commit_after>#include "General.h"

#include "KBot.h"

namespace KBot {

    using namespace BWAPI;

    General::General(KBot &kBot) : m_kBot(kBot) {}

    void General::update() {
        std::string squadSizes;
        for (auto &squad : m_squads)
            squadSizes += ", " + std::to_string(squad.size());
        squadSizes = squadSizes.empty() ? "No squads" : squadSizes.substr(2);

        const auto enemiesNearBase = Broodwar->getUnitsInRadius(Position(Broodwar->self()->getStartLocation()), 1000, Filter::IsEnemy);

        // Display debug information
        Broodwar->drawTextScreen(2, 100, "General: -");
        Broodwar->drawTextScreen(2, 110, "Squad sizes: %s", squadSizes.c_str());
        Broodwar->drawTextScreen(2, 120, "Enemies near base: %d", enemiesNearBase.size());

        // Update squads
        for (auto &squad : m_squads)
            squad.update();

        // Prevent spamming by only running our onFrame once every number of latency frames.
        // Latency frames are the number of frames before commands are processed.
        if (Broodwar->getFrameCount() % Broodwar->getLatencyFrames() != 0)
            return;

        // Remove empty squads
        decltype(m_squads)::const_iterator it;
        while ((it = std::find_if(m_squads.begin(), m_squads.end(), [](const Squad &squad) { return squad.empty(); })) != m_squads.end())
            m_squads.erase(it);

        // Merge nearby and defensive squads
        bool merge = true;
        while (merge) {
            for (auto it = m_squads.begin(); it != m_squads.end(); ++it) {
                auto hit = std::find_if(it + 1, m_squads.end(), [it](const Squad &squad) {
                    return (it->getPosition().getApproxDistance(squad.getPosition()) < 200)
                        || (it->getPosition().getApproxDistance(squad.getPosition()) < 500
                            && it->getState() == SquadState::defend && squad.getState() == SquadState::defend);
                });

                if (hit != m_squads.end()) {
                    // Hold all units as some of them might have old, invalid orders.
                    it->stop();
                    hit->stop();
                    // Merge squad *hit into *it.
                    std::copy(hit->begin(), hit->end(), std::inserter(*it, it->end()));
                    // Remove empty squad *hit.
                    m_squads.erase(hit);
                    // This invalidates all container iterators, so we have to start all over again!
                    break;
                }
            }
            // No squads to merge left.
            merge = false;
        }
    }

    void General::transferOwnership(const Unit &unit) {
        Broodwar->registerEvent([unit](Game*) {
            Broodwar->drawTextMap(Position(unit->getPosition()), "General: %s", unit->getType().c_str());
        }, [unit](Game*) { return unit->exists(); }, 250);

        for (auto &squad : m_squads) {
            if (unit->getPosition().getApproxDistance(squad.getPosition()) < 400) {
                // Join squad
                squad.insert(unit);
                return;
            }
        }

        // Create new squad
        Squad squad(m_kBot);
        squad.insert(unit);
        m_squads.push_back(squad);
    }

    void General::onUnitDestroy(const Unit &unit) {
        for (auto &squad : m_squads)
            squad.erase(unit);
    }

} // namespace
<|endoftext|>


<commit_before>/* -----------------------------------------------------------------------

 Infomap software package for multi-level network clustering

   * Copyright (c) 2013. See LICENSE for more info.
   * For credits and origins, see AUTHORS or www.mapequation.org/about.

----------------------------------------------------------------------- */

#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include "utils/Logger.h"
#include "io/Config.h"
#include "infomap/InfomapContext.h"
#include "utils/Stopwatch.h"
#include "io/ProgramInterface.h"
#include "io/convert.h"
#include "utils/FileURI.h"
#include "utils/Date.h"
#include <iomanip>

void runInfomap(Config const& config)
{
	InfomapContext context(config);
	context.getInfomap()->run();
}

Config getConfig(int argc, char *argv[])
{
	Config conf;
	ProgramInterface api("Infomap",
			"Implementation of the Infomap clustering algorithm based on the Map Equation (see www.mapequation.org)",
			"0.9.2");

	// --------------------- Input options ---------------------
	api.addNonOptionArgument(conf.networkFile, "network_file",
			"The file containing the network data. Accepted formats: Pajek (implied by .net) and link list (.txt)");

	api.addOptionArgument(conf.inputFormat, 'i', "input-format",
			"Specify input format ('pajek' or 'link-list') to override format possibly implied by file extension.", "s");

	api.addOptionArgument(conf.zeroBasedNodeNumbers, 'z', "zero-based-numbering",
			"Assume node numbers start from zero in the input file instead of one.");

	api.addOptionArgument(conf.includeSelfLinks, 'k', "include-self-links",
			"Include links with the same source and target node. (Ignored by default.)");

	api.addOptionArgument(conf.nodeLimit, 'S', "node-limit",
			"Limit the number of nodes to read from the network. Ignore links connected to ignored nodes.", "n");

	api.addOptionArgument(conf.clusterDataFile, 'c', "cluster-data",
			"Provide an initial two-level solution (.clu format).", "p");

	// --------------------- Output options ---------------------
//	api.addOptionArgument(conf.printNodeRanks, 'p', "print-node-ranks",
//			"Print the calculated flow for each node to a file.");
//
//	api.addOptionArgument(conf.printFlowNetwork, 'W', "print-flow-network",
//			"Print the network with calculated flow values.");
	//TODO: Add map container so that printing can be added like -Pranks -Pflow etc!!

	api.addOptionArgument(conf.noFileOutput, '0', "no-file-output",
			"Don't print any output to file.");

	// --------------------- Core algorithm options ---------------------
	api.addOptionArgument(conf.twoLevel, '2', "two-level",
			"Optimize a two-level partition of the network.");

	bool dummyUndirected;
	api.addOptionArgument(dummyUndirected, 'u', "undirected",
			"Assume undirected links (default)");

	api.addOptionArgument(conf.directed, 'd', "directed",
			"Assume directed links");

	api.addOptionArgument(conf.undirdir, 't', "undirdir",
			"Two-mode dynamics: Assume undirected links for calculating flow, but directed when minimizing codelength.");

	api.addOptionArgument(conf.rawdir, 'w', "rawdir",
			"Two-mode dynamics: Assume directed links and let the raw link weights be the flow.");

	api.addOptionArgument(conf.unrecordedTeleportation, 'e', "unrecorded-teleportation",
			"Assume teleportation when calculating flow (on directed network) but don't encode that flow.");

	api.addOptionArgument(conf.teleportToNodes, 'o', "to-nodes",
			"Teleport to nodes (like the PageRank algorithm) instead of to links.");

	api.addOptionArgument(conf.teleportationProbability, 'p', "teleportation-probability",
			"The probability of teleporting to a random node or link.", "f");

	api.addOptionArgument(conf.seedToRandomNumberGenerator, 's', "seed",
			"A seed (integer) to the random number generator.", "n");

	// --------------------- Performance and accuracy options ---------------------
	api.addOptionArgument(conf.numTrials, 'N', "num-trials",
			"The number of outer-most loops to run before picking the best solution.", "n");

	api.addOptionArgument(conf.minimumCodelengthImprovement, 'm', "min-improvement",
			"Minimum codelength threshold for accepting a new solution.", "f");

	api.addOptionArgument(conf.randomizeCoreLoopLimit, 'a', "random-loop-limit",
			"Randomize the core loop limit from 1 to 'core-loop-limit'");

	api.addOptionArgument(conf.coreLoopLimit, 'M', "core-loop-limit",
			"Limit the number of loops that tries to move each node into the best possible module", "n");

	api.addOptionArgument(conf.levelAggregationLimit, 'L', "core-level-limit",
			"Limit the number of times the core loops are reapplied on existing modular network to search bigger structures.", "n");

	api.addOptionArgument(conf.tuneIterationLimit, 'T', "tune-iteration-limit",
			"Limit the number of main iterations in the two-level partition algorithm. 0 means no limit.", "n");

	api.addOptionArgument(conf.minimumRelativeTuneIterationImprovement, 'U', "tune-iteration-threshold",
			"Set a codelength improvement threshold of each new tune iteration to 'f' times the initial two-level codelength.", "f");

	api.addOptionArgument(conf.fastCoarseTunePartition, 'C', "fast-coarse-tune",
			"Try to find the quickest partition of each module when creating sub-modules for the coarse-tune part.");

	api.addOptionArgument(conf.alternateCoarseTuneLevel, 'A', "alternate-course-tune-level",
			"Try to find different levels of sub-modules to move in the coarse-tune part.");

	api.addOptionArgument(conf.coarseTuneLevel, 'S', "course-tune-level",
			"Set the recursion limit when searching for sub-modules. A level of 1 will find sub-sub-modules.", "n");

	api.addIncrementalOptionArgument(conf.fastHierarchicalSolution, 'F', "fast-hierarchical-solution",
			"Find top modules fast. Use -FF to keep all fast levels. Use -FFF to skip recursive part.");

	api.addOptionArgument(conf.coarseTuneLevel, 'S', "course-tune-level",
			"Set the recursion limit when searching for sub-modules. A level of 1 will find sub-sub-modules.", "n");

	// --------------------- Output options ---------------------
	api.addNonOptionArgument(conf.outDirectory, "out_directory",
			"The directory to write the results to");

	api.addIncrementalOptionArgument(conf.verbosity, 'v', "verbose",
			"Verbose output on the console. Add additional 'v' flags to increase verbosity up to -vvv.");

	api.parseArgs(argc, argv);

	// Some checks
	if (*--conf.outDirectory.end() != '/')
		conf.outDirectory.append("/");

	return conf;
}

void initBenchmark(const Config& conf, int argc, char * const argv[])
{
	std::string networkName = FileURI(conf.networkFile).getName();
	std::string logFilename = io::Str() << conf.outDirectory << networkName << ".tsv";
	Logger::setBenchmarkFilename(logFilename);
	std::ostringstream logInfo;
	logInfo << "#benchmark for";
	for (int i = 0; i < argc; ++i)
		logInfo << " " << argv[i];
	Logger::benchmark(logInfo.str(), 0, 0, 0, 0, true);
	Logger::benchmark("elapsedSeconds\ttag\tcodelength\tnumTopModules\tnumNonTrivialTopModules\ttreeDepth",
			0, 0, 0, 0, true);
	// (todo: fix problem with initializing same static file from different functions to simplify above)
	std::cout << "(Writing benchmark log to '" << logFilename << "'...)\n";
}

int main(int argc, char *argv[])
{
	Date startDate;
	Config conf;
	try
	{
		conf = getConfig(argc, argv);
		if (conf.benchmark)
			initBenchmark(conf, argc, argv);
		if (conf.verbosity == 0)
			conf.verboseNumberPrecision = 4;
		std::cout << std::setprecision(conf.verboseNumberPrecision);
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
		return 1;
	}

	std::cout << "===========================================\n";
	std::cout << "  Infomap starts at " << Date() << "\n";
	std::cout << "===========================================\n";

	runInfomap(conf);

	ASSERT(NodeBase::nodeCount() == 0); //TODO: Not working with OpenMP
//	if (NodeBase::nodeCount() != 0)
//		std::cout << "Warning: " << NodeBase::nodeCount() << " nodes not deleted!\n";

	std::cout << "===========================================\n";
	std::cout << "  Infomap ends at " << Date() << "\n";
	std::cout << "  (Elapsed time: " << (Date() - startDate) << ")\n";
	std::cout << "===========================================\n";

//	ElapsedTime t1 = (Date() - startDate);
//	std::cout << "Elapsed time: " << t1 << " (" <<
//			Stopwatch::getElapsedTimeSinceProgramStartInSec() << "s serial)." << std::endl;
	return 0;
}
<commit_msg>* Updated version<commit_after>/* -----------------------------------------------------------------------

 Infomap software package for multi-level network clustering

   * Copyright (c) 2013. See LICENSE for more info.
   * For credits and origins, see AUTHORS or www.mapequation.org/about.

----------------------------------------------------------------------- */

#include <iostream>
#include <sstream>
#include <fstream>
#include <stdexcept>
#include "utils/Logger.h"
#include "io/Config.h"
#include "infomap/InfomapContext.h"
#include "utils/Stopwatch.h"
#include "io/ProgramInterface.h"
#include "io/convert.h"
#include "utils/FileURI.h"
#include "utils/Date.h"
#include <iomanip>

void runInfomap(Config const& config)
{
	InfomapContext context(config);
	context.getInfomap()->run();
}

Config getConfig(int argc, char *argv[])
{
	Config conf;
	ProgramInterface api("Infomap",
			"Implementation of the Infomap clustering algorithm based on the Map Equation (see www.mapequation.org)",
			"0.10.1");

	// --------------------- Input options ---------------------
	api.addNonOptionArgument(conf.networkFile, "network_file",
			"The file containing the network data. Accepted formats: Pajek (implied by .net) and link list (.txt)");

	api.addOptionArgument(conf.inputFormat, 'i', "input-format",
			"Specify input format ('pajek' or 'link-list') to override format possibly implied by file extension.", "s");

	api.addOptionArgument(conf.zeroBasedNodeNumbers, 'z', "zero-based-numbering",
			"Assume node numbers start from zero in the input file instead of one.");

	api.addOptionArgument(conf.includeSelfLinks, 'k', "include-self-links",
			"Include links with the same source and target node. (Ignored by default.)");

	api.addOptionArgument(conf.nodeLimit, 'S', "node-limit",
			"Limit the number of nodes to read from the network. Ignore links connected to ignored nodes.", "n");

	api.addOptionArgument(conf.clusterDataFile, 'c', "cluster-data",
			"Provide an initial two-level solution (.clu format).", "p");

	// --------------------- Output options ---------------------
//	api.addOptionArgument(conf.printNodeRanks, 'p', "print-node-ranks",
//			"Print the calculated flow for each node to a file.");
//
//	api.addOptionArgument(conf.printFlowNetwork, 'W', "print-flow-network",
//			"Print the network with calculated flow values.");
	//TODO: Add map container so that printing can be added like -Pranks -Pflow etc!!

	api.addOptionArgument(conf.noFileOutput, '0', "no-file-output",
			"Don't print any output to file.");

	// --------------------- Core algorithm options ---------------------
	api.addOptionArgument(conf.twoLevel, '2', "two-level",
			"Optimize a two-level partition of the network.");

	bool dummyUndirected;
	api.addOptionArgument(dummyUndirected, 'u', "undirected",
			"Assume undirected links (default)");

	api.addOptionArgument(conf.directed, 'd', "directed",
			"Assume directed links");

	api.addOptionArgument(conf.undirdir, 't', "undirdir",
			"Two-mode dynamics: Assume undirected links for calculating flow, but directed when minimizing codelength.");

	api.addOptionArgument(conf.rawdir, 'w', "rawdir",
			"Two-mode dynamics: Assume directed links and let the raw link weights be the flow.");

	api.addOptionArgument(conf.unrecordedTeleportation, 'e', "unrecorded-teleportation",
			"Assume teleportation when calculating flow (on directed network) but don't encode that flow.");

	api.addOptionArgument(conf.teleportToNodes, 'o', "to-nodes",
			"Teleport to nodes (like the PageRank algorithm) instead of to links.");

	api.addOptionArgument(conf.teleportationProbability, 'p', "teleportation-probability",
			"The probability of teleporting to a random node or link.", "f");

	api.addOptionArgument(conf.seedToRandomNumberGenerator, 's', "seed",
			"A seed (integer) to the random number generator.", "n");

	// --------------------- Performance and accuracy options ---------------------
	api.addOptionArgument(conf.numTrials, 'N', "num-trials",
			"The number of outer-most loops to run before picking the best solution.", "n");

	api.addOptionArgument(conf.minimumCodelengthImprovement, 'm', "min-improvement",
			"Minimum codelength threshold for accepting a new solution.", "f");

	api.addOptionArgument(conf.randomizeCoreLoopLimit, 'a', "random-loop-limit",
			"Randomize the core loop limit from 1 to 'core-loop-limit'");

	api.addOptionArgument(conf.coreLoopLimit, 'M', "core-loop-limit",
			"Limit the number of loops that tries to move each node into the best possible module", "n");

	api.addOptionArgument(conf.levelAggregationLimit, 'L', "core-level-limit",
			"Limit the number of times the core loops are reapplied on existing modular network to search bigger structures.", "n");

	api.addOptionArgument(conf.tuneIterationLimit, 'T', "tune-iteration-limit",
			"Limit the number of main iterations in the two-level partition algorithm. 0 means no limit.", "n");

	api.addOptionArgument(conf.minimumRelativeTuneIterationImprovement, 'U', "tune-iteration-threshold",
			"Set a codelength improvement threshold of each new tune iteration to 'f' times the initial two-level codelength.", "f");

	api.addOptionArgument(conf.fastCoarseTunePartition, 'C', "fast-coarse-tune",
			"Try to find the quickest partition of each module when creating sub-modules for the coarse-tune part.");

	api.addOptionArgument(conf.alternateCoarseTuneLevel, 'A', "alternate-course-tune-level",
			"Try to find different levels of sub-modules to move in the coarse-tune part.");

	api.addOptionArgument(conf.coarseTuneLevel, 'S', "course-tune-level",
			"Set the recursion limit when searching for sub-modules. A level of 1 will find sub-sub-modules.", "n");

	api.addIncrementalOptionArgument(conf.fastHierarchicalSolution, 'F', "fast-hierarchical-solution",
			"Find top modules fast. Use -FF to keep all fast levels. Use -FFF to skip recursive part.");

	api.addOptionArgument(conf.coarseTuneLevel, 'S', "course-tune-level",
			"Set the recursion limit when searching for sub-modules. A level of 1 will find sub-sub-modules.", "n");

	// --------------------- Output options ---------------------
	api.addNonOptionArgument(conf.outDirectory, "out_directory",
			"The directory to write the results to");

	api.addIncrementalOptionArgument(conf.verbosity, 'v', "verbose",
			"Verbose output on the console. Add additional 'v' flags to increase verbosity up to -vvv.");

	api.parseArgs(argc, argv);

	// Some checks
	if (*--conf.outDirectory.end() != '/')
		conf.outDirectory.append("/");

	return conf;
}

void initBenchmark(const Config& conf, int argc, char * const argv[])
{
	std::string networkName = FileURI(conf.networkFile).getName();
	std::string logFilename = io::Str() << conf.outDirectory << networkName << ".tsv";
	Logger::setBenchmarkFilename(logFilename);
	std::ostringstream logInfo;
	logInfo << "#benchmark for";
	for (int i = 0; i < argc; ++i)
		logInfo << " " << argv[i];
	Logger::benchmark(logInfo.str(), 0, 0, 0, 0, true);
	Logger::benchmark("elapsedSeconds\ttag\tcodelength\tnumTopModules\tnumNonTrivialTopModules\ttreeDepth",
			0, 0, 0, 0, true);
	// (todo: fix problem with initializing same static file from different functions to simplify above)
	std::cout << "(Writing benchmark log to '" << logFilename << "'...)\n";
}

int main(int argc, char *argv[])
{
	Date startDate;
	Config conf;
	try
	{
		conf = getConfig(argc, argv);
		if (conf.benchmark)
			initBenchmark(conf, argc, argv);
		if (conf.verbosity == 0)
			conf.verboseNumberPrecision = 4;
		std::cout << std::setprecision(conf.verboseNumberPrecision);
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
		return 1;
	}

	std::cout << "===========================================\n";
	std::cout << "  Infomap starts at " << Date() << "\n";
	std::cout << "===========================================\n";

	runInfomap(conf);

	ASSERT(NodeBase::nodeCount() == 0); //TODO: Not working with OpenMP
//	if (NodeBase::nodeCount() != 0)
//		std::cout << "Warning: " << NodeBase::nodeCount() << " nodes not deleted!\n";

	std::cout << "===========================================\n";
	std::cout << "  Infomap ends at " << Date() << "\n";
	std::cout << "  (Elapsed time: " << (Date() - startDate) << ")\n";
	std::cout << "===========================================\n";

//	ElapsedTime t1 = (Date() - startDate);
//	std::cout << "Elapsed time: " << t1 << " (" <<
//			Stopwatch::getElapsedTimeSinceProgramStartInSec() << "s serial)." << std::endl;
	return 0;
}
<|endoftext|>


<commit_before>//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

using namespace llvm;

namespace {
  class Prepare : public ModulePass {
    public:
      static char ID;

      Prepare() : ModulePass(ID) {}

      virtual bool runOnModule(Module &M);
  };
}

static RegisterPass<Prepare> PRP("prepare",
                                 "Prepare the code for svcomp");
char Prepare::ID;

bool Prepare::runOnModule(Module &M) {
  static const char *del_body[] = {
    "__VERIFIER_assume",
    "__VERIFIER_error",
    "__VERIFIER_nondet_pointer",
    "__VERIFIER_nondet_pchar",
    "__VERIFIER_nondet_char",
    "__VERIFIER_nondet_short",
    "__VERIFIER_nondet_int",
    "__VERIFIER_nondet_long",
    "__VERIFIER_nondet_uchar",
    "__VERIFIER_nondet_ushort",
    "__VERIFIER_nondet_uint",
    "__VERIFIER_nondet_ulong",
    "__VERIFIER_nondet_unsigned",
    "__VERIFIER_nondet_u32",
    "__VERIFIER_nondet_float",
    "__VERIFIER_nondet_double",
    "__VERIFIER_nondet_bool",
    "__VERIFIER_nondet__Bool",
    "__VERIFIER_nondet_size_t",
    nullptr
  };

  for (const char **curr = del_body; *curr; curr++) {
    Function *toDel = M.getFunction(*curr);
    if (toDel && !toDel->empty()) {
      errs() << "deleting " << toDel->getName() << '\n';
      toDel->deleteBody();
    }
  }

  // prevent __VERIFIER_assert from inlining, it introduces
  // a weakness in our control dependence algorithm in some cases
  if (Function *F = M.getFunction("__VERIFIER_assert"))
    F->addFnAttr(Attribute::NoInline);

  return true;
}

<commit_msg>Prepare.cpp Set private linkage to malloc, calloc, realloc<commit_after>//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

using namespace llvm;

namespace {
  class Prepare : public ModulePass {
    public:
      static char ID;

      Prepare() : ModulePass(ID) {}

      virtual bool runOnModule(Module &M);
  };
}

static RegisterPass<Prepare> PRP("prepare",
                                 "Prepare the code for svcomp");
char Prepare::ID;

bool Prepare::runOnModule(Module &M) {
  static const char *del_body[] = {
    "__VERIFIER_assume",
    "__VERIFIER_error",
    "__VERIFIER_nondet_pointer",
    "__VERIFIER_nondet_pchar",
    "__VERIFIER_nondet_char",
    "__VERIFIER_nondet_short",
    "__VERIFIER_nondet_int",
    "__VERIFIER_nondet_long",
    "__VERIFIER_nondet_uchar",
    "__VERIFIER_nondet_ushort",
    "__VERIFIER_nondet_uint",
    "__VERIFIER_nondet_ulong",
    "__VERIFIER_nondet_unsigned",
    "__VERIFIER_nondet_u32",
    "__VERIFIER_nondet_float",
    "__VERIFIER_nondet_double",
    "__VERIFIER_nondet_bool",
    "__VERIFIER_nondet__Bool",
    "__VERIFIER_nondet_size_t",
    nullptr
  };

  for (const char **curr = del_body; *curr; curr++) {
    Function *toDel = M.getFunction(*curr);
    if (toDel && !toDel->empty()) {
      errs() << "deleting " << toDel->getName() << '\n';
      toDel->deleteBody();
    }
  }

  // prevent __VERIFIER_assert from inlining, it introduces
  // a weakness in our control dependence algorithm in some cases
  if (Function *F = M.getFunction("__VERIFIER_assert"))
    F->addFnAttr(Attribute::NoInline);

  static const char *set_linkage[] = {
    "malloc",
    "calloc",
    "realloc",
    nullptr
  };

  // we want to use our definiton of malloc
  for (const char **curr = set_linkage; *curr; curr++) {
    Function *F = M.getFunction(*curr);
    if (F && !F->empty()) {
      errs() << "Making " << F->getName() << " private\n";
      F->setLinkage(GlobalValue::PrivateLinkage);
    }
  }

  return true;
}

<|endoftext|>


<commit_before>/*=============================================================================
   Copyright (c) 2016-2017 Joel de Guzman

   Distributed under the MIT License (https://opensource.org/licenses/MIT)
=============================================================================*/
#include "view_impl.hpp"
#include <cairo.h>

namespace photon
{
   ///////////////////////////////////////////////////////////////////////////
   // Main view creation callback
   std::function<std::unique_ptr<base_view>(host_view* h)> new_view;

   struct platform_access
   {
      inline static host_view* get_host_view(base_view& main_view)
      {
         return main_view.h;
      }
   };

   namespace
   {
      inline base_view& get(gpointer user_data)
      {
         return *reinterpret_cast<base_view*>(user_data);
      }

      gboolean on_draw(GtkWidget* widget, cairo_t* cr, gpointer user_data)
      {
         auto& main_view = get(user_data);
         platform_access::get_host_view(main_view)->cr = cr;

         // Note that cr (cairo_t) is already clipped to only draw the
         // exposed areas of the widget.
         double left, top, right, bottom;
         cairo_clip_extents(cr, &left, &top, &right, &bottom);
         main_view.draw(rect{ float(left), float(top), float(right), float(bottom) });

         return false;
      }

      // void draw(base_view& main_view)
      // {
      //    platform_access::get_host_view(main_view)->cr = cr;

      //    // Note that cr (cairo_t) is already clipped to only draw the
      //    // exposed areas of the widget.
      //    double left, top, right, bottom;
      //    cairo_clip_extents(cr, &left, &top, &right, &bottom);
      //    main_view.draw(rect{ float(left), float(top), float(right), float(bottom) });
      // }

      template <typename Event>
      bool get_mouse(Event* event, mouse_button& btn, host_view* view)
      {
         btn.modifiers = 0;
         if (event->state & GDK_SHIFT_MASK)
            btn.modifiers |= mod_shift;
         if (event->state & GDK_CONTROL_MASK)
            btn.modifiers |= mod_control;
         if (event->state & GDK_MOD1_MASK)
            btn.modifiers |= mod_alt;
         if (event->state & GDK_SUPER_MASK)
            btn.modifiers |= mod_super;

         btn.num_clicks = view->click_count;
         btn.pos = { float(event->x), float(event->y) };
         return true;
      }

      bool get_button(GdkEventButton* event, mouse_button& btn, host_view* view)
      {
         if (event->button > 4)
            return false;

         static constexpr auto _250ms = 250;
         switch (event->type)
         {
            case GDK_BUTTON_PRESS:
               btn.down = true;
               if ((event->time - view->click_time) < _250ms)
                  ++view->click_count;
               else
                  view->click_count = 1;
               view->click_time = event->time;
               break;
            case GDK_BUTTON_RELEASE:
               btn.down = false;
               view->click_count = 0;
               break;
            default:
               return false;
         }

         if (!get_mouse(event, btn, view))
            return false;
         return true;
      }

      static gboolean
      on_button(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
      {
         auto& main_view = get(user_data);
         mouse_button btn;
         if (get_button(event, btn, platform_access::get_host_view(main_view)))
            main_view.click(btn);
         return TRUE;
      }

      static gboolean
      on_motion(GtkWidget* widget, GdkEventMotion* event, gpointer user_data)
      {
         auto& main_view = get(user_data);
         mouse_button btn;
         if (get_mouse(event, btn, platform_access::get_host_view(main_view)))
         {
            if (event->state & GDK_BUTTON1_MASK)
            {
               btn.down = true;
               btn.state = mouse_button::left;
            }
            else if (event->state & GDK_BUTTON2_MASK)
            {
               btn.down = true;
               btn.state = mouse_button::middle;
            }
            else if (event->state & GDK_BUTTON3_MASK)
            {
               btn.down = true;
               btn.state = mouse_button::right;
            }
            else
            {
               btn.down = false;
            }

            if (btn.down)
               main_view.drag(btn);
         }
         return TRUE;
      }

      static gboolean
      on_scroll(GtkWidget* widget, GdkEventScroll* event, gpointer user_data)
      {
         auto& main_view = get(user_data);
         auto* host_view = platform_access::get_host_view(main_view);
         auto elapsed = event->time - host_view->scroll_time;
         static constexpr float _1s = 1000;
         host_view->scroll_time = event->time;

         float dx = 0;
         float dy = 0;
         float step = _1s / elapsed;

         switch (event->direction)
         {
            case GDK_SCROLL_UP:
               dy = step;
               break;
            case GDK_SCROLL_DOWN:
               dy = -step;
               break;
            case GDK_SCROLL_LEFT:
               dx = step;
               break;
            case GDK_SCROLL_RIGHT:
               dy = -step;
               break;
            case GDK_SCROLL_SMOOTH:
               dx = event->delta_x;
               dy = event->delta_y;
               break;
            default:
               break;
         }

         main_view.scroll(
            { dx, dy },
            { float(event->x), float(event->y) }
         );
         return TRUE;
      }
   }

   void make_main_window(base_view& main_view, GtkWidget* window)
   {
      auto* drawing_area = gtk_drawing_area_new();

      gtk_container_add(GTK_CONTAINER(window), drawing_area);

      g_signal_connect(G_OBJECT(drawing_area), "draw",
         G_CALLBACK(on_draw), &main_view);

      //gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);

      g_signal_connect(drawing_area, "button-press-event",
         G_CALLBACK(on_button), &main_view);
      g_signal_connect (drawing_area, "button-release-event",
         G_CALLBACK(on_button), &main_view);
      g_signal_connect(drawing_area, "motion-notify-event",
         G_CALLBACK(on_motion), &main_view);
      g_signal_connect(drawing_area, "scroll-event",
         G_CALLBACK(on_scroll), &main_view);

      // Ask to receive events the drawing area doesn't normally
      // subscribe to. In particular, we need to ask for the
      // button press and motion notify events that want to handle.
      gtk_widget_set_events (drawing_area,
         gtk_widget_get_events(drawing_area)
         | GDK_BUTTON_PRESS_MASK
         | GDK_BUTTON_RELEASE_MASK
         | GDK_POINTER_MOTION_MASK
         | GDK_SCROLL_MASK
      );
   }

   point base_view::cursor_pos() const
   {
      return {};
   }

   point base_view::size() const
   {
      auto x = gtk_widget_get_allocated_width(h->window);
      auto y = gtk_widget_get_allocated_height(h->window);
      return { float(x), float(y) };
   }

   void base_view::size(point p)
   {
   }

   void base_view::refresh()
   {
      auto x = gtk_widget_get_allocated_width(h->window);
      auto y = gtk_widget_get_allocated_height(h->window);
      refresh({ 0, 0, float(x), float(y) });
   }

   void base_view::refresh(rect area)
   {
      gtk_widget_queue_draw_area(h->window,
         area.left, area.top, area.width(), area.height());
   }

   void base_view::limits(view_limits limits_, bool maintain_aspect)
   {
   }

   bool base_view::is_focus() const
   {
      return false;
   }

   cairo_t* base_view::begin_drawing()
   {
      // GTK already does this for us
      return h->cr;
   }

   void base_view::end_drawing(cairo_t* ctx)
   {
      // GTK will do this for us
   }

   std::string clipboard()
   {
      return "";
   }

   void clipboard(std::string const& text)
   {
   }

   void set_cursor(cursor_type type)
   {
      switch (type)
      {
         case cursor_type::arrow:
            break;
         case cursor_type::ibeam:
            break;
         case cursor_type::cross_hair:
            break;
         case cursor_type::hand:
            break;
         case cursor_type::h_resize:
            break;
         case cursor_type::v_resize:
            break;
      }
   }
}

<commit_msg>bug: wrong coordinate<commit_after>/*=============================================================================
   Copyright (c) 2016-2017 Joel de Guzman

   Distributed under the MIT License (https://opensource.org/licenses/MIT)
=============================================================================*/
#include "view_impl.hpp"
#include <cairo.h>

namespace photon
{
   ///////////////////////////////////////////////////////////////////////////
   // Main view creation callback
   std::function<std::unique_ptr<base_view>(host_view* h)> new_view;

   struct platform_access
   {
      inline static host_view* get_host_view(base_view& main_view)
      {
         return main_view.h;
      }
   };

   namespace
   {
      inline base_view& get(gpointer user_data)
      {
         return *reinterpret_cast<base_view*>(user_data);
      }

      gboolean on_draw(GtkWidget* widget, cairo_t* cr, gpointer user_data)
      {
         auto& main_view = get(user_data);
         platform_access::get_host_view(main_view)->cr = cr;

         // Note that cr (cairo_t) is already clipped to only draw the
         // exposed areas of the widget.
         double left, top, right, bottom;
         cairo_clip_extents(cr, &left, &top, &right, &bottom);
         main_view.draw(rect{ float(left), float(top), float(right), float(bottom) });

         return false;
      }

      // void draw(base_view& main_view)
      // {
      //    platform_access::get_host_view(main_view)->cr = cr;

      //    // Note that cr (cairo_t) is already clipped to only draw the
      //    // exposed areas of the widget.
      //    double left, top, right, bottom;
      //    cairo_clip_extents(cr, &left, &top, &right, &bottom);
      //    main_view.draw(rect{ float(left), float(top), float(right), float(bottom) });
      // }

      template <typename Event>
      bool get_mouse(Event* event, mouse_button& btn, host_view* view)
      {
         btn.modifiers = 0;
         if (event->state & GDK_SHIFT_MASK)
            btn.modifiers |= mod_shift;
         if (event->state & GDK_CONTROL_MASK)
            btn.modifiers |= mod_control;
         if (event->state & GDK_MOD1_MASK)
            btn.modifiers |= mod_alt;
         if (event->state & GDK_SUPER_MASK)
            btn.modifiers |= mod_super;

         btn.num_clicks = view->click_count;
         btn.pos = { float(event->x), float(event->y) };
         return true;
      }

      bool get_button(GdkEventButton* event, mouse_button& btn, host_view* view)
      {
         if (event->button > 4)
            return false;

         static constexpr auto _250ms = 250;
         switch (event->type)
         {
            case GDK_BUTTON_PRESS:
               btn.down = true;
               if ((event->time - view->click_time) < _250ms)
                  ++view->click_count;
               else
                  view->click_count = 1;
               view->click_time = event->time;
               break;
            case GDK_BUTTON_RELEASE:
               btn.down = false;
               view->click_count = 0;
               break;
            default:
               return false;
         }

         if (!get_mouse(event, btn, view))
            return false;
         return true;
      }

      static gboolean
      on_button(GtkWidget* widget, GdkEventButton* event, gpointer user_data)
      {
         auto& main_view = get(user_data);
         mouse_button btn;
         if (get_button(event, btn, platform_access::get_host_view(main_view)))
            main_view.click(btn);
         return TRUE;
      }

      static gboolean
      on_motion(GtkWidget* widget, GdkEventMotion* event, gpointer user_data)
      {
         auto& main_view = get(user_data);
         mouse_button btn;
         if (get_mouse(event, btn, platform_access::get_host_view(main_view)))
         {
            if (event->state & GDK_BUTTON1_MASK)
            {
               btn.down = true;
               btn.state = mouse_button::left;
            }
            else if (event->state & GDK_BUTTON2_MASK)
            {
               btn.down = true;
               btn.state = mouse_button::middle;
            }
            else if (event->state & GDK_BUTTON3_MASK)
            {
               btn.down = true;
               btn.state = mouse_button::right;
            }
            else
            {
               btn.down = false;
            }

            if (btn.down)
               main_view.drag(btn);
         }
         return TRUE;
      }

      static gboolean
      on_scroll(GtkWidget* widget, GdkEventScroll* event, gpointer user_data)
      {
         auto& main_view = get(user_data);
         auto* host_view = platform_access::get_host_view(main_view);
         auto elapsed = event->time - host_view->scroll_time;
         static constexpr float _1s = 1000;
         host_view->scroll_time = event->time;

         float dx = 0;
         float dy = 0;
         float step = _1s / elapsed;

         switch (event->direction)
         {
            case GDK_SCROLL_UP:
               dy = step;
               break;
            case GDK_SCROLL_DOWN:
               dy = -step;
               break;
            case GDK_SCROLL_LEFT:
               dx = step;
               break;
            case GDK_SCROLL_RIGHT:
               dx = -step;
               break;
            case GDK_SCROLL_SMOOTH:
               dx = event->delta_x;
               dy = event->delta_y;
               break;
            default:
               break;
         }

         main_view.scroll(
            { dx, dy },
            { float(event->x), float(event->y) }
         );
         return TRUE;
      }
   }

   void make_main_window(base_view& main_view, GtkWidget* window)
   {
      auto* drawing_area = gtk_drawing_area_new();

      gtk_container_add(GTK_CONTAINER(window), drawing_area);

      g_signal_connect(G_OBJECT(drawing_area), "draw",
         G_CALLBACK(on_draw), &main_view);

      //gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
      gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);

      g_signal_connect(drawing_area, "button-press-event",
         G_CALLBACK(on_button), &main_view);
      g_signal_connect (drawing_area, "button-release-event",
         G_CALLBACK(on_button), &main_view);
      g_signal_connect(drawing_area, "motion-notify-event",
         G_CALLBACK(on_motion), &main_view);
      g_signal_connect(drawing_area, "scroll-event",
         G_CALLBACK(on_scroll), &main_view);

      // Ask to receive events the drawing area doesn't normally
      // subscribe to. In particular, we need to ask for the
      // button press and motion notify events that want to handle.
      gtk_widget_set_events (drawing_area,
         gtk_widget_get_events(drawing_area)
         | GDK_BUTTON_PRESS_MASK
         | GDK_BUTTON_RELEASE_MASK
         | GDK_POINTER_MOTION_MASK
         | GDK_SCROLL_MASK
      );
   }

   point base_view::cursor_pos() const
   {
      return {};
   }

   point base_view::size() const
   {
      auto x = gtk_widget_get_allocated_width(h->window);
      auto y = gtk_widget_get_allocated_height(h->window);
      return { float(x), float(y) };
   }

   void base_view::size(point p)
   {
   }

   void base_view::refresh()
   {
      auto x = gtk_widget_get_allocated_width(h->window);
      auto y = gtk_widget_get_allocated_height(h->window);
      refresh({ 0, 0, float(x), float(y) });
   }

   void base_view::refresh(rect area)
   {
      gtk_widget_queue_draw_area(h->window,
         area.left, area.top, area.width(), area.height());
   }

   void base_view::limits(view_limits limits_, bool maintain_aspect)
   {
   }

   bool base_view::is_focus() const
   {
      return false;
   }

   cairo_t* base_view::begin_drawing()
   {
      // GTK already does this for us
      return h->cr;
   }

   void base_view::end_drawing(cairo_t* ctx)
   {
      // GTK will do this for us
   }

   std::string clipboard()
   {
      return "";
   }

   void clipboard(std::string const& text)
   {
   }

   void set_cursor(cursor_type type)
   {
      switch (type)
      {
         case cursor_type::arrow:
            break;
         case cursor_type::ibeam:
            break;
         case cursor_type::cross_hair:
            break;
         case cursor_type::hand:
            break;
         case cursor_type::h_resize:
            break;
         case cursor_type::v_resize:
            break;
      }
   }
}

<|endoftext|>