<commit_before>//! \file **************************************************************
//! \brief Source Action de sauvegarde de traduction.
//!
//! - Compilateur : GCC,MinGW
//!
//! \author Antoine Maleyrie
//! \version 0.9
//! \date 31.03.2013
//!
//! ********************************************************************

/*
*	Copyright © 2013 - Antoine Maleyrie.
*/

#include "action/actSaveTranslation.hpp"
#include "resource.hpp"

#include <wx/wfstream.h>
#include <wx/msgdlg.h>
#include <wx/file.h>
#include <wx/log.h>

//TEST
#include <iostream>

// *********************************************************************
// Class PanelActSaveTranslation
// *********************************************************************

PanelActSaveTranslation::PanelActSaveTranslation(wxWindow* parent, wxButton* buttonOK, ActSaveTranslation * act)
: GuiPanelActSaveTranslation(parent), _act(act), _buttonOK(buttonOK)
{
	std::map<wxString, wxString> const& languages = Resource::getInstance()->getLanguages();

	//Ajout des langues.
	for(auto &it: languages)
	{
		_choiceLanguageSource->Append(it.second);
		_choiceLanguageOfTranslation->Append(it.second);
	}

	//Sélectionne les bonnes langues.
	int n = _choiceLanguageSource->FindString(languages.at(_act->_lgsrc));
	_choiceLanguageSource->SetSelection(n);
	n = _choiceLanguageOfTranslation->FindString(languages.at(_act->_lgto));
	_choiceLanguageOfTranslation->SetSelection(n);

	//Sélectionne le bon fichier.
	_filePickerFile->SetFileName(_act->_fileName);

	//Tout sauvegarder ?
	if(_act->_saveAll)
		_radioBtnSaveAllTranslations->SetValue(true);
	else
		_radioBtnSaveATranslation->SetValue(true);

	//Pas de doublon
	if(_act->_noDoublon)
		_checkBoxNoDoublon->SetValue(true);
	else
		_checkBoxNoDoublon->SetValue(false);

	//Dessiner un dialogue
	if(_act->_showDialog)
		_checkBoxShowDialog->SetValue(true);
	else
		_checkBoxShowDialog->SetValue(false);

	//Lier l'événement du bouton OK du wxWindow parent.
	_buttonOK->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &PanelActSaveTranslation::OnOKButtonClick, this, _buttonOK->GetId());
}

PanelActSaveTranslation::~PanelActSaveTranslation()
{
	_buttonOK->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &PanelActSaveTranslation::OnOKButtonClick, this, _buttonOK->GetId());
}

void PanelActSaveTranslation::OnOKButtonClick(wxCommandEvent& event)
{
	//Vérifie si il y a un fichier de sélectionner.
	if(_filePickerFile->GetFileName().GetFullName().IsEmpty())
	{
		wxMessageBox(_("The name of file is empty."), _("Name file invalid"), wxOK|wxICON_EXCLAMATION|wxCENTRE, this);
		return;
	}

	//Récupérer le nom du fichier.
	wxFileName tmpFileName = _filePickerFile->GetFileName();

	//Si fichier a été modifier ?
	if(_act->_fileName != tmpFileName)
	{
		//Le fichier est déjà existent ?
		if(tmpFileName.Exists() && tmpFileName != _act->_fileName)
		{
			//Si il existe, on demande si il faut remplacer le fichier.
			wxString message = _("The file \"") + tmpFileName.GetFullPath() + _("\" already exists.\n") + _("Do you want delete this file?");
			wxMessageDialog *dlg = new wxMessageDialog(this, message, _("Delete a file"), wxYES_NO|wxICON_QUESTION|wxICON_EXCLAMATION|wxCENTRE);
			if(dlg->ShowModal() != wxID_YES)
			{
				dlg->Destroy();
				return;
			}
			else
			{
				//Suppression du fichier.
				if(!wxRemoveFile(_filePickerFile->GetPath()))
				{
					wxLogError(_("Could not remove the file : ")+tmpFileName.GetFullPath());
				}

				dlg->Destroy();
			}
		}
	}

	//Affect le langage source.
	int n = _choiceLanguageSource->GetSelection();
	wxString s = _choiceLanguageSource->GetString(n);
	_act->_lgsrc = Resource::getInstance()->languageToAbbreviation(s);

	//Affect le langage de destination.
	n = _choiceLanguageOfTranslation->GetSelection();
	s = _choiceLanguageOfTranslation->GetString(n);
	_act->_lgto = Resource::getInstance()->languageToAbbreviation(s);

	//Affect les autres arguments.
	_act->_fileName = tmpFileName;
	_act->_saveAll = _radioBtnSaveAllTranslations->GetValue();
	_act->_noDoublon = _checkBoxNoDoublon->IsChecked();
	_act->_showDialog = _checkBoxShowDialog->IsChecked();

	//Propage l'événement.
	event.Skip();
}

// *********************************************************************
// Class ActSaveTranslationFile
// *********************************************************************
ActSaveTranslationFile::ActSaveTranslationFile(wxFileName const& fileName)
: _fileName(fileName), _isOk(true)
{
	//Si le fichier existe on le charge
	if(wxFile::Exists(fileName.GetFullPath()))
	{
		//Ouverture du fichier
		wxFileInputStream file(fileName.GetFullPath());
		_isOk = file.IsOk();

		//OK ?
		if(_isOk)
		{
			//Le buffer pour stoker le tout contenue fichier
			wxMemoryBuffer buffer;
			//data temporaire.
			uint8_t tmpData[1024];

			//Lie des données temps qu'il y en a.
			while(file.CanRead() && !file.Eof())
			{
				file.Read(tmpData, 1024);
				buffer.AppendData(tmpData, file.LastRead());
			}

			//Ajouter les données dans un wxString.
			wxString stringFile;
			stringFile.Append((const char *)buffer.GetData(), buffer.GetDataLen());

			//On récupère la première ligne et on sauvegarde le reste
			wxString firstLine = stringFile.BeforeFirst('\n', &_texts);

			//On analyse la première ligne
			wxString beforeComma;
			for(size_t i; i<firstLine.Length(); i++)
			{
				if(firstLine[i] == ',')
				{
					_FirstLine.Add(beforeComma);
					beforeComma.Clear();
				}
				else
				{
					beforeComma << firstLine[i];
				}
			}
		}
	}
}

ActSaveTranslationFile::~ActSaveTranslationFile()
{

}

bool ActSaveTranslationFile::isOk()
{
	return _isOk;
}

bool ActSaveTranslationFile::exist(wxString const& text)
{
	//Taille des wxString
	size_t sizeStringFile = _texts.Length();
	size_t sizeText = text.Length();
	//Index pour le text
	size_t indexText = 0;

	//Variable pour savoir si on doit comparer les caractères.
	bool compare = true;

	//Parcoure touts les caractères (avec la ',') temps que l'on a pas trouver le "text"
	for(size_t i = 0; i < sizeStringFile; i++)
	{
		//Doit-ont comparer les caractères ?
		if(compare)
		{
			//Les caractères sont égaux.
			if(text[indexText] == _texts[i])
			{
				//Si le caractères suivent est une ',' alors le text existe
				if(_texts[i+1] == ',')
				{
					return true;
				}

				indexText++;
			}
			//On arrête de comparer pour cette ligne.
			else
			{
				compare = false;
			}
		}

		//On arrête de comparer si ','
		if(_texts[i] == ',')
		{
			compare = false;
		}
		//On repent la comparaison si nouvelle ligne ?
		else if(_texts[i] == '\n')
		{
			compare = true;
			sizeText = 0;
		}
	}

	return false;
}

void ActSaveTranslationFile::save(	wxString const& text,
									wxString const& mainTranslate)
{
	//const wxCharBuffer buffer = text.fn_str();
	//_file.
	//_file.Write(buffer.data(), buffer.length());
}

void ActSaveTranslationFile::save(
	wxString const& text,
	wxString const& mainTranslate,
	std::map<wxString, wxArrayString> const& translations)
{
}

// *********************************************************************
// Class ActSaveTranslation
// *********************************************************************

//! \todo a compléter avec les local
ActSaveTranslation::ActSaveTranslation()
: ActSaveTranslation(	"en", "fr", wxFileName(wxGetUserHome(), ""),
						true, true, true)
{
}

ActSaveTranslation::ActSaveTranslation(wxString const& lgsrc,
							wxString const& lgto,
							wxFileName const& fileName,
							bool soveAll,
							bool noDoublon,
							bool showDialog)
: Action(_("Save a translation"), "ActSaveTranslation",
_("Translation a word or a group words from google and save in a file.")),
_lgsrc(lgsrc), _lgto(lgto), _fileName(fileName),
_saveAll(soveAll), _noDoublon(noDoublon), _showDialog(showDialog)
{
}

ActSaveTranslation::~ActSaveTranslation()
{
}

void ActSaveTranslation::execute()
{
	//On récupère le contenue de la presse papier.
	wxString clipboard = Resource::getClipboard();

	//La presse papier est t'elle vide ?
	if(clipboard.IsEmpty())
	{
		//Pas de texte à traduire
		Notification::getInstance()->notify(_("Save clipboard translation"), _("Sorry, nothing at save."));
		return;
	}

	//On récupère le texte traduit
	std::map<wxString, wxArrayString> translations;
	wxString mainTranslate = Resource::getTranslations(&translations, clipboard, _lgsrc, _lgto);
	//On vérifie si une traduction existe.
	if(mainTranslate.IsEmpty())
	{
		Notification::getInstance()->notify(_("Save clipboard translation"), _("Sorry, nothing at save."));
		return;
	}

	//On vérifie la validités du fichier.
	if(_fileName.GetFullName().IsEmpty())
	{
		wxMessageBox(_("The name of file is wrong."), _("Name file invalid"), wxOK|wxICON_EXCLAMATION|wxCENTRE);
		return;
	}

	//Fichier de sauvegarde
	ActSaveTranslationFile file(_fileName);

	//Vérifie si ok
	if(!file.isOk())
		return;

	//Si on dois vérifier l'existence du texte dans le fichier
	if(_noDoublon)
	{
		if(file.exist(clipboard))
		{
			Notification::getInstance()->notify(_("Save clipboard translation"), _("The text is already existing in ")+_fileName.GetFullPath());
			return;
		}
	}

	//Sinon on le sauvegarde.
	if(_saveAll)//Doit ton tout sauvegarder ?
	{
		file.save(clipboard, mainTranslate, translations);
	}
	else
	{
		file.save(clipboard, mainTranslate);
	}
}

wxPanel* ActSaveTranslation::getPanelPreferences(wxWindow* parent, wxButton* buttonOK)
{
	return new PanelActSaveTranslation(parent, buttonOK, this);
}

void ActSaveTranslation::actLoad(wxFileConfig & fileConfig)
{
	//On récupère les langages.
	fileConfig.Read("lgsrc", &_lgsrc);
	fileConfig.Read("lgto", &_lgto);

	//On récupère le fichier.
	wxString file;
	fileConfig.Read("fileName", &file);
	_fileName.Assign(file);

	//On récupère le reste
	fileConfig.Read("saveAll", &_saveAll);
	fileConfig.Read("noDoublon", &_noDoublon);
	fileConfig.Read("showDialog", &_showDialog);
}

void ActSaveTranslation::actSave(wxFileConfig & fileConfig)const
{
	//On sauvegarde les langages.
	fileConfig.Write("lgsrc", _lgsrc);
	fileConfig.Write("lgto", _lgto);

	//On sauvegarde le fichier.
	fileConfig.Write("fileName", _fileName.GetFullPath());

	//On sauvegarde le reste
	fileConfig.Write("saveAll", _saveAll);
	fileConfig.Write("noDoublon", _noDoublon);
	fileConfig.Write("showDialog", _showDialog);
}

wxString ActSaveTranslation::getStringPreferences()const
{
	return 	Resource::getInstance()->abbreviationToLanguage(_lgsrc) +
			_(" to ") +
			Resource::getInstance()->abbreviationToLanguage(_lgto) +
			_(" in ") + _fileName.GetFullPath();
}
<commit_msg>save a text (text and mainTranslate)<commit_after>//! \file **************************************************************
//! \brief Source Action de sauvegarde de traduction.
//!
//! - Compilateur : GCC,MinGW
//!
//! \author Antoine Maleyrie
//! \version 0.9
//! \date 31.03.2013
//!
//! ********************************************************************

/*
*	Copyright © 2013 - Antoine Maleyrie.
*/

#include "action/actSaveTranslation.hpp"
#include "resource.hpp"

#include <wx/wfstream.h>
#include <wx/msgdlg.h>
#include <wx/file.h>
#include <wx/log.h>

//TEST
#include <iostream>

// *********************************************************************
// Class PanelActSaveTranslation
// *********************************************************************

PanelActSaveTranslation::PanelActSaveTranslation(wxWindow* parent, wxButton* buttonOK, ActSaveTranslation * act)
: GuiPanelActSaveTranslation(parent), _act(act), _buttonOK(buttonOK)
{
	std::map<wxString, wxString> const& languages = Resource::getInstance()->getLanguages();

	//Ajout des langues.
	for(auto &it: languages)
	{
		_choiceLanguageSource->Append(it.second);
		_choiceLanguageOfTranslation->Append(it.second);
	}

	//Sélectionne les bonnes langues.
	int n = _choiceLanguageSource->FindString(languages.at(_act->_lgsrc));
	_choiceLanguageSource->SetSelection(n);
	n = _choiceLanguageOfTranslation->FindString(languages.at(_act->_lgto));
	_choiceLanguageOfTranslation->SetSelection(n);

	//Sélectionne le bon fichier.
	_filePickerFile->SetFileName(_act->_fileName);

	//Tout sauvegarder ?
	if(_act->_saveAll)
		_radioBtnSaveAllTranslations->SetValue(true);
	else
		_radioBtnSaveATranslation->SetValue(true);

	//Pas de doublon
	if(_act->_noDoublon)
		_checkBoxNoDoublon->SetValue(true);
	else
		_checkBoxNoDoublon->SetValue(false);

	//Dessiner un dialogue
	if(_act->_showDialog)
		_checkBoxShowDialog->SetValue(true);
	else
		_checkBoxShowDialog->SetValue(false);

	//Lier l'événement du bouton OK du wxWindow parent.
	_buttonOK->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &PanelActSaveTranslation::OnOKButtonClick, this, _buttonOK->GetId());
}

PanelActSaveTranslation::~PanelActSaveTranslation()
{
	_buttonOK->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &PanelActSaveTranslation::OnOKButtonClick, this, _buttonOK->GetId());
}

void PanelActSaveTranslation::OnOKButtonClick(wxCommandEvent& event)
{
	//Vérifie si il y a un fichier de sélectionner.
	if(_filePickerFile->GetFileName().GetFullName().IsEmpty())
	{
		wxMessageBox(_("The name of file is empty."), _("Name file invalid"), wxOK|wxICON_EXCLAMATION|wxCENTRE, this);
		return;
	}

	//Récupérer le nom du fichier.
	wxFileName tmpFileName = _filePickerFile->GetFileName();

	//Si fichier a été modifier ?
	if(_act->_fileName != tmpFileName)
	{
		//Le fichier est déjà existent ?
		if(tmpFileName.Exists() && tmpFileName != _act->_fileName)
		{
			//Si il existe, on demande si il faut remplacer le fichier.
			wxString message = _("The file \"") + tmpFileName.GetFullPath() + _("\" already exists.\n") + _("Do you want delete this file?");
			wxMessageDialog *dlg = new wxMessageDialog(this, message, _("Delete a file"), wxYES_NO|wxICON_QUESTION|wxICON_EXCLAMATION|wxCENTRE);
			if(dlg->ShowModal() != wxID_YES)
			{
				dlg->Destroy();
				return;
			}
			else
			{
				//Suppression du fichier.
				if(!wxRemoveFile(_filePickerFile->GetPath()))
				{
					wxLogError(_("Could not remove the file : ")+tmpFileName.GetFullPath());
				}

				dlg->Destroy();
			}
		}
	}

	//Affect le langage source.
	int n = _choiceLanguageSource->GetSelection();
	wxString s = _choiceLanguageSource->GetString(n);
	_act->_lgsrc = Resource::getInstance()->languageToAbbreviation(s);

	//Affect le langage de destination.
	n = _choiceLanguageOfTranslation->GetSelection();
	s = _choiceLanguageOfTranslation->GetString(n);
	_act->_lgto = Resource::getInstance()->languageToAbbreviation(s);

	//Affect les autres arguments.
	_act->_fileName = tmpFileName;
	_act->_saveAll = _radioBtnSaveAllTranslations->GetValue();
	_act->_noDoublon = _checkBoxNoDoublon->IsChecked();
	_act->_showDialog = _checkBoxShowDialog->IsChecked();

	//Propage l'événement.
	event.Skip();
}

// *********************************************************************
// Class ActSaveTranslationFile
// *********************************************************************
ActSaveTranslationFile::ActSaveTranslationFile(wxFileName const& fileName)
: _fileName(fileName), _isOk(true)
{
	//Si le fichier existe on le charge
	if(wxFile::Exists(fileName.GetFullPath()))
	{
		//Ouverture du fichier
		wxFileInputStream file(_fileName.GetFullPath());
		_isOk = file.IsOk();

		//OK ?
		if(_isOk)
		{
			//Le buffer pour stoker le tout contenue fichier
			wxMemoryBuffer buffer;
			//data temporaire.
			uint8_t tmpData[1024];

			//Lie des données temps qu'il y en a.
			while(file.CanRead() && !file.Eof())
			{
				file.Read(tmpData, 1024);
				buffer.AppendData(tmpData, file.LastRead());
			}

			//Ajouter les données dans un wxString.
			wxString stringFile;
			stringFile.Append((const char *)buffer.GetData(), buffer.GetDataLen());

			//On récupère la première ligne et on sauvegarde le reste
			wxString firstLine = stringFile.BeforeFirst('\n', &_texts);

			//On analyse la première ligne
			wxString beforeComma;
			for(size_t i; i<firstLine.Length(); i++)
			{
				if(firstLine[i] == ',')
				{
					_FirstLine.Add(beforeComma);
					beforeComma.Clear();
				}
				else
				{
					beforeComma << firstLine[i];
				}
			}
		}
	}
}

ActSaveTranslationFile::~ActSaveTranslationFile()
{

}

bool ActSaveTranslationFile::isOk()
{
	return _isOk;
}

bool ActSaveTranslationFile::exist(wxString const& text)
{
	//Taille des wxString
	size_t sizeStringFile = _texts.Length();
	size_t sizeText = text.Length();
	//Index pour le text
	size_t indexText = 0;

	//Variable pour savoir si on doit comparer les caractères.
	bool compare = true;

	//Parcoure touts les caractères (avec la ',') temps que l'on a pas trouver le "text"
	for(size_t i = 0; i < sizeStringFile; i++)
	{
		//Doit-ont comparer les caractères ?
		if(compare)
		{
			//Les caractères sont égaux.
			if(text[indexText] == _texts[i])
			{
				//Si le caractères suivent est une ',' alors le text existe
				if(_texts[i+1] == ',')
				{
					return true;
				}

				indexText++;
			}
			//On arrête de comparer pour cette ligne.
			else
			{
				compare = false;
			}
		}

		//On arrête de comparer si ','
		if(_texts[i] == ',')
		{
			compare = false;
		}
		//On repent la comparaison si nouvelle ligne ?
		else if(_texts[i] == '\n')
		{
			compare = true;
			sizeText = 0;
		}
	}

	return false;
}

void ActSaveTranslationFile::save(	wxString const& text,
									wxString const& mainTranslate)
{
	wxFile file;

	wxString stringAtWrite;

	//Ouverture du fichier
	if(!file.Open(_fileName.GetFullPath(), wxFile::write_append))
	{
		return;
	}

	//Écriture des données dans le fichier
	stringAtWrite += "\n" + text + "," + mainTranslate;
	file.Write(stringAtWrite);

	//Fermeture du fichier
	file.Close();
}

void ActSaveTranslationFile::save(
	wxString const& text,
	wxString const& mainTranslate,
	std::map<wxString, wxArrayString> const& translations)
{
}

// *********************************************************************
// Class ActSaveTranslation
// *********************************************************************

//! \todo a compléter avec les local
ActSaveTranslation::ActSaveTranslation()
: ActSaveTranslation(	"en", "fr", wxFileName(wxGetUserHome(), ""),
						true, true, true)
{
}

ActSaveTranslation::ActSaveTranslation(wxString const& lgsrc,
							wxString const& lgto,
							wxFileName const& fileName,
							bool soveAll,
							bool noDoublon,
							bool showDialog)
: Action(_("Save a translation"), "ActSaveTranslation",
_("Translation a word or a group words from google and save in a file.")),
_lgsrc(lgsrc), _lgto(lgto), _fileName(fileName),
_saveAll(soveAll), _noDoublon(noDoublon), _showDialog(showDialog)
{
}

ActSaveTranslation::~ActSaveTranslation()
{
}

void ActSaveTranslation::execute()
{
	//On récupère le contenue de la presse papier.
	wxString clipboard = Resource::getClipboard();

	//La presse papier est t'elle vide ?
	if(clipboard.IsEmpty())
	{
		//Pas de texte à traduire
		Notification::getInstance()->notify(_("Save clipboard translation"), _("Sorry, nothing at save."));
		return;
	}

	//On récupère le texte traduit
	std::map<wxString, wxArrayString> translations;
	wxString mainTranslate = Resource::getTranslations(&translations, clipboard, _lgsrc, _lgto);
	//On vérifie si une traduction existe.
	if(mainTranslate.IsEmpty())
	{
		Notification::getInstance()->notify(_("Save clipboard translation"), _("Sorry, nothing at save."));
		return;
	}

	//On vérifie la validités du fichier.
	if(_fileName.GetFullName().IsEmpty())
	{
		wxMessageBox(_("The name of file is wrong."), _("Name file invalid"), wxOK|wxICON_EXCLAMATION|wxCENTRE);
		return;
	}

	//Fichier de sauvegarde
	ActSaveTranslationFile file(_fileName);

	//Vérifie si ok
	if(!file.isOk())
		return;

	//Si on dois vérifier l'existence du texte dans le fichier
	if(_noDoublon)
	{
		if(file.exist(clipboard))
		{
			Notification::getInstance()->notify(_("Save clipboard translation"), _("The text is already existing in ")+_fileName.GetFullPath());
			return;
		}
	}

	//Sinon on le sauvegarde.
	if(_saveAll)//Doit ton tout sauvegarder ?
	{
		file.save(clipboard, mainTranslate, translations);
	}
	else
	{
		file.save(clipboard, mainTranslate);
	}
}

wxPanel* ActSaveTranslation::getPanelPreferences(wxWindow* parent, wxButton* buttonOK)
{
	return new PanelActSaveTranslation(parent, buttonOK, this);
}

void ActSaveTranslation::actLoad(wxFileConfig & fileConfig)
{
	//On récupère les langages.
	fileConfig.Read("lgsrc", &_lgsrc);
	fileConfig.Read("lgto", &_lgto);

	//On récupère le fichier.
	wxString file;
	fileConfig.Read("fileName", &file);
	_fileName.Assign(file);

	//On récupère le reste
	fileConfig.Read("saveAll", &_saveAll);
	fileConfig.Read("noDoublon", &_noDoublon);
	fileConfig.Read("showDialog", &_showDialog);
}

void ActSaveTranslation::actSave(wxFileConfig & fileConfig)const
{
	//On sauvegarde les langages.
	fileConfig.Write("lgsrc", _lgsrc);
	fileConfig.Write("lgto", _lgto);

	//On sauvegarde le fichier.
	fileConfig.Write("fileName", _fileName.GetFullPath());

	//On sauvegarde le reste
	fileConfig.Write("saveAll", _saveAll);
	fileConfig.Write("noDoublon", _noDoublon);
	fileConfig.Write("showDialog", _showDialog);
}

wxString ActSaveTranslation::getStringPreferences()const
{
	return 	Resource::getInstance()->abbreviationToLanguage(_lgsrc) +
			_(" to ") +
			Resource::getInstance()->abbreviationToLanguage(_lgto) +
			_(" in ") + _fileName.GetFullPath();
}
<|endoftext|>


<commit_before>#include "LoadSaveState.h"

#include "GameController.h"
#include "VFileDevice.h"

#include <QKeyEvent>
#include <QPainter>

extern "C" {
#include "gba-serialize.h"
#include "gba-video.h"
}

using namespace QGBA;

LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
	: QWidget(parent)
	, m_controller(controller)
	, m_currentFocus(0)
{
	m_ui.setupUi(this);

	QImage currentImage(reinterpret_cast<const uchar*>(controller->drawContext()), VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGB32);
	m_currentImage.convertFromImage(currentImage.rgbSwapped());

	m_slots[0] = m_ui.state1;
	m_slots[1] = m_ui.state2;
	m_slots[2] = m_ui.state3;
	m_slots[3] = m_ui.state4;
	m_slots[4] = m_ui.state5;
	m_slots[5] = m_ui.state6;
	m_slots[6] = m_ui.state7;
	m_slots[7] = m_ui.state8;
	m_slots[8] = m_ui.state9;

	int i;
	for (i = 0; i < NUM_SLOTS; ++i) {
		loadState(i + 1);
		m_slots[i]->installEventFilter(this);
		connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
	}
}

void LoadSaveState::setMode(LoadSave mode) {
	m_mode = mode;
	QString text = mode == LoadSave::LOAD ? tr("Load State") : tr("SaveState");
	setWindowTitle(text);
	m_ui.lsLabel->setText(text);
}

bool LoadSaveState::eventFilter(QObject* object, QEvent* event) {
	if (event->type() == QEvent::KeyPress) {
		int column = m_currentFocus % 3;
		int row = m_currentFocus - column;
		switch (static_cast<QKeyEvent*>(event)->key()) {
		case Qt::Key_Up:
			row += 6;
			break;
		case Qt::Key_Down:
			row += 3;
			break;
		case Qt::Key_Left:
			column += 2;
			break;
		case Qt::Key_Right:
			column += 1;
			break;
		case Qt::Key_1:
		case Qt::Key_2:
		case Qt::Key_3:
		case Qt::Key_4:
		case Qt::Key_5:
		case Qt::Key_6:
		case Qt::Key_7:
		case Qt::Key_8:
		case Qt::Key_9:
			triggerState(static_cast<QKeyEvent*>(event)->key() - Qt::Key_1 + 1);
			break;
		case Qt::Key_Escape:
			close();
			break;
		default:
			return false;
		}
		column %= 3;
		row %= 9;
		m_currentFocus = column + row;
		m_slots[m_currentFocus]->setFocus();
		return true;
	}
	if (event->type() == QEvent::Enter) {
		int i;
		for (i = 0; i < 9; ++i) {
			if (m_slots[i] == object) {
				m_currentFocus = i;
				m_slots[m_currentFocus]->setFocus();
				return true;
			}
		}
	}
	return false;
}

void LoadSaveState::loadState(int slot) {
	GBAThread* thread = m_controller->thread();
	VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false);
	if (!vf) {
		m_slots[slot - 1]->setText(tr("Empty"));
		return;
	}
	VFileDevice vdev(vf);
	QImage stateImage;
	stateImage.load(&vdev, "PNG");
	if (!stateImage.isNull()) {
		QPixmap statePixmap;
		statePixmap.convertFromImage(stateImage);
		m_slots[slot - 1]->setIcon(statePixmap);
		m_slots[slot - 1]->setText(QString());
	} else {
		m_slots[slot - 1]->setText(tr("Slot %1").arg(slot));
	}
}

void LoadSaveState::triggerState(int slot) {
	if (m_mode == LoadSave::SAVE) {
		m_controller->saveState(slot);
	} else {
		m_controller->loadState(slot);
	}
	close();
}

void LoadSaveState::closeEvent(QCloseEvent* event) {
	emit closed();
	QWidget::closeEvent(event);
}

void LoadSaveState::showEvent(QShowEvent* event) {
	m_slots[m_currentFocus]->setFocus();
	QWidget::showEvent(event);
}

void LoadSaveState::paintEvent(QPaintEvent* event) {
	QPainter painter(this);
	QRect full(QPoint(), size());
	painter.drawPixmap(full, m_currentImage);
	painter.fillRect(full, QColor(0, 0, 0, 128));
}
<commit_msg>Fix typo<commit_after>#include "LoadSaveState.h"

#include "GameController.h"
#include "VFileDevice.h"

#include <QKeyEvent>
#include <QPainter>

extern "C" {
#include "gba-serialize.h"
#include "gba-video.h"
}

using namespace QGBA;

LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
	: QWidget(parent)
	, m_controller(controller)
	, m_currentFocus(0)
{
	m_ui.setupUi(this);

	QImage currentImage(reinterpret_cast<const uchar*>(controller->drawContext()), VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGB32);
	m_currentImage.convertFromImage(currentImage.rgbSwapped());

	m_slots[0] = m_ui.state1;
	m_slots[1] = m_ui.state2;
	m_slots[2] = m_ui.state3;
	m_slots[3] = m_ui.state4;
	m_slots[4] = m_ui.state5;
	m_slots[5] = m_ui.state6;
	m_slots[6] = m_ui.state7;
	m_slots[7] = m_ui.state8;
	m_slots[8] = m_ui.state9;

	int i;
	for (i = 0; i < NUM_SLOTS; ++i) {
		loadState(i + 1);
		m_slots[i]->installEventFilter(this);
		connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
	}
}

void LoadSaveState::setMode(LoadSave mode) {
	m_mode = mode;
	QString text = mode == LoadSave::LOAD ? tr("Load State") : tr("Save State");
	setWindowTitle(text);
	m_ui.lsLabel->setText(text);
}

bool LoadSaveState::eventFilter(QObject* object, QEvent* event) {
	if (event->type() == QEvent::KeyPress) {
		int column = m_currentFocus % 3;
		int row = m_currentFocus - column;
		switch (static_cast<QKeyEvent*>(event)->key()) {
		case Qt::Key_Up:
			row += 6;
			break;
		case Qt::Key_Down:
			row += 3;
			break;
		case Qt::Key_Left:
			column += 2;
			break;
		case Qt::Key_Right:
			column += 1;
			break;
		case Qt::Key_1:
		case Qt::Key_2:
		case Qt::Key_3:
		case Qt::Key_4:
		case Qt::Key_5:
		case Qt::Key_6:
		case Qt::Key_7:
		case Qt::Key_8:
		case Qt::Key_9:
			triggerState(static_cast<QKeyEvent*>(event)->key() - Qt::Key_1 + 1);
			break;
		case Qt::Key_Escape:
			close();
			break;
		default:
			return false;
		}
		column %= 3;
		row %= 9;
		m_currentFocus = column + row;
		m_slots[m_currentFocus]->setFocus();
		return true;
	}
	if (event->type() == QEvent::Enter) {
		int i;
		for (i = 0; i < 9; ++i) {
			if (m_slots[i] == object) {
				m_currentFocus = i;
				m_slots[m_currentFocus]->setFocus();
				return true;
			}
		}
	}
	return false;
}

void LoadSaveState::loadState(int slot) {
	GBAThread* thread = m_controller->thread();
	VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false);
	if (!vf) {
		m_slots[slot - 1]->setText(tr("Empty"));
		return;
	}
	VFileDevice vdev(vf);
	QImage stateImage;
	stateImage.load(&vdev, "PNG");
	if (!stateImage.isNull()) {
		QPixmap statePixmap;
		statePixmap.convertFromImage(stateImage);
		m_slots[slot - 1]->setIcon(statePixmap);
		m_slots[slot - 1]->setText(QString());
	} else {
		m_slots[slot - 1]->setText(tr("Slot %1").arg(slot));
	}
}

void LoadSaveState::triggerState(int slot) {
	if (m_mode == LoadSave::SAVE) {
		m_controller->saveState(slot);
	} else {
		m_controller->loadState(slot);
	}
	close();
}

void LoadSaveState::closeEvent(QCloseEvent* event) {
	emit closed();
	QWidget::closeEvent(event);
}

void LoadSaveState::showEvent(QShowEvent* event) {
	m_slots[m_currentFocus]->setFocus();
	QWidget::showEvent(event);
}

void LoadSaveState::paintEvent(QPaintEvent* event) {
	QPainter painter(this);
	QRect full(QPoint(), size());
	painter.drawPixmap(full, m_currentImage);
	painter.fillRect(full, QColor(0, 0, 0, 128));
}
<|endoftext|>


<commit_before>#include <ortools/sat/cp_model.h>

#include <rice/Array.hpp>
#include <rice/Constructor.hpp>
#include <rice/Module.hpp>

using operations_research::sat::BoolVar;
using operations_research::sat::Constraint;
using operations_research::sat::CpModelBuilder;
using operations_research::sat::CpSolverResponse;
using operations_research::sat::CpSolverStatus;
using operations_research::sat::LinearExpr;
using operations_research::sat::IntVar;
using operations_research::sat::IntervalVar;
using operations_research::sat::Model;
using operations_research::sat::NewFeasibleSolutionObserver;
using operations_research::sat::SatParameters;
using operations_research::sat::SolutionBooleanValue;
using operations_research::sat::SolutionIntegerValue;

using Rice::Array;
using Rice::Object;
using Rice::String;
using Rice::Symbol;

template<>
inline
LinearExpr from_ruby<LinearExpr>(Object x)
{
  LinearExpr expr;

  if (x.respond_to("to_i")) {
    expr = from_ruby<int64>(x.call("to_i"));
  } else if (x.respond_to("vars")) {
    Array vars = x.call("vars");
    for(auto const& var: vars) {
      auto cvar = (Array) var;
      // TODO clean up
      Object o = cvar[0];
      std::string type = ((String) o.call("class").call("name")).str();
      if (type == "ORTools::BoolVar") {
        expr.AddTerm(from_ruby<BoolVar>(cvar[0]), from_ruby<int64>(cvar[1]));
      } else if (type == "Integer") {
        expr.AddConstant(from_ruby<int64>(cvar[0]) * from_ruby<int64>(cvar[1]));
      } else {
        expr.AddTerm(from_ruby<IntVar>(cvar[0]), from_ruby<int64>(cvar[1]));
      }
    }
  } else {
    std::string type = ((String) x.call("class").call("name")).str();
    if (type == "ORTools::BoolVar") {
      expr = from_ruby<BoolVar>(x);
    } else {
      expr = from_ruby<IntVar>(x);
    }
  }

  return expr;
}

// need a wrapper class since absl::Span doesn't own
class IntVarSpan {
  std::vector<IntVar> vec;
  public:
    IntVarSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<IntVar>(a[i]));
      }
    }
    operator absl::Span<const IntVar>() {
      return absl::Span<const IntVar>(vec);
    }
};

template<>
inline
IntVarSpan from_ruby<IntVarSpan>(Object x)
{
  return IntVarSpan(x);
}

// need a wrapper class since absl::Span doesn't own
class IntervalVarSpan {
  std::vector<IntervalVar> vec;
  public:
    IntervalVarSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<IntervalVar>(a[i]));
      }
    }
    operator absl::Span<const IntervalVar>() {
      return absl::Span<const IntervalVar>(vec);
    }
};

template<>
inline
IntervalVarSpan from_ruby<IntervalVarSpan>(Object x)
{
  return IntervalVarSpan(x);
}

// need a wrapper class since absl::Span doesn't own
class LinearExprSpan {
  std::vector<LinearExpr> vec;
  public:
    LinearExprSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<LinearExpr>(a[i]));
      }
    }
    operator absl::Span<const LinearExpr>() {
      return absl::Span<const LinearExpr>(vec);
    }
};

template<>
inline
LinearExprSpan from_ruby<LinearExprSpan>(Object x)
{
  return LinearExprSpan(x);
}

// need a wrapper class since absl::Span doesn't own
class BoolVarSpan {
  std::vector<BoolVar> vec;
  public:
    BoolVarSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<BoolVar>(a[i]));
      }
    }
    operator absl::Span<const BoolVar>() {
      return absl::Span<const BoolVar>(vec);
    }
};

template<>
inline
BoolVarSpan from_ruby<BoolVarSpan>(Object x)
{
  return BoolVarSpan(x);
}

void init_constraint(Rice::Module& m) {
  Rice::define_class_under<IntVar>(m, "SatIntVar")
    .define_method("name", &IntVar::Name);

  Rice::define_class_under<IntervalVar>(m, "SatIntervalVar")
    .define_method("name", &IntervalVar::Name);

  Rice::define_class_under<Constraint>(m, "SatConstraint");

  Rice::define_class_under<BoolVar>(m, "BoolVar")
    .define_method("name", &BoolVar::Name)
    .define_method("index", &BoolVar::index)
    .define_method("not", &BoolVar::Not)
    .define_method(
      "inspect",
      *[](BoolVar& self) {
        String name(self.Name());
        return "#<ORTools::BoolVar @name=" + name.inspect().str() + ">";
      });

  Rice::define_class_under<SatParameters>(m, "SatParameters")
    .define_constructor(Rice::Constructor<SatParameters>())
    .define_method("max_time_in_seconds=",
    *[](SatParameters& self, double value) {
      self.set_max_time_in_seconds(value);
    });

  Rice::define_class_under<CpModelBuilder>(m, "CpModel")
    .define_constructor(Rice::Constructor<CpModelBuilder>())
    .define_method(
      "new_int_var",
      *[](CpModelBuilder& self, int64 start, int64 end, std::string name) {
        const operations_research::Domain domain(start, end);
        return self.NewIntVar(domain).WithName(name);
      })
    .define_method(
      "new_bool_var",
      *[](CpModelBuilder& self, std::string name) {
        return self.NewBoolVar().WithName(name);
      })
    .define_method(
      "new_interval_var",
      *[](CpModelBuilder& self, IntVar start, IntVar size, IntVar end, std::string name) {
        return self.NewIntervalVar(start, size, end).WithName(name);
      })
    .define_method(
      "new_constant",
      *[](CpModelBuilder& self, int64 value) {
        return self.NewConstant(value);
      })
    .define_method(
      "add_equality",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddEquality(x, y);
      })
    .define_method(
      "add_not_equal",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddNotEqual(x, y);
      })
    .define_method(
      "add_greater_than",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddGreaterThan(x, y);
      })
    .define_method(
      "add_greater_or_equal",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddGreaterOrEqual(x, y);
      })
    .define_method(
      "add_less_than",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddLessThan(x, y);
      })
    .define_method(
      "add_less_or_equal",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddLessOrEqual(x, y);
      })
    .define_method(
      "add_all_different",
      *[](CpModelBuilder& self, IntVarSpan vars) {
        self.AddAllDifferent(vars);
      })
    .define_method(
      "add_min_equality",
      *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
        self.AddMinEquality(target, vars);
      })
    .define_method(
      "add_lin_min_equality",
      *[](CpModelBuilder& self, LinearExpr target, LinearExprSpan exprs) {
        self.AddLinMinEquality(target, exprs);
      })
    .define_method(
      "add_max_equality",
      *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
        self.AddMaxEquality(target, vars);
      })
    .define_method(
      "add_lin_max_equality",
      *[](CpModelBuilder& self, LinearExpr target, LinearExprSpan exprs) {
        self.AddLinMaxEquality(target, exprs);
      })
    .define_method(
      "add_division_equality",
      *[](CpModelBuilder& self, IntVar target, IntVar numerator, IntVar denominator) {
        self.AddDivisionEquality(target, numerator, denominator);
      })
    .define_method(
      "add_abs_equality",
      *[](CpModelBuilder& self, IntVar target, IntVar var) {
        self.AddAbsEquality(target, var);
      })
    .define_method(
      "add_modulo_equality",
      *[](CpModelBuilder& self, IntVar target, IntVar var, IntVar mod) {
        self.AddModuloEquality(target, var, mod);
      })
    .define_method(
      "add_product_equality",
      *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
        self.AddProductEquality(target, vars);
      })
    .define_method(
      "add_no_overlap",
      *[](CpModelBuilder& self, IntervalVarSpan vars) {
        self.AddNoOverlap(vars);
      })
    .define_method(
      "add_bool_or",
      *[](CpModelBuilder& self, BoolVarSpan literals) {
        self.AddBoolOr(literals);
      })
    .define_method("add_implication", &CpModelBuilder::AddImplication)
    .define_method(
      "maximize",
      *[](CpModelBuilder& self, LinearExpr expr) {
        self.Maximize(expr);
      })
    .define_method(
      "minimize",
      *[](CpModelBuilder& self, LinearExpr expr) {
        self.Minimize(expr);
      });

  Rice::define_class_under(m, "CpSolver")
    .define_method(
      "_solve_with_observer",
      *[](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback, bool all_solutions) {
        Model m;

        if (all_solutions) {
          // set parameters for SearchForAllSolutions
          parameters.set_enumerate_all_solutions(true);
        }
        m.Add(NewSatParameters(parameters));

        m.Add(NewFeasibleSolutionObserver(
          [callback](const CpSolverResponse& r) {
            // TODO find a better way to do this
            callback.call("response=", r);
            callback.call("on_solution_callback");
          })
        );
        return SolveCpModel(model.Build(), &m);
      })
    .define_method(
      "_solve",
      *[](Object self, CpModelBuilder& model, SatParameters& parameters) {
        Model m;
        m.Add(NewSatParameters(parameters));
        return SolveCpModel(model.Build(), &m);
      })
    .define_method(
      "_solution_integer_value",
      *[](Object self, CpSolverResponse& response, IntVar& x) {
        return SolutionIntegerValue(response, x);
      })
    .define_method(
      "_solution_boolean_value",
      *[](Object self, CpSolverResponse& response, BoolVar& x) {
        return SolutionBooleanValue(response, x);
      });

  Rice::define_class_under<CpSolverResponse>(m, "CpSolverResponse")
    .define_method("objective_value", &CpSolverResponse::objective_value)
    .define_method("num_conflicts", &CpSolverResponse::num_conflicts)
    .define_method("num_branches", &CpSolverResponse::num_branches)
    .define_method("wall_time", &CpSolverResponse::wall_time)
    .define_method(
      "solution_integer_value",
      *[](CpSolverResponse& self, IntVar& x) {
        LinearExpr expr(x);
        return SolutionIntegerValue(self, expr);
      })
    .define_method("solution_boolean_value", &SolutionBooleanValue)
    .define_method(
      "status",
      *[](CpSolverResponse& self) {
        auto status = self.status();

        if (status == CpSolverStatus::OPTIMAL) {
          return Symbol("optimal");
        } else if (status == CpSolverStatus::FEASIBLE) {
          return Symbol("feasible");
        } else if (status == CpSolverStatus::INFEASIBLE) {
          return Symbol("infeasible");
        } else if (status == CpSolverStatus::MODEL_INVALID) {
          return Symbol("model_invalid");
        } else if (status == CpSolverStatus::UNKNOWN) {
          return Symbol("unknown");
        } else {
          throw std::runtime_error("Unknown solver status");
        }
      });
}
<commit_msg>Added scale_objective_by method [skip ci]<commit_after>#include <ortools/sat/cp_model.h>

#include <rice/Array.hpp>
#include <rice/Constructor.hpp>
#include <rice/Module.hpp>

using operations_research::sat::BoolVar;
using operations_research::sat::Constraint;
using operations_research::sat::CpModelBuilder;
using operations_research::sat::CpSolverResponse;
using operations_research::sat::CpSolverStatus;
using operations_research::sat::LinearExpr;
using operations_research::sat::IntVar;
using operations_research::sat::IntervalVar;
using operations_research::sat::Model;
using operations_research::sat::NewFeasibleSolutionObserver;
using operations_research::sat::SatParameters;
using operations_research::sat::SolutionBooleanValue;
using operations_research::sat::SolutionIntegerValue;

using Rice::Array;
using Rice::Object;
using Rice::String;
using Rice::Symbol;

template<>
inline
LinearExpr from_ruby<LinearExpr>(Object x)
{
  LinearExpr expr;

  if (x.respond_to("to_i")) {
    expr = from_ruby<int64>(x.call("to_i"));
  } else if (x.respond_to("vars")) {
    Array vars = x.call("vars");
    for(auto const& var: vars) {
      auto cvar = (Array) var;
      // TODO clean up
      Object o = cvar[0];
      std::string type = ((String) o.call("class").call("name")).str();
      if (type == "ORTools::BoolVar") {
        expr.AddTerm(from_ruby<BoolVar>(cvar[0]), from_ruby<int64>(cvar[1]));
      } else if (type == "Integer") {
        expr.AddConstant(from_ruby<int64>(cvar[0]) * from_ruby<int64>(cvar[1]));
      } else {
        expr.AddTerm(from_ruby<IntVar>(cvar[0]), from_ruby<int64>(cvar[1]));
      }
    }
  } else {
    std::string type = ((String) x.call("class").call("name")).str();
    if (type == "ORTools::BoolVar") {
      expr = from_ruby<BoolVar>(x);
    } else {
      expr = from_ruby<IntVar>(x);
    }
  }

  return expr;
}

// need a wrapper class since absl::Span doesn't own
class IntVarSpan {
  std::vector<IntVar> vec;
  public:
    IntVarSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<IntVar>(a[i]));
      }
    }
    operator absl::Span<const IntVar>() {
      return absl::Span<const IntVar>(vec);
    }
};

template<>
inline
IntVarSpan from_ruby<IntVarSpan>(Object x)
{
  return IntVarSpan(x);
}

// need a wrapper class since absl::Span doesn't own
class IntervalVarSpan {
  std::vector<IntervalVar> vec;
  public:
    IntervalVarSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<IntervalVar>(a[i]));
      }
    }
    operator absl::Span<const IntervalVar>() {
      return absl::Span<const IntervalVar>(vec);
    }
};

template<>
inline
IntervalVarSpan from_ruby<IntervalVarSpan>(Object x)
{
  return IntervalVarSpan(x);
}

// need a wrapper class since absl::Span doesn't own
class LinearExprSpan {
  std::vector<LinearExpr> vec;
  public:
    LinearExprSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<LinearExpr>(a[i]));
      }
    }
    operator absl::Span<const LinearExpr>() {
      return absl::Span<const LinearExpr>(vec);
    }
};

template<>
inline
LinearExprSpan from_ruby<LinearExprSpan>(Object x)
{
  return LinearExprSpan(x);
}

// need a wrapper class since absl::Span doesn't own
class BoolVarSpan {
  std::vector<BoolVar> vec;
  public:
    BoolVarSpan(Object x) {
      Array a = Array(x);
      vec.reserve(a.size());
      for (std::size_t i = 0; i < a.size(); ++i) {
        vec.push_back(from_ruby<BoolVar>(a[i]));
      }
    }
    operator absl::Span<const BoolVar>() {
      return absl::Span<const BoolVar>(vec);
    }
};

template<>
inline
BoolVarSpan from_ruby<BoolVarSpan>(Object x)
{
  return BoolVarSpan(x);
}

void init_constraint(Rice::Module& m) {
  Rice::define_class_under<IntVar>(m, "SatIntVar")
    .define_method("name", &IntVar::Name);

  Rice::define_class_under<IntervalVar>(m, "SatIntervalVar")
    .define_method("name", &IntervalVar::Name);

  Rice::define_class_under<Constraint>(m, "SatConstraint");

  Rice::define_class_under<BoolVar>(m, "BoolVar")
    .define_method("name", &BoolVar::Name)
    .define_method("index", &BoolVar::index)
    .define_method("not", &BoolVar::Not)
    .define_method(
      "inspect",
      *[](BoolVar& self) {
        String name(self.Name());
        return "#<ORTools::BoolVar @name=" + name.inspect().str() + ">";
      });

  Rice::define_class_under<SatParameters>(m, "SatParameters")
    .define_constructor(Rice::Constructor<SatParameters>())
    .define_method("max_time_in_seconds=",
    *[](SatParameters& self, double value) {
      self.set_max_time_in_seconds(value);
    });

  Rice::define_class_under<CpModelBuilder>(m, "CpModel")
    .define_constructor(Rice::Constructor<CpModelBuilder>())
    .define_method(
      "new_int_var",
      *[](CpModelBuilder& self, int64 start, int64 end, std::string name) {
        const operations_research::Domain domain(start, end);
        return self.NewIntVar(domain).WithName(name);
      })
    .define_method(
      "new_bool_var",
      *[](CpModelBuilder& self, std::string name) {
        return self.NewBoolVar().WithName(name);
      })
    .define_method(
      "new_interval_var",
      *[](CpModelBuilder& self, IntVar start, IntVar size, IntVar end, std::string name) {
        return self.NewIntervalVar(start, size, end).WithName(name);
      })
    .define_method(
      "new_constant",
      *[](CpModelBuilder& self, int64 value) {
        return self.NewConstant(value);
      })
    .define_method(
      "add_equality",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddEquality(x, y);
      })
    .define_method(
      "add_not_equal",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddNotEqual(x, y);
      })
    .define_method(
      "add_greater_than",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddGreaterThan(x, y);
      })
    .define_method(
      "add_greater_or_equal",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddGreaterOrEqual(x, y);
      })
    .define_method(
      "add_less_than",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddLessThan(x, y);
      })
    .define_method(
      "add_less_or_equal",
      *[](CpModelBuilder& self, LinearExpr x, LinearExpr y) {
        self.AddLessOrEqual(x, y);
      })
    .define_method(
      "add_all_different",
      *[](CpModelBuilder& self, IntVarSpan vars) {
        self.AddAllDifferent(vars);
      })
    .define_method(
      "add_min_equality",
      *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
        self.AddMinEquality(target, vars);
      })
    .define_method(
      "add_lin_min_equality",
      *[](CpModelBuilder& self, LinearExpr target, LinearExprSpan exprs) {
        self.AddLinMinEquality(target, exprs);
      })
    .define_method(
      "add_max_equality",
      *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
        self.AddMaxEquality(target, vars);
      })
    .define_method(
      "add_lin_max_equality",
      *[](CpModelBuilder& self, LinearExpr target, LinearExprSpan exprs) {
        self.AddLinMaxEquality(target, exprs);
      })
    .define_method(
      "add_division_equality",
      *[](CpModelBuilder& self, IntVar target, IntVar numerator, IntVar denominator) {
        self.AddDivisionEquality(target, numerator, denominator);
      })
    .define_method(
      "add_abs_equality",
      *[](CpModelBuilder& self, IntVar target, IntVar var) {
        self.AddAbsEquality(target, var);
      })
    .define_method(
      "add_modulo_equality",
      *[](CpModelBuilder& self, IntVar target, IntVar var, IntVar mod) {
        self.AddModuloEquality(target, var, mod);
      })
    .define_method(
      "add_product_equality",
      *[](CpModelBuilder& self, IntVar target, IntVarSpan vars) {
        self.AddProductEquality(target, vars);
      })
    .define_method(
      "add_no_overlap",
      *[](CpModelBuilder& self, IntervalVarSpan vars) {
        self.AddNoOverlap(vars);
      })
    .define_method(
      "add_bool_or",
      *[](CpModelBuilder& self, BoolVarSpan literals) {
        self.AddBoolOr(literals);
      })
    .define_method("add_implication", &CpModelBuilder::AddImplication)
    .define_method(
      "maximize",
      *[](CpModelBuilder& self, LinearExpr expr) {
        self.Maximize(expr);
      })
    .define_method(
      "minimize",
      *[](CpModelBuilder& self, LinearExpr expr) {
        self.Minimize(expr);
      })
    .define_method(
      "scale_objective_by",
      *[](CpModelBuilder& self, double scaling) {
        self.ScaleObjectiveBy(scaling);
      });

  Rice::define_class_under(m, "CpSolver")
    .define_method(
      "_solve_with_observer",
      *[](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback, bool all_solutions) {
        Model m;

        if (all_solutions) {
          // set parameters for SearchForAllSolutions
          parameters.set_enumerate_all_solutions(true);
        }
        m.Add(NewSatParameters(parameters));

        m.Add(NewFeasibleSolutionObserver(
          [callback](const CpSolverResponse& r) {
            // TODO find a better way to do this
            callback.call("response=", r);
            callback.call("on_solution_callback");
          })
        );
        return SolveCpModel(model.Build(), &m);
      })
    .define_method(
      "_solve",
      *[](Object self, CpModelBuilder& model, SatParameters& parameters) {
        Model m;
        m.Add(NewSatParameters(parameters));
        return SolveCpModel(model.Build(), &m);
      })
    .define_method(
      "_solution_integer_value",
      *[](Object self, CpSolverResponse& response, IntVar& x) {
        return SolutionIntegerValue(response, x);
      })
    .define_method(
      "_solution_boolean_value",
      *[](Object self, CpSolverResponse& response, BoolVar& x) {
        return SolutionBooleanValue(response, x);
      });

  Rice::define_class_under<CpSolverResponse>(m, "CpSolverResponse")
    .define_method("objective_value", &CpSolverResponse::objective_value)
    .define_method("num_conflicts", &CpSolverResponse::num_conflicts)
    .define_method("num_branches", &CpSolverResponse::num_branches)
    .define_method("wall_time", &CpSolverResponse::wall_time)
    .define_method(
      "solution_integer_value",
      *[](CpSolverResponse& self, IntVar& x) {
        LinearExpr expr(x);
        return SolutionIntegerValue(self, expr);
      })
    .define_method("solution_boolean_value", &SolutionBooleanValue)
    .define_method(
      "status",
      *[](CpSolverResponse& self) {
        auto status = self.status();

        if (status == CpSolverStatus::OPTIMAL) {
          return Symbol("optimal");
        } else if (status == CpSolverStatus::FEASIBLE) {
          return Symbol("feasible");
        } else if (status == CpSolverStatus::INFEASIBLE) {
          return Symbol("infeasible");
        } else if (status == CpSolverStatus::MODEL_INVALID) {
          return Symbol("model_invalid");
        } else if (status == CpSolverStatus::UNKNOWN) {
          return Symbol("unknown");
        } else {
          throw std::runtime_error("Unknown solver status");
        }
      });
}
<|endoftext|>


<commit_before>#include "LoadSaveState.h"

#include "GameController.h"
#include "VFileDevice.h"

#include <QKeyEvent>

extern "C" {
#include "gba-serialize.h"
#include "gba-video.h"
}

using namespace QGBA;

LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
	: QWidget(parent)
	, m_controller(controller)
	, m_currentFocus(0)
{
	m_ui.setupUi(this);

	QImage currentImage(reinterpret_cast<const uchar*>(controller->drawContext()), VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGB32);
	m_currentImage.convertFromImage(currentImage.rgbSwapped());

	m_slots[0] = m_ui.state1;
	m_slots[1] = m_ui.state2;
	m_slots[2] = m_ui.state3;
	m_slots[3] = m_ui.state4;
	m_slots[4] = m_ui.state5;
	m_slots[5] = m_ui.state6;
	m_slots[6] = m_ui.state7;
	m_slots[7] = m_ui.state8;
	m_slots[8] = m_ui.state9;

	int i;
	for (i = 0; i < NUM_SLOTS; ++i) {
		loadState(i);
		m_slots[i]->installEventFilter(this);
		connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i); });
	}
}

void LoadSaveState::setMode(LoadSave mode) {
	m_mode = mode;
	QString text = mode == LoadSave::LOAD ? tr("Load State") : tr("SaveState");
	setWindowTitle(text);
	m_ui.lsLabel->setText(text);
}

bool LoadSaveState::eventFilter(QObject*, QEvent* event) {
	if (event->type() == QEvent::KeyPress) {
		int column = m_currentFocus % 3;
		int row = m_currentFocus - column;
		switch (static_cast<QKeyEvent*>(event)->key()) {
		case Qt::Key_Up:
			row += 6;
			break;
		case Qt::Key_Down:
			row += 3;
			break;
		case Qt::Key_Left:
			column += 2;
			break;
		case Qt::Key_Right:
			column += 1;
			break;
		case Qt::Key_Escape:
			close();
			break;
		default:
			return false;
		}
		column %= 3;
		row %= 9;
		m_currentFocus = column + row;
		m_slots[m_currentFocus]->setFocus();
		return true;
	}
	return false;
}

void LoadSaveState::loadState(int slot) {
	GBAThread* thread = m_controller->thread();
	VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false);
	if (!vf) {
		return;
	}
	VFileDevice vdev(vf);
	QImage stateImage;
	stateImage.load(&vdev, "PNG");
	if (!stateImage.isNull()) {
		QPixmap statePixmap;
		statePixmap.convertFromImage(stateImage);
		m_slots[slot]->setIcon(statePixmap);
		m_slots[slot]->setText(QString());
	} else {
		m_slots[slot]->setText(tr("Slot %1").arg(slot + 1));
	}
	m_slots[slot]->setShortcut(QString::number(slot + 1));
}

void LoadSaveState::triggerState(int slot) {
	if (m_mode == LoadSave::SAVE) {
		m_controller->saveState(slot);
	} else {
		m_controller->loadState(slot);
	}
	close();
}

void LoadSaveState::closeEvent(QCloseEvent* event) {
	emit closed();
	QWidget::closeEvent(event);
}
<commit_msg>Load the right states in the right slots<commit_after>#include "LoadSaveState.h"

#include "GameController.h"
#include "VFileDevice.h"

#include <QKeyEvent>

extern "C" {
#include "gba-serialize.h"
#include "gba-video.h"
}

using namespace QGBA;

LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
	: QWidget(parent)
	, m_controller(controller)
	, m_currentFocus(0)
{
	m_ui.setupUi(this);

	QImage currentImage(reinterpret_cast<const uchar*>(controller->drawContext()), VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGB32);
	m_currentImage.convertFromImage(currentImage.rgbSwapped());

	m_slots[0] = m_ui.state1;
	m_slots[1] = m_ui.state2;
	m_slots[2] = m_ui.state3;
	m_slots[3] = m_ui.state4;
	m_slots[4] = m_ui.state5;
	m_slots[5] = m_ui.state6;
	m_slots[6] = m_ui.state7;
	m_slots[7] = m_ui.state8;
	m_slots[8] = m_ui.state9;

	int i;
	for (i = 0; i < NUM_SLOTS; ++i) {
		loadState(i + 1);
		m_slots[i]->installEventFilter(this);
		connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
	}
}

void LoadSaveState::setMode(LoadSave mode) {
	m_mode = mode;
	QString text = mode == LoadSave::LOAD ? tr("Load State") : tr("SaveState");
	setWindowTitle(text);
	m_ui.lsLabel->setText(text);
}

bool LoadSaveState::eventFilter(QObject*, QEvent* event) {
	if (event->type() == QEvent::KeyPress) {
		int column = m_currentFocus % 3;
		int row = m_currentFocus - column;
		switch (static_cast<QKeyEvent*>(event)->key()) {
		case Qt::Key_Up:
			row += 6;
			break;
		case Qt::Key_Down:
			row += 3;
			break;
		case Qt::Key_Left:
			column += 2;
			break;
		case Qt::Key_Right:
			column += 1;
			break;
		case Qt::Key_Escape:
			close();
			break;
		default:
			return false;
		}
		column %= 3;
		row %= 9;
		m_currentFocus = column + row;
		m_slots[m_currentFocus]->setFocus();
		return true;
	}
	return false;
}

void LoadSaveState::loadState(int slot) {
	GBAThread* thread = m_controller->thread();
	VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false);
	if (!vf) {
		return;
	}
	VFileDevice vdev(vf);
	QImage stateImage;
	stateImage.load(&vdev, "PNG");
	if (!stateImage.isNull()) {
		QPixmap statePixmap;
		statePixmap.convertFromImage(stateImage);
		m_slots[slot - 1]->setIcon(statePixmap);
		m_slots[slot - 1]->setText(QString());
	} else {
		m_slots[slot - 1]->setText(tr("Slot %1").arg(slot));
	}
	m_slots[slot - 1]->setShortcut(QString::number(slot));
}

void LoadSaveState::triggerState(int slot) {
	if (m_mode == LoadSave::SAVE) {
		m_controller->saveState(slot);
	} else {
		m_controller->loadState(slot);
	}
	close();
}

void LoadSaveState::closeEvent(QCloseEvent* event) {
	emit closed();
	QWidget::closeEvent(event);
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "hdfspp/hdfspp.h"

#include "fs/filesystem.h"
#include "common/hdfs_configuration.h"
#include "common/configuration_loader.h"

#include <hdfs/hdfs.h>
#include <hdfspp/hdfs_ext.h>

#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace hdfs;

/* Separate the handles used by the C api from the C++ API*/
struct hdfs_internal {
  hdfs_internal(FileSystem *p) : filesystem_(p) {}
  hdfs_internal(std::unique_ptr<FileSystem> p)
      : filesystem_(std::move(p)) {}
  virtual ~hdfs_internal(){};
  FileSystem *get_impl() { return filesystem_.get(); }
  const FileSystem *get_impl() const { return filesystem_.get(); }

 private:
  std::unique_ptr<FileSystem> filesystem_;
};

struct hdfsFile_internal {
  hdfsFile_internal(FileHandle *p) : file_(p) {}
  hdfsFile_internal(std::unique_ptr<FileHandle> p) : file_(std::move(p)) {}
  virtual ~hdfsFile_internal(){};
  FileHandle *get_impl() { return file_.get(); }
  const FileHandle *get_impl() const { return file_.get(); }

 private:
  std::unique_ptr<FileHandle> file_;
};

/* Keep thread local copy of last error string */
thread_local std::string errstr;

/* Fetch last error that happened in this thread */
void hdfsGetLastError(char *buf, int len) {
  if(nullptr == buf || len < 1 || errstr.empty()) {
    return;
  }

  /* leave space for a trailing null */
  size_t copylen = std::min((size_t)errstr.size(), (size_t)len);
  if(copylen == (size_t)len) {
    copylen--;
  }

  strncpy(buf, errstr.c_str(), copylen);

  /* stick in null */
  buf[copylen] = 0;
}

struct hdfsBuilder {
  hdfsBuilder();
  hdfsBuilder(const char * directory);
  virtual ~hdfsBuilder() {}
  ConfigurationLoader loader;
  HdfsConfiguration config;

  std::string overrideHost;
  tPort       overridePort; // 0 --> use default

  static constexpr tPort kUseDefaultPort = 0;
  static constexpr tPort kDefaultPort = 8020;
};

/* Error handling with optional debug to stderr */
static void ReportError(int errnum, std::string msg) {
  errno = errnum;
  errstr = msg;
#ifdef LIBHDFSPP_C_API_ENABLE_DEBUG
  std::cerr << "Error: errno=" << strerror(errnum) << " message=\"" << msg
            << "\"" << std::endl;
#else
  (void)msg;
#endif
}

/* Convert Status wrapped error into appropriate errno and return code */
static int Error(const Status &stat) {
  int code = stat.code();
  switch (code) {
    case Status::Code::kOk:
      return 0;
    case Status::Code::kInvalidArgument:
      ReportError(EINVAL, "Invalid argument");
      break;
    case Status::Code::kResourceUnavailable:
      ReportError(EAGAIN, "Resource temporarily unavailable");
      break;
    case Status::Code::kUnimplemented:
      ReportError(ENOSYS, "Function not implemented");
      break;
    case Status::Code::kException:
      ReportError(EINTR, "Exception raised");
      break;
    default:
      ReportError(ENOSYS, "Error: unrecognised code");
  }
  return -1;
}

/* return false on failure */
bool CheckSystemAndHandle(hdfsFS fs, hdfsFile file) {
  if (!fs) {
    ReportError(ENODEV, "Cannot perform FS operations with null FS handle.");
    return false;
  }
  if (!file) {
    ReportError(EBADF, "Cannot perform FS operations with null File handle.");
    return false;
  }
  return true;
}

/**
 * C API implementations
 **/

int hdfsFileIsOpenForRead(hdfsFile file) {
  /* files can only be open for reads at the moment, do a quick check */
  if (file) {
    return true; // Update implementation when we get file writing
  }
  return false;
}

hdfsFS hdfsConnect(const char *nn, tPort port) {
  std::string port_as_string = std::to_string(port);
  IoService * io_service = IoService::New();
  FileSystem *fs = FileSystem::New(io_service, Options());
  if (!fs) {
    return nullptr;
  }

  if (!fs->Connect(nn, port_as_string).ok()) {
    ReportError(ENODEV, "Unable to connect to NameNode.");

    // FileSystem's ctor might take ownership of the io_service; if it does,
    //    it will null out the pointer
    if (io_service)
      delete io_service;

    delete fs;

    return nullptr;
  }
  return new hdfs_internal(fs);
}

int hdfsDisconnect(hdfsFS fs) {
  if (!fs) {
    ReportError(ENODEV, "Cannot disconnect null FS handle.");
    return -1;
  }

  delete fs;
  return 0;
}

hdfsFile hdfsOpenFile(hdfsFS fs, const char *path, int flags, int bufferSize,
                      short replication, tSize blocksize) {
  (void)flags;
  (void)bufferSize;
  (void)replication;
  (void)blocksize;
  if (!fs) {
    ReportError(ENODEV, "Cannot perform FS operations with null FS handle.");
    return nullptr;
  }
  FileHandle *f = nullptr;
  Status stat = fs->get_impl()->Open(path, &f);
  if (!stat.ok()) {
    return nullptr;
  }
  return new hdfsFile_internal(f);
}

int hdfsCloseFile(hdfsFS fs, hdfsFile file) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }
  delete file;
  return 0;
}

tSize hdfsPread(hdfsFS fs, hdfsFile file, tOffset position, void *buffer,
                tSize length) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  size_t len = length;
  Status stat = file->get_impl()->PositionRead(buffer, &len, position);
  if(!stat.ok()) {
    return Error(stat);
  }
  return (tSize)len;
}

tSize hdfsRead(hdfsFS fs, hdfsFile file, void *buffer, tSize length) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  size_t len = length;
  Status stat = file->get_impl()->Read(buffer, &len);
  if (!stat.ok()) {
    return Error(stat);
  }

  return (tSize)len;
}

int hdfsSeek(hdfsFS fs, hdfsFile file, tOffset desiredPos) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  off_t desired = desiredPos;
  Status stat = file->get_impl()->Seek(&desired, std::ios_base::beg);
  if (!stat.ok()) {
    return Error(stat);
  }

  return (int)desired;
}

tOffset hdfsTell(hdfsFS fs, hdfsFile file) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  ssize_t offset = 0;
  Status stat = file->get_impl()->Seek(&offset, std::ios_base::cur);
  if (!stat.ok()) {
    return Error(stat);
  }

  return offset;
}

int hdfsCancel(hdfsFS fs, hdfsFile file) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }
  static_cast<FileHandleImpl*>(file->get_impl())->CancelOperations();
  return 0;
}

/*******************************************************************
 *                BUILDER INTERFACE
 *******************************************************************/

HdfsConfiguration LoadDefault(ConfigurationLoader & loader)
{
  optional<HdfsConfiguration> result = loader.LoadDefaultResources<HdfsConfiguration>();
  if (result)
  {
    return result.value();
  }
  else
  {
    return loader.New<HdfsConfiguration>();
  }
}

hdfsBuilder::hdfsBuilder() : config(LoadDefault(loader)), overridePort(kUseDefaultPort)
{
}

hdfsBuilder::hdfsBuilder(const char * directory) :
      config(loader.New<HdfsConfiguration>()), overridePort(kUseDefaultPort)
{
  loader.SetSearchPath(directory);
  config = LoadDefault(loader);
}

struct hdfsBuilder *hdfsNewBuilder(void)
{
  return new struct hdfsBuilder();
}

void hdfsBuilderSetNameNode(struct hdfsBuilder *bld, const char *nn)
{
  bld->overrideHost = nn;
}

void hdfsBuilderSetNameNodePort(struct hdfsBuilder *bld, tPort port)
{
  bld->overridePort = port;
}

void hdfsFreeBuilder(struct hdfsBuilder *bld)
{
  delete bld;
}

int hdfsBuilderConfSetStr(struct hdfsBuilder *bld, const char *key,
                          const char *val)
{
  optional<HdfsConfiguration> newConfig = bld->loader.OverlayValue(bld->config, key, val);
  if (newConfig)
  {
    bld->config = newConfig.value();
    return 0;
  }
  else
  {
    return 1;
  }
}

void hdfsConfStrFree(char *val)
{
  if (val)
  {
    free(val);
  }
}

hdfsFS hdfsBuilderConnect(struct hdfsBuilder *bld) {

  if (!bld->overrideHost.empty())
  {
    // TODO: pass rest of config once we get that done (HDFS-9556)
    tPort port = bld->overridePort;
    if (port == hdfsBuilder::kUseDefaultPort)
    {
      port = hdfsBuilder::kDefaultPort;
    }
    return hdfsConnect(bld->overrideHost.c_str(), port);
  }
  else
  {
    //TODO: allow construction from default port once that is done (HDFS-9556)
    ReportError(EINVAL, "No host provided to builder in hdfsBuilderConnect");
    return nullptr;
  }
}

int hdfsConfGetStr(const char *key, char **val)
{
  hdfsBuilder builder;
  return hdfsBuilderConfGetStr(&builder, key, val);
}

int hdfsConfGetInt(const char *key, int32_t *val)
{
  hdfsBuilder builder;
  return hdfsBuilderConfGetInt(&builder, key, val);
}

//
//  Extended builder interface
//
struct hdfsBuilder *hdfsNewBuilderFromDirectory(const char * configDirectory)
{
  return new struct hdfsBuilder(configDirectory);
}

int hdfsBuilderConfGetStr(struct hdfsBuilder *bld, const char *key,
                          char **val)
{
  optional<std::string> value = bld->config.Get(key);
  if (value)
  {
    size_t len = value->length() + 1;
    *val = static_cast<char *>(malloc(len));
    strncpy(*val, value->c_str(), len);
  }
  else
  {
    *val = nullptr;
  }
  return 0;
}

// If we're running on a 32-bit platform, we might get 64-bit values that
//    don't fit in an int, and int is specified by the java hdfs.h interface
bool isValidInt(int64_t value)
{
  return (value >= std::numeric_limits<int>::min() &&
          value <= std::numeric_limits<int>::max());
}

int hdfsBuilderConfGetInt(struct hdfsBuilder *bld, const char *key, int32_t *val)
{
  // Pull from default configuration
  optional<int64_t> value = bld->config.GetInt(key);
  if (value)
  {
    if (!isValidInt(*value))
      return 1;

    *val = *value;
  }
  // If not found, don't change val
  return 0;
}
<commit_msg>HDFS-9679: Fix inconsistencies with libhdfs C API.  Contributed by James Clampffer<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "hdfspp/hdfspp.h"

#include "fs/filesystem.h"
#include "common/hdfs_configuration.h"
#include "common/configuration_loader.h"

#include <hdfs/hdfs.h>
#include <hdfspp/hdfs_ext.h>

#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace hdfs;

/* Separate the handles used by the C api from the C++ API*/
struct hdfs_internal {
  hdfs_internal(FileSystem *p) : filesystem_(p) {}
  hdfs_internal(std::unique_ptr<FileSystem> p)
      : filesystem_(std::move(p)) {}
  virtual ~hdfs_internal(){};
  FileSystem *get_impl() { return filesystem_.get(); }
  const FileSystem *get_impl() const { return filesystem_.get(); }

 private:
  std::unique_ptr<FileSystem> filesystem_;
};

struct hdfsFile_internal {
  hdfsFile_internal(FileHandle *p) : file_(p) {}
  hdfsFile_internal(std::unique_ptr<FileHandle> p) : file_(std::move(p)) {}
  virtual ~hdfsFile_internal(){};
  FileHandle *get_impl() { return file_.get(); }
  const FileHandle *get_impl() const { return file_.get(); }

 private:
  std::unique_ptr<FileHandle> file_;
};

/* Keep thread local copy of last error string */
thread_local std::string errstr;

/* Fetch last error that happened in this thread */
void hdfsGetLastError(char *buf, int len) {
  if(nullptr == buf || len < 1 || errstr.empty()) {
    return;
  }

  /* leave space for a trailing null */
  size_t copylen = std::min((size_t)errstr.size(), (size_t)len);
  if(copylen == (size_t)len) {
    copylen--;
  }

  strncpy(buf, errstr.c_str(), copylen);

  /* stick in null */
  buf[copylen] = 0;
}

struct hdfsBuilder {
  hdfsBuilder();
  hdfsBuilder(const char * directory);
  virtual ~hdfsBuilder() {}
  ConfigurationLoader loader;
  HdfsConfiguration config;

  std::string overrideHost;
  tPort       overridePort; // 0 --> use default

  static constexpr tPort kUseDefaultPort = 0;
  static constexpr tPort kDefaultPort = 8020;
};

/* Error handling with optional debug to stderr */
static void ReportError(int errnum, std::string msg) {
  errno = errnum;
  errstr = msg;
#ifdef LIBHDFSPP_C_API_ENABLE_DEBUG
  std::cerr << "Error: errno=" << strerror(errnum) << " message=\"" << msg
            << "\"" << std::endl;
#else
  (void)msg;
#endif
}

/* Convert Status wrapped error into appropriate errno and return code */
static int Error(const Status &stat) {
  int code = stat.code();
  switch (code) {
    case Status::Code::kOk:
      return 0;
    case Status::Code::kInvalidArgument:
      ReportError(EINVAL, "Invalid argument");
      break;
    case Status::Code::kResourceUnavailable:
      ReportError(EAGAIN, "Resource temporarily unavailable");
      break;
    case Status::Code::kUnimplemented:
      ReportError(ENOSYS, "Function not implemented");
      break;
    case Status::Code::kException:
      ReportError(EINTR, "Exception raised");
      break;
    case Status::Code::kOperationCanceled:
      ReportError(EINTR, "Operation canceled");
      break;
    default:
      ReportError(ENOSYS, "Error: unrecognised code");
  }
  return -1;
}

/* return false on failure */
bool CheckSystemAndHandle(hdfsFS fs, hdfsFile file) {
  if (!fs) {
    ReportError(ENODEV, "Cannot perform FS operations with null FS handle.");
    return false;
  }
  if (!file) {
    ReportError(EBADF, "Cannot perform FS operations with null File handle.");
    return false;
  }
  return true;
}

/**
 * C API implementations
 **/

int hdfsFileIsOpenForRead(hdfsFile file) {
  /* files can only be open for reads at the moment, do a quick check */
  if (file) {
    return 1; // Update implementation when we get file writing
  }
  return 0;
}

hdfsFS hdfsConnect(const char *nn, tPort port) {
  std::string port_as_string = std::to_string(port);
  IoService * io_service = IoService::New();
  FileSystem *fs = FileSystem::New(io_service, Options());
  if (!fs) {
    return nullptr;
  }

  if (!fs->Connect(nn, port_as_string).ok()) {
    ReportError(ENODEV, "Unable to connect to NameNode.");

    // FileSystem's ctor might take ownership of the io_service; if it does,
    //    it will null out the pointer
    if (io_service)
      delete io_service;

    delete fs;

    return nullptr;
  }
  return new hdfs_internal(fs);
}

int hdfsDisconnect(hdfsFS fs) {
  if (!fs) {
    ReportError(ENODEV, "Cannot disconnect null FS handle.");
    return -1;
  }

  delete fs;
  return 0;
}

hdfsFile hdfsOpenFile(hdfsFS fs, const char *path, int flags, int bufferSize,
                      short replication, tSize blocksize) {
  (void)flags;
  (void)bufferSize;
  (void)replication;
  (void)blocksize;
  if (!fs) {
    ReportError(ENODEV, "Cannot perform FS operations with null FS handle.");
    return nullptr;
  }
  FileHandle *f = nullptr;
  Status stat = fs->get_impl()->Open(path, &f);
  if (!stat.ok()) {
    return nullptr;
  }
  return new hdfsFile_internal(f);
}

int hdfsCloseFile(hdfsFS fs, hdfsFile file) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }
  delete file;
  return 0;
}

tSize hdfsPread(hdfsFS fs, hdfsFile file, tOffset position, void *buffer,
                tSize length) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  size_t len = length;
  Status stat = file->get_impl()->PositionRead(buffer, &len, position);
  if(!stat.ok()) {
    return Error(stat);
  }
  return (tSize)len;
}

tSize hdfsRead(hdfsFS fs, hdfsFile file, void *buffer, tSize length) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  size_t len = length;
  Status stat = file->get_impl()->Read(buffer, &len);
  if (!stat.ok()) {
    return Error(stat);
  }

  return (tSize)len;
}

/* 0 on success, -1 on error*/
int hdfsSeek(hdfsFS fs, hdfsFile file, tOffset desiredPos) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  off_t desired = desiredPos;
  Status stat = file->get_impl()->Seek(&desired, std::ios_base::beg);
  if (!stat.ok()) {
    return Error(stat);
  }

  return 0;
}

tOffset hdfsTell(hdfsFS fs, hdfsFile file) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }

  ssize_t offset = 0;
  Status stat = file->get_impl()->Seek(&offset, std::ios_base::cur);
  if (!stat.ok()) {
    return Error(stat);
  }

  return offset;
}

/* extended API */
int hdfsCancel(hdfsFS fs, hdfsFile file) {
  if (!CheckSystemAndHandle(fs, file)) {
    return -1;
  }
  static_cast<FileHandleImpl*>(file->get_impl())->CancelOperations();
  return 0;
}

/*******************************************************************
 *                BUILDER INTERFACE
 *******************************************************************/

HdfsConfiguration LoadDefault(ConfigurationLoader & loader)
{
  optional<HdfsConfiguration> result = loader.LoadDefaultResources<HdfsConfiguration>();
  if (result)
  {
    return result.value();
  }
  else
  {
    return loader.New<HdfsConfiguration>();
  }
}

hdfsBuilder::hdfsBuilder() : config(LoadDefault(loader)), overridePort(kUseDefaultPort)
{
}

hdfsBuilder::hdfsBuilder(const char * directory) :
      config(loader.New<HdfsConfiguration>()), overridePort(kUseDefaultPort)
{
  loader.SetSearchPath(directory);
  config = LoadDefault(loader);
}

struct hdfsBuilder *hdfsNewBuilder(void)
{
  return new struct hdfsBuilder();
}

void hdfsBuilderSetNameNode(struct hdfsBuilder *bld, const char *nn)
{
  bld->overrideHost = nn;
}

void hdfsBuilderSetNameNodePort(struct hdfsBuilder *bld, tPort port)
{
  bld->overridePort = port;
}

void hdfsFreeBuilder(struct hdfsBuilder *bld)
{
  delete bld;
}

int hdfsBuilderConfSetStr(struct hdfsBuilder *bld, const char *key,
                          const char *val)
{
  optional<HdfsConfiguration> newConfig = bld->loader.OverlayValue(bld->config, key, val);
  if (newConfig)
  {
    bld->config = newConfig.value();
    return 0;
  }
  else
  {
    return 1;
  }
}

void hdfsConfStrFree(char *val)
{
  free(val);
}

hdfsFS hdfsBuilderConnect(struct hdfsBuilder *bld) {

  if (!bld->overrideHost.empty())
  {
    // TODO: pass rest of config once we get that done (HDFS-9556)
    tPort port = bld->overridePort;
    if (port == hdfsBuilder::kUseDefaultPort)
    {
      port = hdfsBuilder::kDefaultPort;
    }
    return hdfsConnect(bld->overrideHost.c_str(), port);
  }
  else
  {
    //TODO: allow construction from default port once that is done (HDFS-9556)
    ReportError(EINVAL, "No host provided to builder in hdfsBuilderConnect");
    return nullptr;
  }
}

int hdfsConfGetStr(const char *key, char **val)
{
  hdfsBuilder builder;
  return hdfsBuilderConfGetStr(&builder, key, val);
}

int hdfsConfGetInt(const char *key, int32_t *val)
{
  hdfsBuilder builder;
  return hdfsBuilderConfGetInt(&builder, key, val);
}

//
//  Extended builder interface
//
struct hdfsBuilder *hdfsNewBuilderFromDirectory(const char * configDirectory)
{
  return new struct hdfsBuilder(configDirectory);
}

int hdfsBuilderConfGetStr(struct hdfsBuilder *bld, const char *key,
                          char **val)
{
  optional<std::string> value = bld->config.Get(key);
  if (value)
  {
    size_t len = value->length() + 1;
    *val = static_cast<char *>(malloc(len));
    strncpy(*val, value->c_str(), len);
  }
  else
  {
    *val = nullptr;
  }
  return 0;
}

// If we're running on a 32-bit platform, we might get 64-bit values that
//    don't fit in an int, and int is specified by the java hdfs.h interface
bool isValidInt(int64_t value)
{
  return (value >= std::numeric_limits<int>::min() &&
          value <= std::numeric_limits<int>::max());
}

int hdfsBuilderConfGetInt(struct hdfsBuilder *bld, const char *key, int32_t *val)
{
  // Pull from default configuration
  optional<int64_t> value = bld->config.GetInt(key);
  if (value)
  {
    if (!isValidInt(*value))
      return 1;

    *val = *value;
  }
  // If not found, don't change val
  return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <chrono>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <string>
#include "test_failure.hpp"
#include "test_filter.hpp"
#include <vector>
#ifdef _WIN32
#include <wtypes.h>
#include <WinBase.h>
#endif

namespace rs
{
  // Stores and executes tests.
  class test_harness
  {
  public:
    typedef std::unique_ptr<itest_desc> desc_ptr;
    typedef std::vector<desc_ptr> desc_array;
    typedef std::vector<itest_desc*> pdesc_array;
    typedef std::function<void(std::string const&)> output_function;
    typedef std::pair<bool, test_failure_exception> test_run_result;

  private:
    test_filter m_filter;
    desc_array m_meta_array;
    output_function m_output;
    bool m_output_passed_tests;
    std::chrono::milliseconds m_timeout;

  public:
    // Returns the current test filter.
    static test_filter const& filter()
    {
      return inst().m_filter;
    }

    // Sets the test filter used to run a specified set of tests.
    static void filter(test_filter const& tf)
    {
      inst().m_filter = tf;
    }

    // Returns the current log function used by the test harness.
    static output_function const& log_function()
    {
      return inst().m_output;
    }

    // Set the log function used by the test harness.
    static void log_function(output_function const& log_fn)
    {
      inst().m_output = log_fn;
    }

    // Returns whether test passes are logged.
    static bool log_test_passes()
    {
      return inst().m_output_passed_tests;
    }

    // Flag whether test passes should be logged (false by default).
    static void log_test_passes(bool b)
    {
      inst().m_output_passed_tests = b;
    }

    template <typename descT, std::size_t idx = 0>
    // Registers a test via a test_desc object.
    // Called automatically when you use a macro which defines a test_desc.
    static void register_test()
    {
      test_harness& harness = inst();
      harness.m_meta_array.emplace_back(new test_desc<descT, idx>());
    }

    // Runs all tests specified by the current filter.
    // Returns the number of failed tests.
    static int run()
    {
      test_harness& harness = inst();
      pdesc_array tests;

      // create filtered tests array
      for (desc_ptr& desc : harness.m_meta_array)
        if (!harness.m_filter.is_filtered(*desc))
          tests.emplace_back(desc.get());

      return harness.run_test_array(tests);
    }

    // Returns the current timeout in milliseconds.
    static std::chrono::milliseconds timeout()
    {
      return inst().m_timeout;
    }

    template <typename Rep, typename Period>
    // Sets the cap for the amount of time tests are allowed to run.
    // Individual tests may override this timeout.
    static void timeout(std::chrono::duration<Rep, Period> const& duration)
    {
      inst().m_timeout = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
    }

  private:
    // Default timeout is 2 minutes.
    static const std::size_t c_default_timeout = 120 * 1000;

    // Constructs the test_harness object. (private)
    test_harness() : m_timeout(c_default_timeout)
    {
      m_output = [](std::string const& str)
      {
        std::cout << str;
#ifdef _MSC_VER
        OutputDebugStringA(str.c_str());
#endif
      };
    }

    // Performs a test run and handles any failure.
    static test_run_result do_test_run(itest* test)
    {
      try
      {
        test->run();
      }
      catch (test_failure_exception& failure)
      {
        return std::make_pair(true, failure);
      }

      return std::make_pair(false, test_failure_exception());
    }

    // Formats a full test name as object:test.
    static std::string format_test_name(itest_desc const& desc)
    {
      std::string const& obj_name = desc.get_object_name();
      std::string const& test_name = desc.get_test_name();

      std::string str(obj_name);
      if (obj_name.size() && test_name.size()) str += ":";
      str += test_name;

      return std::move(str);
    }

    // Returns the test_harness instance.
    static test_harness& inst()
    {
      static test_harness instance;
      return instance;
    }

    // Runs all tests in the given description array
    int run_test_array(std::vector<itest_desc*> const& arr)
    {
      int fail_count = 0;

      // run all tests from their test descriptions
      for (itest_desc* desc : arr)
        if (!run_test_desc(desc))
          fail_count++;

      return fail_count;
    }

    // Runs a test from a test description.
    bool run_test_desc(itest_desc* desc)
    {
      using namespace std;
      using namespace std::chrono;

      milliseconds timeout = desc->get_timeout() == size_t(-1) ? m_timeout : milliseconds(desc->get_timeout());
      unique_ptr<itest> test = move(desc->create());

      try
      {
        // run the test on a separate thread
        future<test_run_result> res = async(launch::async, do_test_run, test.get());
        future_status status = res.wait_for(timeout);

        // if the test has finished:
        if (status == future_status::ready)
        {
          test_run_result run_result = res.get();
          if (run_result.first) throw run_result.second; // test failed
        }
        else // the test has timed out:
        {
          throw test_failure_exception(desc->get_file_name(), desc->get_line_number())
            << "timeout after " << timeout.count() << " milliseconds";
        }
      }
      catch (test_failure_exception& failure)
      {
        // print test failure
        m_output(format_test_name(*desc) + " failed\n  " + failure.what() + "\n");
        return false;
      }

      // print test passed
      if (m_output_passed_tests) m_output(format_test_name(*desc) + " passed\n");
      return true;
    }

  };
} // namespace rs<commit_msg>Added log function to test_harness.<commit_after>#pragma once

#include <chrono>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <string>
#include "test_failure.hpp"
#include "test_filter.hpp"
#include <vector>
#ifdef _WIN32
#include <wtypes.h>
#include <WinBase.h>
#endif

namespace rs
{
  // Stores and executes tests.
  class test_harness
  {
  public:
    typedef std::unique_ptr<itest_desc> desc_ptr;
    typedef std::vector<desc_ptr> desc_array;
    typedef std::vector<itest_desc*> pdesc_array;
    typedef std::function<void(std::string const&)> output_function;
    typedef std::pair<bool, test_failure_exception> test_run_result;

  private:
    test_filter m_filter;
    desc_array m_meta_array;
    output_function m_output;
    bool m_output_passed_tests;
    std::chrono::milliseconds m_timeout;

  public:
    // Returns the current test filter.
    static test_filter const& filter()
    {
      return inst().m_filter;
    }

    // Sets the test filter used to run a specified set of tests.
    static void filter(test_filter const& tf)
    {
      inst().m_filter = tf;
    }

    // Sends a string to the current log function.
    static void log(std::string const& str)
    {
      inst().m_output(str);
    }

    // Returns the current log function used by the test harness.
    static output_function const& log_function()
    {
      return inst().m_output;
    }

    // Set the log function used by the test harness.
    static void log_function(output_function const& log_fn)
    {
      inst().m_output = log_fn;
    }

    // Returns whether test passes are logged.
    static bool log_test_passes()
    {
      return inst().m_output_passed_tests;
    }

    // Flag whether test passes should be logged (false by default).
    static void log_test_passes(bool b)
    {
      inst().m_output_passed_tests = b;
    }

    template <typename descT, std::size_t idx = 0>
    // Registers a test via a test_desc object.
    // Called automatically when you use a macro which defines a test_desc.
    static void register_test()
    {
      test_harness& harness = inst();
      harness.m_meta_array.emplace_back(new test_desc<descT, idx>());
    }

    // Runs all tests specified by the current filter.
    // Returns the number of failed tests.
    static int run()
    {
      test_harness& harness = inst();
      pdesc_array tests;

      // create filtered tests array
      for (desc_ptr& desc : harness.m_meta_array)
        if (!harness.m_filter.is_filtered(*desc))
          tests.emplace_back(desc.get());

      return harness.run_test_array(tests);
    }

    // Returns the current timeout in milliseconds.
    static std::chrono::milliseconds timeout()
    {
      return inst().m_timeout;
    }

    template <typename Rep, typename Period>
    // Sets the cap for the amount of time tests are allowed to run.
    // Individual tests may override this timeout.
    static void timeout(std::chrono::duration<Rep, Period> const& duration)
    {
      inst().m_timeout = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
    }

  private:
    // Default timeout is 2 minutes.
    static const std::size_t c_default_timeout = 120 * 1000;

    // Constructs the test_harness object. (private)
    test_harness() : m_timeout(c_default_timeout)
    {
      m_output = [](std::string const& str)
      {
        std::cout << str;
#ifdef _MSC_VER
        OutputDebugStringA(str.c_str());
#endif
      };
    }

    // Performs a test run and handles any failure.
    static test_run_result do_test_run(itest* test)
    {
      try
      {
        test->run();
      }
      catch (test_failure_exception& failure)
      {
        return std::make_pair(true, failure);
      }

      return std::make_pair(false, test_failure_exception());
    }

    // Formats a full test name as object:test.
    static std::string format_test_name(itest_desc const& desc)
    {
      std::string const& obj_name = desc.get_object_name();
      std::string const& test_name = desc.get_test_name();

      std::string str(obj_name);
      if (obj_name.size() && test_name.size()) str += ":";
      str += test_name;

      return std::move(str);
    }

    // Returns the test_harness instance.
    static test_harness& inst()
    {
      static test_harness instance;
      return instance;
    }

    // Runs all tests in the given description array
    int run_test_array(std::vector<itest_desc*> const& arr)
    {
      int fail_count = 0;

      // run all tests from their test descriptions
      for (itest_desc* desc : arr)
        if (!run_test_desc(desc))
          fail_count++;

      return fail_count;
    }

    // Runs a test from a test description.
    bool run_test_desc(itest_desc* desc)
    {
      using namespace std;
      using namespace std::chrono;

      milliseconds timeout = desc->get_timeout() == size_t(-1) ? m_timeout : milliseconds(desc->get_timeout());
      unique_ptr<itest> test = move(desc->create());

      try
      {
        // run the test on a separate thread
        future<test_run_result> res = async(launch::async, do_test_run, test.get());
        future_status status = res.wait_for(timeout);

        // if the test has finished:
        if (status == future_status::ready)
        {
          test_run_result run_result = res.get();
          if (run_result.first) throw run_result.second; // test failed
        }
        else // the test has timed out:
        {
          throw test_failure_exception(desc->get_file_name(), desc->get_line_number())
            << "timeout after " << timeout.count() << " milliseconds";
        }
      }
      catch (test_failure_exception& failure)
      {
        // print test failure
        m_output(format_test_name(*desc) + " failed\n  " + failure.what() + "\n");
        return false;
      }

      // print test passed
      if (m_output_passed_tests) m_output(format_test_name(*desc) + " passed\n");
      return true;
    }

  };
} // namespace rs<|endoftext|>