<commit_before>#include "updater.h"
#include "util.h"
#include "compat.h"
#include "init.h"

#include <inttypes.h>
#include <string>
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

bool willing_to_update=false;
bool ready_to_update=false;
bool am_updated=false;
bool downloading_update=false;
bool updating=false;
char updating_to[16384] = {'\0'};
int32_t latest_version = -1;

#include <QCoreApplication>
#include <QSslError>
#include <QSslConfiguration>
#include "qt/overviewpage.h"

boost::filesystem::path TmpPath = boost::filesystem::temp_directory_path();

// constructor
Download::Download(BitcoinGUI *guiref_, QString url_string, std::string filename) {
	guiref = guiref_;
	file_name = filename;
	am_complete_trigger = false;

	// QString::toLocal8Bit()
	//  - local 8-bit representation of the string as a QByteArray
	// Qurl::fromEncoded(QByteArray)
	//  - Parses input and returns the corresponding QUrl.
	//    input is assumed to be in encoded form,
	//    containing only ASCII characters.
	LogPrintf("updater: Downloading %s\n", qPrintable(url_string));
	QUrl url = QUrl::fromEncoded(url_string.toLocal8Bit());

	// makes a request
	QNetworkRequest request(url);
	QSslConfiguration config = QSslConfiguration::defaultConfiguration();
	config.setProtocol(QSsl::AnyProtocol);
	request.setSslConfiguration(config);
	QNetworkReply *reply = net_manager.get(request);
	QObject::connect(&net_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(on_finished(QNetworkReply *)));
	QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(on_error(QNetworkReply::NetworkError)));
	QObject::connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(on_ssl_errors(QList<QSslError>)));
	QObject::connect(reply, SIGNAL(readyRead()), this, SLOT(on_ready_read()));

	LogPrintf("updater: Preparing file to write out to at: \"%s\"\n", filename.c_str());
	QFile file(QString(file_name.c_str()));
	if (!file.open(QIODevice::WriteOnly)) {
		LogPrintf("updater: Couldn't open \"%s\" for writing: %s\n", filename, qPrintable(file.errorString()));
		reply->deleteLater();
		return;
	}

	curr_dl = reply;
	return;
}

Download::~Download() {
}

void Download::on_ready_read() {
	file.write(curr_dl->readAll());
	file.close();
}

void Download::on_error(QNetworkReply::NetworkError code) {
	LogPrintf("updater: Error on dl attempt: (%s).\n", code);
}

inline std::string slurp (const std::string& path) {
	std::ostringstream buf; std::ifstream input (path.c_str()); buf << input.rdbuf(); return buf.str();
}

void Download::on_finished(QNetworkReply *reply) {
	QVariant possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);

	/* We'll deduct if the redirection is valid in the redirectUrl function */
	QUrl _urlRedirectedTo = this->redirectUrl(possibleRedirectUrl.toUrl(), _urlRedirectedTo);
	QUrl url = reply->url();
	/* If the URL is not empty, we're being redirected. */
	if(!_urlRedirectedTo.isEmpty()) {
		QString text = QString("updater: Redirected to ").append(_urlRedirectedTo.toString()).append("\n");
		LogPrintf(qPrintable(text));
		//dl(_urlRedirectedTo.toString());
		curr_dl->deleteLater();
		return;
	}

	if (reply->error()) {
		LogPrintf("updater: Download of %s failed: %s\n", url.toEncoded().constData(), qPrintable(reply->errorString()));
		curr_dl->deleteLater();
		return;
	}

	file.write(curr_dl->readAll());
	file.close();
	LogPrintf("updater: Download of %s succeeded (saved to %s)\n", url.toEncoded().constData(), file_name);
	curr_dl->deleteLater();
	am_complete_trigger = true;
	return;
}

QUrl Download::redirectUrl(const QUrl& possibleRedirectUrl, const QUrl& oldRedirectUrl) const {
	QUrl redirectUrl;
	/*
	 * Check if the URL is empty and
	 * that we aren't being fooled into a infinite redirect loop.
	 * We could also keep track of how many redirects we have been to
	 * and set a limit to it, but we'll leave that to you.
	 */
	if(!possibleRedirectUrl.isEmpty() &&
		possibleRedirectUrl != oldRedirectUrl) {
		redirectUrl = possibleRedirectUrl;
	}
	return redirectUrl;
}

void Download::on_ssl_errors(const QList<QSslError> &sslErrors) {
	for (int i=0; i<sslErrors.count(); ++i) {
		LogPrintf("updater: SSL error: %s\n", qPrintable(sslErrors[i].errorString()));
	}
}
void Download::ShowDL() {
	QObject::connect(guiref->overviewPage->GetUpdateButton(), SIGNAL(clicked()), this, SLOT(Update()));
	guiref->overviewPage->HideUpdateText();
	guiref->overviewPage->ShowUpdateButton();
}

void Download::Update() {
	#ifdef _WIN32
	boost::filesystem::path tmp = boost::filesystem::unique_path();
	const std::string dst_str = QCoreApplication::applicationFilePath();
	const std::string tmp_str = TmpPath.string()+tmp.string();
	const std::string src_str = TmpPath.string()+"Ember-qt.exe";
	LogPrintf("updater: Currently running exe: \"%s\"\n", dst_str);
	LogPrintf("updater: Temporary name for ^: \"%s\"\n", tmp_str);
	LogPrintf("updater: Newly downloaded exe: \"%s\"\n", src_str);
	remove(tmp_str.c_str()); // ignore return code

	LogPrintf("updater: Renaming currently running exe to temporary name.\n");
	rename(dst_str.c_str(),tmp_str.c_str());
	LogPrintf("updater: Copying newly downloaded to currently running name.\n");
	CopyFileA(src_str.c_str(),dst_str.c_str(),false);
	LogPrintf("updater: Getting the currently running name (who is now replaced).\n");
	strcpy(updating_to,dst_str.c_str());
	updating_to[16383] = '\0';
	updating = true;
	StartShutdown();
	#endif
	return;
}

char* GetExeUrl(int version) {
	char *str = NULL;
	int res = 0;

	if (NULL == (str = (char*)malloc(1024))) {
		LogPrintf("updater: GetExeUrl() out of memory!\n");
		return NULL;
	}
	if (0 > (res = sprintf(str, "https://www.0xify.com/static/emb/win/x86/Ember-qt-%d.exe", version))) {
		LogPrintf("updater: GetExeUrl() couldn't sprintf()!\n");
		return NULL;
	}
	str[1023] = '\0';
	LogPrintf("updater: Got exe url as \"%s\".\n", str);
	return str;
}

void ThreadUpdater(BitcoinGUI *guiref_) {
	#ifdef _WIN32
    Download ver_dl(guiref_, "https://www.0xify.com/static/emb/win/x86/_latest_version.txt", TmpPath.string()+"Ember-latest-version.txt");
    while (!ver_dl.am_complete_trigger && !ShutdownRequested()) {
    	MilliSleep(1000);
    }
    std::string latest_version_str = slurp(TmpPath.string()+"Ember-latest-version.txt");
    LogPrintf("updater: Latest version string of file contents: \"%s\"\n", latest_version_str);
	latest_version = std::stoi(latest_version_str);
	LogPrintf("updater: Here is the latest version: %d.\n", latest_version);
	if (latest_version >= 0) {
        if (ready_to_update) {
            LogPrintf("updater: Ready for upgrade process.\n");
        } else if (CLIENT_VERSION < latest_version) { // When true, we've got an upgrade ready to dl, and we haven't already
	  		LogPrintf("updater: Upgrade should be available on host...\n");
	  		char *s = GetExeUrl(latest_version);
	   		if (s == NULL) {
	  			LogPrintf("updater: Problem with building the URL for latest version.\n");
	   			return;
	   		} else {
	   			downloading_update = true;
    			Download dl(guiref_, s, TmpPath.string()+"Ember-qt.exe");
    			while (!dl.am_complete_trigger  && !ShutdownRequested()) {
    				MilliSleep(1000);
    			}
    			LogPrintf("updater: Got updated version downloaded and primed.\n");
				ready_to_update = true;
				am_updated = false;
				downloading_update = false;
				dl.ShowDL();
				LogPrintf("updater: We have shown the update button. Hint hint.\n");
				return;
			}
		} else {
			LogPrintf("updater: We are latest version. Good.\n");
			am_updated = true;
			guiref_->overviewPage->ShowUpdateText();
		}
	}
	#endif
}
<commit_msg>Updater tweak<commit_after>#include "updater.h"
#include "util.h"
#include "compat.h"
#include "init.h"

#include <inttypes.h>
#include <string>
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

bool willing_to_update=false;
bool ready_to_update=false;
bool am_updated=false;
bool downloading_update=false;
bool updating=false;
char updating_to[16384] = {'\0'};
int32_t latest_version = -1;

#include <QCoreApplication>
#include <QSslError>
#include <QSslConfiguration>
#include "qt/overviewpage.h"

boost::filesystem::path TmpPath = boost::filesystem::temp_directory_path();

// constructor
Download::Download(BitcoinGUI *guiref_, QString url_string, std::string filename) {
	guiref = guiref_;
	file_name = filename;
	am_complete_trigger = false;

	// QString::toLocal8Bit()
	//  - local 8-bit representation of the string as a QByteArray
	// Qurl::fromEncoded(QByteArray)
	//  - Parses input and returns the corresponding QUrl.
	//    input is assumed to be in encoded form,
	//    containing only ASCII characters.
	LogPrintf("updater: Downloading %s\n", qPrintable(url_string));
	QUrl url = QUrl::fromEncoded(url_string.toLocal8Bit());

	// makes a request
	QNetworkRequest request(url);
	QSslConfiguration config = QSslConfiguration::defaultConfiguration();
	config.setProtocol(QSsl::AnyProtocol);
	request.setSslConfiguration(config);
	QNetworkReply *reply = net_manager.get(request);
	QObject::connect(&net_manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(on_finished(QNetworkReply *)));
	QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(on_error(QNetworkReply::NetworkError)));
	QObject::connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(on_ssl_errors(QList<QSslError>)));
	QObject::connect(reply, SIGNAL(readyRead()), this, SLOT(on_ready_read()));

	LogPrintf("updater: Preparing file to write out to at: \"%s\"\n", filename.c_str());
	QFile file(QString(file_name.c_str()));
	if (!file.open(QIODevice::WriteOnly)) {
		LogPrintf("updater: Couldn't open \"%s\" for writing: %s\n", filename, qPrintable(file.errorString()));
		reply->deleteLater();
		return;
	}

	curr_dl = reply;
	return;
}

Download::~Download() {
}

void Download::on_ready_read() {
	file.write(curr_dl->readAll());
	file.close();
}

void Download::on_error(QNetworkReply::NetworkError code) {
	LogPrintf("updater: Error on dl attempt: (%s).\n", code);
}

inline std::string slurp (const std::string& path) {
	std::ostringstream buf; std::ifstream input (path.c_str()); buf << input.rdbuf(); return buf.str();
}

void Download::on_finished(QNetworkReply *reply) {
	QVariant possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);

	/* We'll deduct if the redirection is valid in the redirectUrl function */
	QUrl _urlRedirectedTo = this->redirectUrl(possibleRedirectUrl.toUrl(), _urlRedirectedTo);
	QUrl url = reply->url();
	/* If the URL is not empty, we're being redirected. */
	if(!_urlRedirectedTo.isEmpty()) {
		QString text = QString("updater: Redirected to ").append(_urlRedirectedTo.toString()).append("\n");
		LogPrintf(qPrintable(text));
		//dl(_urlRedirectedTo.toString());
		curr_dl->deleteLater();
		return;
	}

	if (reply->error()) {
		LogPrintf("updater: Download of %s failed: %s\n", url.toEncoded().constData(), qPrintable(reply->errorString()));
		curr_dl->deleteLater();
		return;
	}

	file.write(curr_dl->readAll());
	file.close();
	LogPrintf("updater: Download of %s succeeded (saved to %s)\n", url.toEncoded().constData(), file_name);
	curr_dl->deleteLater();
	am_complete_trigger = true;
	return;
}

QUrl Download::redirectUrl(const QUrl& possibleRedirectUrl, const QUrl& oldRedirectUrl) const {
	QUrl redirectUrl;
	/*
	 * Check if the URL is empty and
	 * that we aren't being fooled into a infinite redirect loop.
	 * We could also keep track of how many redirects we have been to
	 * and set a limit to it, but we'll leave that to you.
	 */
	if(!possibleRedirectUrl.isEmpty() &&
		possibleRedirectUrl != oldRedirectUrl) {
		redirectUrl = possibleRedirectUrl;
	}
	return redirectUrl;
}

void Download::on_ssl_errors(const QList<QSslError> &sslErrors) {
	for (int i=0; i<sslErrors.count(); ++i) {
		LogPrintf("updater: SSL error: %s\n", qPrintable(sslErrors[i].errorString()));
	}
}
void Download::ShowDL() {
	QObject::connect(guiref->overviewPage->GetUpdateButton(), SIGNAL(clicked()), this, SLOT(Update()));
	guiref->overviewPage->HideUpdateText();
	guiref->overviewPage->ShowUpdateButton();
}

void Download::Update() {
	#ifdef _WIN32
	boost::filesystem::path tmp = boost::filesystem::unique_path();
    const std::string dst_str = QCoreApplication::applicationFilePath().toStdString();
	const std::string tmp_str = TmpPath.string()+tmp.string();
	const std::string src_str = TmpPath.string()+"Ember-qt.exe";
	LogPrintf("updater: Currently running exe: \"%s\"\n", dst_str);
	LogPrintf("updater: Temporary name for ^: \"%s\"\n", tmp_str);
	LogPrintf("updater: Newly downloaded exe: \"%s\"\n", src_str);
	remove(tmp_str.c_str()); // ignore return code

	LogPrintf("updater: Renaming currently running exe to temporary name.\n");
	rename(dst_str.c_str(),tmp_str.c_str());
	LogPrintf("updater: Copying newly downloaded to currently running name.\n");
	CopyFileA(src_str.c_str(),dst_str.c_str(),false);
	LogPrintf("updater: Getting the currently running name (who is now replaced).\n");
	strcpy(updating_to,dst_str.c_str());
	updating_to[16383] = '\0';
	updating = true;
	StartShutdown();
	#endif
	return;
}

char* GetExeUrl(int version) {
	char *str = NULL;
	int res = 0;

	if (NULL == (str = (char*)malloc(1024))) {
		LogPrintf("updater: GetExeUrl() out of memory!\n");
		return NULL;
	}
	if (0 > (res = sprintf(str, "https://www.0xify.com/static/emb/win/x86/Ember-qt-%d.exe", version))) {
		LogPrintf("updater: GetExeUrl() couldn't sprintf()!\n");
		return NULL;
	}
	str[1023] = '\0';
	LogPrintf("updater: Got exe url as \"%s\".\n", str);
	return str;
}

void ThreadUpdater(BitcoinGUI *guiref_) {
	#ifdef _WIN32
    Download ver_dl(guiref_, "https://www.0xify.com/static/emb/win/x86/_latest_version.txt", TmpPath.string()+"Ember-latest-version.txt");
    while (!ver_dl.am_complete_trigger && !ShutdownRequested()) {
    	MilliSleep(1000);
    }
    std::string latest_version_str = slurp(TmpPath.string()+"Ember-latest-version.txt");
    LogPrintf("updater: Latest version string of file contents: \"%s\"\n", latest_version_str);
	latest_version = std::stoi(latest_version_str);
	LogPrintf("updater: Here is the latest version: %d.\n", latest_version);
	if (latest_version >= 0) {
        if (ready_to_update) {
            LogPrintf("updater: Ready for upgrade process.\n");
        } else if (CLIENT_VERSION < latest_version) { // When true, we've got an upgrade ready to dl, and we haven't already
	  		LogPrintf("updater: Upgrade should be available on host...\n");
	  		char *s = GetExeUrl(latest_version);
	   		if (s == NULL) {
	  			LogPrintf("updater: Problem with building the URL for latest version.\n");
	   			return;
	   		} else {
	   			downloading_update = true;
    			Download dl(guiref_, s, TmpPath.string()+"Ember-qt.exe");
    			while (!dl.am_complete_trigger  && !ShutdownRequested()) {
    				MilliSleep(1000);
    			}
    			LogPrintf("updater: Got updated version downloaded and primed.\n");
				ready_to_update = true;
				am_updated = false;
				downloading_update = false;
				dl.ShowDL();
				LogPrintf("updater: We have shown the update button. Hint hint.\n");
				return;
			}
		} else {
			LogPrintf("updater: We are latest version. Good.\n");
			am_updated = true;
			guiref_->overviewPage->ShowUpdateText();
		}
	}
	#endif
}
<|endoftext|>


<commit_before>#include "black_box_tests.h"

void prg_test(Value& v)
{
    u64 seed = v["Seed"].GetUint64();
    int iterations = v["Iterations"].GetInt();

    int uniformIntervalStart = -1;
    int uniformIntervalEnd = -1;
    if (!v["UniformInterval"].IsNull())
    {
        uniformIntervalStart = v["UniformInterval"]["Item1"].GetInt();
        uniformIntervalEnd = v["UniformInterval"]["Item2"].GetInt();
    }

    const char* outputFile = v["OutputFile"].GetString();

    PRG::prg rg(seed);

    ofstream out_file(outputFile);

    for (int i = 0; i < iterations; i++)
    {
        if (uniformIntervalStart != -1 && uniformIntervalEnd != -1)
        {
            u32 random = rg.Uniform_Int(uniformIntervalStart, uniformIntervalEnd);
            out_file << random << endl;
        }
        else
        {
            float random = rg.Uniform_Unit_Interval();
            out_file << random << endl;
        }
    }
}

void hash_test(Value& v)
{

}

void explore_test(Value& v)
{

}

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc != 2)
    {
        return 0;
    }

    ifstream json_file(argv[1]);
    string json_file_content;
    while (json_file >> json_file_content) { }

    Document d;
    d.Parse(json_file_content.c_str());

    for (SizeType i = 0; i < d.Size(); i++)
    {
        switch (d[i]["Type"].GetInt())
        {
        case 0:
            prg_test(d[i]);
            break;
        case 1:
            hash_test(d[i]);
            break;
        case 2:
            explore_test(d[i]);
            break;
        }
    }
    //Value& s = d["stars"];
    //s.SetInt(s.GetInt() + 1);

    //// 3. Stringify the DOM
    //StringBuffer buffer;
    //Writer<StringBuffer> writer(buffer);
    //d.Accept(writer);

    //// Output {"project":"rapidjson","stars":11}
    //std::cout << buffer.GetString() << std::endl;

	return 0;
}<commit_msg>added hash test<commit_after>#include "black_box_tests.h"

void prg_test(Value& v)
{
    u64 seed = v["Seed"].GetUint64();
    int iterations = v["Iterations"].GetInt();

    int uniformIntervalStart = -1;
    int uniformIntervalEnd = -1;
    if (!v["UniformInterval"].IsNull())
    {
        uniformIntervalStart = v["UniformInterval"]["Item1"].GetInt();
        uniformIntervalEnd = v["UniformInterval"]["Item2"].GetInt();
    }

    const char* outputFile = v["OutputFile"].GetString();

    PRG::prg rg(seed);

    ofstream out_file(outputFile);

    for (int i = 0; i < iterations; i++)
    {
        if (uniformIntervalStart != -1 && uniformIntervalEnd != -1)
        {
            u32 random = rg.Uniform_Int(uniformIntervalStart, uniformIntervalEnd);
            out_file << random << endl;
        }
        else
        {
            float random = rg.Uniform_Unit_Interval();
            out_file << random << endl;
        }
    }
}

void hash_test(Value& v)
{
    const char* outputFile = v["OutputFile"].GetString();

    ofstream out_file(outputFile);

    Value& values = v["Values"];
    for (SizeType i = 0; i < values.Size(); i++)
    {
        string value(values[i].GetString());

        out_file << HashUtils::Compute_Id_Hash(value) << endl;
    }
}

void explore_test(Value& v)
{

}

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc != 2)
    {
        return 0;
    }

    ifstream json_file(argv[1]);
    string json_file_content;
    while (json_file >> json_file_content) { }

    Document d;
    d.Parse(json_file_content.c_str());

    for (SizeType i = 0; i < d.Size(); i++)
    {
        switch (d[i]["Type"].GetInt())
        {
        case 0:
            prg_test(d[i]);
            break;
        case 1:
            hash_test(d[i]);
            break;
        case 2:
            explore_test(d[i]);
            break;
        }
    }

    return 0;
}<|endoftext|>


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

/**
 * Definition of ListNode
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *         this->val = val;
 *         this->next = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param node: a node in the list should be deleted
     * @return: nothing
     */
    void deleteNode(ListNode *node) {
        if (node->next) {
            auto node_to_delete = node->next;
            node->val = node->next->val;
            node->next = node->next->next;
            delete node_to_delete;
        } else {
            node = None;
        }
    }
};
<commit_msg>Update delete-node-in-the-middle-of-singly-linked-list.cpp<commit_after>// Time:  O(1)
// Space: O(1)

/**
 * Definition of ListNode
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *         this->val = val;
 *         this->next = NULL;
 *     }
 * }
 */
class Solution {
public:
    /**
     * @param node: a node in the list should be deleted
     * @return: nothing
     */
    void deleteNode(ListNode *node) {
        if (node->next) {
            auto node_to_delete = node->next;
            node->val = node->next->val;
            node->next = node->next->next;
            delete node_to_delete;
        } else {
            node = nullptr;
        }
    }
};
<|endoftext|>


<commit_before>/*
  This file is part of KOrganizer.

  Copyright (c) 2008 Thomas Thrainer <tom_t@gmx.at>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 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 General Public License for more details.

  You should have received a copy of the GNU 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.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "kcheckcombobox.h"

#include <KDebug>

#include <QListView>
#include <QStyledItemDelegate>
#include <QLineEdit>
#include <QKeyEvent>

KCheckComboBox::KCheckComboBox( QWidget *parent ) : KComboBox( parent )
{
  mSeparator = QLatin1String( "," );
  mIgnoreHide = false;

  connect( this, SIGNAL(activated(int)), this, SLOT(toggleCheckState(int)) );
  connect( model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
           this, SLOT(updateCheckedItems(const QModelIndex &, const QModelIndex &)) );

  // read-only contents
  setEditable( true );
  lineEdit()->setReadOnly( true );
  setInsertPolicy( KComboBox::NoInsert );

  view()->installEventFilter( this );
  view()->viewport()->installEventFilter( this );

  updateCheckedItems();
}

KCheckComboBox::~KCheckComboBox()
{
}

void KCheckComboBox::hidePopup()
{
  if ( !mIgnoreHide ) {
    KComboBox::hidePopup();
  }
  mIgnoreHide = false;
}

Qt::CheckState KCheckComboBox::itemCheckState( int index ) const
{
  return static_cast<Qt::CheckState>( itemData( index, Qt::CheckStateRole ).toInt() );
}

void KCheckComboBox::setItemCheckState( int index, Qt::CheckState state )
{
  setItemData( index, state, Qt::CheckStateRole );
}

QStringList KCheckComboBox::checkedItems() const
{
  QStringList items;
  if ( model() ) {
    QModelIndex index = model()->index( 0, modelColumn(), rootModelIndex() );
    QModelIndexList indexes = model()->match( index, Qt::CheckStateRole,
                                              Qt::Checked, -1, Qt::MatchExactly );
    foreach ( const QModelIndex &index, indexes ) {
      items += index.data().toString();
    }
  }
  return items;
}

void KCheckComboBox::setCheckedItems( const QStringList &items )
{
  for ( int r = 0; r < model()->rowCount( rootModelIndex() ); ++r ) {
    QModelIndex indx = model()->index( r, modelColumn(), rootModelIndex() );
    QString text = indx.data().toString();
    bool found = items.contains( text );
    model()->setData( indx, found ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole );
  }
  updateCheckedItems();
}

QString KCheckComboBox::defaultText() const
{
  return mDefaultText;
}

void KCheckComboBox::setDefaultText( const QString &text )
{
  if ( mDefaultText != text ) {
    mDefaultText = text;
    updateCheckedItems();
  }
}

QString KCheckComboBox::separator() const
{
  return mSeparator;
}

void KCheckComboBox::setSeparator( const QString &separator )
{
  if ( mSeparator != separator ) {
    mSeparator = separator;
    updateCheckedItems();
  }
}

void KCheckComboBox::keyPressEvent( QKeyEvent *event )
{
  switch ( event->key() ) {
    case Qt::Key_Up:
    case Qt::Key_Down:
      showPopup();
      event->accept();
      break;
    case Qt::Key_Return:
    case Qt::Key_Enter:
    case Qt::Key_Escape:
      hidePopup();
      event->accept();
      break;
    default:
      break;
  }
  // don't call base class implementation, we don't need all that stuff in there
}

void KCheckComboBox::wheelEvent( QWheelEvent *event )
{
  // discard mouse wheel events on the combo box
  event->accept();
}

bool KCheckComboBox::eventFilter( QObject *receiver, QEvent *event )
{
  switch ( event->type() ) {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::ShortcutOverride:
    {
      switch ( static_cast<QKeyEvent *>( event )->key() ) {
        case Qt::Key_Space:
          if ( event->type() == QEvent::KeyPress ) {
            toggleCheckState( view()->currentIndex() );
            return true;
          }
          break;
        case Qt::Key_Return:
        case Qt::Key_Enter:
        case Qt::Key_Escape:
          // ignore Enter keys, they would normally select items.
          // but we select with Space, because multiple selection is possible
          // we simply close the popup on Enter/Escape
          hidePopup();
          return true;
      }
    }
    case QEvent::MouseButtonRelease:
      mIgnoreHide = true;
      break;
    default:
      break;
  }
  return KComboBox::eventFilter( receiver, event );
}

void KCheckComboBox::updateCheckedItems( const QModelIndex &topLeft,
                                         const QModelIndex &bottomRight )
{
  Q_UNUSED( topLeft );
  Q_UNUSED( bottomRight );

  QStringList items = checkedItems();
  QString text;
  if ( items.isEmpty() ) {
    text = mDefaultText;
  } else {
    text = items.join( mSeparator );
  }

  setEditText( text );
  emit checkedItemsChanged( items );
}

void KCheckComboBox::toggleCheckState( const QModelIndex &index )
{
  QVariant value = index.data( Qt::CheckStateRole );
  if ( value.isValid() ) {
    Qt::CheckState state = static_cast<Qt::CheckState>( value.toInt() );
    model()->setData( index, state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked,
                      Qt::CheckStateRole );
  }
}

void KCheckComboBox::toggleCheckState( int pos )
{
  Q_UNUSED( pos );
  toggleCheckState( view()->currentIndex() );
}

#include "kcheckcombobox.moc"
<commit_msg>In the lineedit, elide the text so it doesn't scroll too far to the right. also put on a tooltip showing the contents of the lineedit.<commit_after>/*
  This file is part of KOrganizer.

  Copyright (c) 2008 Thomas Thrainer <tom_t@gmx.at>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 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 General Public License for more details.

  You should have received a copy of the GNU 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.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "kcheckcombobox.h"

#include <KDebug>

#include <QListView>
#include <QStyledItemDelegate>
#include <QLineEdit>
#include <QKeyEvent>

KCheckComboBox::KCheckComboBox( QWidget *parent ) : KComboBox( parent )
{
  mSeparator = QLatin1String( "," );
  mIgnoreHide = false;

  connect( this, SIGNAL(activated(int)), this, SLOT(toggleCheckState(int)) );
  connect( model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
           this, SLOT(updateCheckedItems(const QModelIndex &, const QModelIndex &)) );

  // read-only contents
  setEditable( true );
  lineEdit()->setReadOnly( true );
  setInsertPolicy( KComboBox::NoInsert );

  view()->installEventFilter( this );
  view()->viewport()->installEventFilter( this );

  updateCheckedItems();
}

KCheckComboBox::~KCheckComboBox()
{
}

void KCheckComboBox::hidePopup()
{
  if ( !mIgnoreHide ) {
    KComboBox::hidePopup();
  }
  mIgnoreHide = false;
}

Qt::CheckState KCheckComboBox::itemCheckState( int index ) const
{
  return static_cast<Qt::CheckState>( itemData( index, Qt::CheckStateRole ).toInt() );
}

void KCheckComboBox::setItemCheckState( int index, Qt::CheckState state )
{
  setItemData( index, state, Qt::CheckStateRole );
}

QStringList KCheckComboBox::checkedItems() const
{
  QStringList items;
  if ( model() ) {
    QModelIndex index = model()->index( 0, modelColumn(), rootModelIndex() );
    QModelIndexList indexes = model()->match( index, Qt::CheckStateRole,
                                              Qt::Checked, -1, Qt::MatchExactly );
    foreach ( const QModelIndex &index, indexes ) {
      items += index.data().toString();
    }
  }
  return items;
}

void KCheckComboBox::setCheckedItems( const QStringList &items )
{
  for ( int r = 0; r < model()->rowCount( rootModelIndex() ); ++r ) {
    QModelIndex indx = model()->index( r, modelColumn(), rootModelIndex() );
    QString text = indx.data().toString();
    bool found = items.contains( text );
    model()->setData( indx, found ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole );
  }
  updateCheckedItems();
}

QString KCheckComboBox::defaultText() const
{
  return mDefaultText;
}

void KCheckComboBox::setDefaultText( const QString &text )
{
  if ( mDefaultText != text ) {
    mDefaultText = text;
    updateCheckedItems();
  }
}

QString KCheckComboBox::separator() const
{
  return mSeparator;
}

void KCheckComboBox::setSeparator( const QString &separator )
{
  if ( mSeparator != separator ) {
    mSeparator = separator;
    updateCheckedItems();
  }
}

void KCheckComboBox::keyPressEvent( QKeyEvent *event )
{
  switch ( event->key() ) {
    case Qt::Key_Up:
    case Qt::Key_Down:
      showPopup();
      event->accept();
      break;
    case Qt::Key_Return:
    case Qt::Key_Enter:
    case Qt::Key_Escape:
      hidePopup();
      event->accept();
      break;
    default:
      break;
  }
  // don't call base class implementation, we don't need all that stuff in there
}

void KCheckComboBox::wheelEvent( QWheelEvent *event )
{
  // discard mouse wheel events on the combo box
  event->accept();
}

bool KCheckComboBox::eventFilter( QObject *receiver, QEvent *event )
{
  switch ( event->type() ) {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::ShortcutOverride:
    {
      switch ( static_cast<QKeyEvent *>( event )->key() ) {
        case Qt::Key_Space:
          if ( event->type() == QEvent::KeyPress ) {
            toggleCheckState( view()->currentIndex() );
            return true;
          }
          break;
        case Qt::Key_Return:
        case Qt::Key_Enter:
        case Qt::Key_Escape:
          // ignore Enter keys, they would normally select items.
          // but we select with Space, because multiple selection is possible
          // we simply close the popup on Enter/Escape
          hidePopup();
          return true;
      }
    }
    case QEvent::MouseButtonRelease:
      mIgnoreHide = true;
      break;
    default:
      break;
  }
  return KComboBox::eventFilter( receiver, event );
}

void KCheckComboBox::updateCheckedItems( const QModelIndex &topLeft,
                                         const QModelIndex &bottomRight )
{
  Q_UNUSED( topLeft );
  Q_UNUSED( bottomRight );

  QStringList items = checkedItems();
  QString text;
  if ( items.isEmpty() ) {
    text = mDefaultText;
  } else {
    text = items.join( mSeparator );
  }

  setEditText( fontMetrics().elidedText( text, Qt::ElideRight, width() ) );
  setToolTip( text );

  emit checkedItemsChanged( items );
}

void KCheckComboBox::toggleCheckState( const QModelIndex &index )
{
  QVariant value = index.data( Qt::CheckStateRole );
  if ( value.isValid() ) {
    Qt::CheckState state = static_cast<Qt::CheckState>( value.toInt() );
    model()->setData( index, state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked,
                      Qt::CheckStateRole );
  }
}

void KCheckComboBox::toggleCheckState( int pos )
{
  Q_UNUSED( pos );
  toggleCheckState( view()->currentIndex() );
}

#include "kcheckcombobox.moc"
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "math.h"

#include "IECore/EXRImageReader.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/VectorTypedData.h"
#include "IECore/ImagePrimitive.h"
#include "IECore/FileNameParameter.h"
#include "IECore/BoxOps.h"
#include "IECore/MessageHandler.h"

#include "boost/format.hpp"

#include "OpenEXR/ImfInputFile.h"
#include "OpenEXR/ImfChannelList.h"
#include "OpenEXR/Iex.h"
#include "OpenEXR/ImfTestFile.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <cassert>

using namespace IECore;
using namespace Imf;
using namespace std;

using Imath::Box2i;

const Reader::ReaderDescription<EXRImageReader> EXRImageReader::g_readerDescription("exr");

EXRImageReader::EXRImageReader() :
		ImageReader( "EXRImageReader", "Reads ILM OpenEXR file format." ),
		m_inputFile( 0 )
{
}

EXRImageReader::EXRImageReader(const string &fileName) :
		ImageReader( "EXRImageReader", "Reads ILM OpenEXR file format." ),
		m_inputFile( 0 )
{
	m_fileNameParameter->setTypedValue( fileName );
	// added so that isComplete works and nothing changes on the class definition... the branch version should fix this.
	open();
	// added so that isComplete works and nothing changes on the class definition... the branch version should fix this.
	open();
}

EXRImageReader::~EXRImageReader()
{
	delete m_inputFile;
}

bool EXRImageReader::canRead( const string &fileName )
{
	return isOpenExrFile( fileName.c_str() );
}

void EXRImageReader::channelNames( vector<string> &names )
{
	open( true );

	const ChannelList &channels = m_inputFile->header().channels();
	names.clear();
	for( ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i )
	{
		names.push_back( i.name() );
	}
}

bool EXRImageReader::isComplete()
{
	if( !open() )
	{
		return false;
	}
	return m_inputFile->isComplete();
}

Imath::Box2i EXRImageReader::dataWindow()
{
	open( true );
	return m_inputFile->header().dataWindow();
}

Imath::Box2i EXRImageReader::displayWindow()
{
	open( true );
	return m_inputFile->header().displayWindow();
}

template<class T>
DataPtr EXRImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow, const Imf::Channel *channel )
{
	assert( channel );
	Imath::V2i pixelDimensions = dataWindow.size() + Imath::V2i( 1 );
	unsigned numPixels = pixelDimensions.x * pixelDimensions.y;

	typedef TypedData<vector<T> > DataType;
	typename DataType::Ptr data = new DataType;
	data->writable().resize( numPixels );

	Imath::Box2i fullDataWindow = this->dataWindow();
	if( fullDataWindow.min.x==dataWindow.min.x && fullDataWindow.max.x==dataWindow.max.x )
	{
		// the width we want to read matches the width in the file, so we can read straight
		// into the result buffer
		FrameBuffer frameBuffer;
		T *buffer00 = data->baseWritable() - dataWindow.min.y * pixelDimensions.x - fullDataWindow.min.x;
		Slice slice( channel->type, (char *)buffer00, sizeof(T), sizeof(T) * pixelDimensions.x );
		frameBuffer.insert( name.c_str(), slice );
		m_inputFile->setFrameBuffer( frameBuffer );
		// exr library will choose the best order to read scanlines automatically (increasing or decreasing)
		try
		{
			m_inputFile->readPixels( dataWindow.min.y, dataWindow.max.y );
		}
		catch( Iex::InputExc &e )
		{
			// so we can read incomplete files
			msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
		}
	}
	else
	{
		// widths don't match, we need to read into a temporary buffer and then transfer just
		// the bits we need into the result buffer.
		int numTmpPixels = fullDataWindow.size().x + 1;
		vector<T> tmpBuffer( numTmpPixels );
		T *tmpBufferTransferStart = &(tmpBuffer[0]) + dataWindow.min.x - fullDataWindow.min.x;
		size_t tmpBufferTransferLength = pixelDimensions.x * sizeof( T );
		T *transferDestination = &(data->writable()[0]);

		// slice has yStride of 0 so each successive scanline just overwrites the previous one
		Slice slice( channel->type, (char *)(&(tmpBuffer[0]) - fullDataWindow.min.x), sizeof(T), 0 );
		FrameBuffer frameBuffer;
		frameBuffer.insert( name.c_str(), slice );
		m_inputFile->setFrameBuffer( frameBuffer );

		int yStart = dataWindow.min.y;
		int yEnd = dataWindow.max.y;
		int yStep = 1;
		try
		{
			for( int y=yStart; y!=(yEnd+yStep); y+=yStep )
			{

					m_inputFile->readPixels( y );
					memcpy( (char *)transferDestination, (const char *)tmpBufferTransferStart, tmpBufferTransferLength );
					transferDestination += pixelDimensions.x;
			}
		}
		catch( Iex::InputExc &e )
		{
			// so we can read incomplete files
			msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
		}
	}

#ifndef NDEBUG
	for ( typename DataType::ValueType::const_iterator it = data->readable().begin(); it != data->readable().end(); ++it )
	{
		assert( *it == *it ); // Will fail iff NaN
	}
#endif

	return data;
}

DataPtr EXRImageReader::readChannel( const string &name, const Imath::Box2i &dataWindow )
{
	open( true );

	try
	{

		const Channel *channel = m_inputFile->header().channels().findChannel( name.c_str() );
		assert( channel );
		assert( channel->xSampling==1 ); /// \todo Support subsampling when we have a need for it
		assert( channel->ySampling==1 );

		switch( channel->type )
		{

			case UINT :
				BOOST_STATIC_ASSERT( sizeof( unsigned int ) == 4 );
				return readTypedChannel<unsigned int>( name, dataWindow, channel );

			case HALF :
				return readTypedChannel<half>( name, dataWindow, channel );

			case FLOAT :
				BOOST_STATIC_ASSERT( sizeof( float ) == 4 );
				return readTypedChannel<float>( name, dataWindow, channel );

			default:
				throw IOException( ( boost::format( "EXRImageReader : Unsupported data type for channel \"%s\"" ) % name ).str() );

		}

	}
	catch ( Exception &e )
	{
		throw;
	}
	catch( Iex::BaseExc &e )
	{
		std::string s = ( boost::format( "EXRImageReader : %s" ) % e.what() ).str();
		e.assign( s.c_str() );
		throw e;
	}
	catch ( std::exception &e )
	{
		throw IOException( ( boost::format( "EXRImageReader : %s" ) % e.what() ).str() );
	}
	catch ( ... )
	{
		throw IOException( "EXRImageReader : Unexpected error" );
	}
}

bool EXRImageReader::open( bool throwOnFailure )
{
	if( m_inputFile && fileName()==m_inputFile->fileName() )
	{
		// we already opened the right file successfully
		return true;
	}

	delete m_inputFile;
	m_inputFile = 0;

	try
	{
		m_inputFile = new Imf::InputFile( fileName().c_str() );
	}
	catch( ... )
	{
		delete m_inputFile;
		m_inputFile = 0;
		if( !throwOnFailure )
		{
			return false;
		}
		else
		{
			throw IOException( string( "Failed to open file \"" ) + fileName() + "\"" );
		}
	}

	return true;
}
<commit_msg>Fixed formatting<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "math.h"

#include "IECore/EXRImageReader.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/VectorTypedData.h"
#include "IECore/ImagePrimitive.h"
#include "IECore/FileNameParameter.h"
#include "IECore/BoxOps.h"
#include "IECore/MessageHandler.h"

#include "boost/format.hpp"

#include "OpenEXR/ImfInputFile.h"
#include "OpenEXR/ImfChannelList.h"
#include "OpenEXR/Iex.h"
#include "OpenEXR/ImfTestFile.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <cassert>

using namespace IECore;
using namespace Imf;
using namespace std;

using Imath::Box2i;

const Reader::ReaderDescription<EXRImageReader> EXRImageReader::g_readerDescription("exr");

EXRImageReader::EXRImageReader() :
		ImageReader( "EXRImageReader", "Reads ILM OpenEXR file format." ),
		m_inputFile( 0 )
{
}

EXRImageReader::EXRImageReader(const string &fileName) :
		ImageReader( "EXRImageReader", "Reads ILM OpenEXR file format." ),
		m_inputFile( 0 )
{
	m_fileNameParameter->setTypedValue( fileName );
	// added so that isComplete works and nothing changes on the class definition... the branch version should fix this.
	open();
	// added so that isComplete works and nothing changes on the class definition... the branch version should fix this.
	open();
}

EXRImageReader::~EXRImageReader()
{
	delete m_inputFile;
}

bool EXRImageReader::canRead( const string &fileName )
{
	return isOpenExrFile( fileName.c_str() );
}

void EXRImageReader::channelNames( vector<string> &names )
{
	open( true );

	const ChannelList &channels = m_inputFile->header().channels();
	names.clear();
	for( ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i )
	{
		names.push_back( i.name() );
	}
}

bool EXRImageReader::isComplete()
{
	if( !open() )
	{
		return false;
	}
	return m_inputFile->isComplete();
}

Imath::Box2i EXRImageReader::dataWindow()
{
	open( true );
	return m_inputFile->header().dataWindow();
}

Imath::Box2i EXRImageReader::displayWindow()
{
	open( true );
	return m_inputFile->header().displayWindow();
}

template<class T>
DataPtr EXRImageReader::readTypedChannel( const std::string &name, const Imath::Box2i &dataWindow, const Imf::Channel *channel )
{
	assert( channel );
	Imath::V2i pixelDimensions = dataWindow.size() + Imath::V2i( 1 );
	unsigned numPixels = pixelDimensions.x * pixelDimensions.y;

	typedef TypedData<vector<T> > DataType;
	typename DataType::Ptr data = new DataType;
	data->writable().resize( numPixels );

	Imath::Box2i fullDataWindow = this->dataWindow();
	if( fullDataWindow.min.x==dataWindow.min.x && fullDataWindow.max.x==dataWindow.max.x )
	{
		// the width we want to read matches the width in the file, so we can read straight
		// into the result buffer
		FrameBuffer frameBuffer;
		T *buffer00 = data->baseWritable() - dataWindow.min.y * pixelDimensions.x - fullDataWindow.min.x;
		Slice slice( channel->type, (char *)buffer00, sizeof(T), sizeof(T) * pixelDimensions.x );
		frameBuffer.insert( name.c_str(), slice );
		m_inputFile->setFrameBuffer( frameBuffer );
		// exr library will choose the best order to read scanlines automatically (increasing or decreasing)
		try
		{
			m_inputFile->readPixels( dataWindow.min.y, dataWindow.max.y );
		}
		catch( Iex::InputExc &e )
		{
			// so we can read incomplete files
			msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
		}
	}
	else
	{
		// widths don't match, we need to read into a temporary buffer and then transfer just
		// the bits we need into the result buffer.
		int numTmpPixels = fullDataWindow.size().x + 1;
		vector<T> tmpBuffer( numTmpPixels );
		T *tmpBufferTransferStart = &(tmpBuffer[0]) + dataWindow.min.x - fullDataWindow.min.x;
		size_t tmpBufferTransferLength = pixelDimensions.x * sizeof( T );
		T *transferDestination = &(data->writable()[0]);

		// slice has yStride of 0 so each successive scanline just overwrites the previous one
		Slice slice( channel->type, (char *)(&(tmpBuffer[0]) - fullDataWindow.min.x), sizeof(T), 0 );
		FrameBuffer frameBuffer;
		frameBuffer.insert( name.c_str(), slice );
		m_inputFile->setFrameBuffer( frameBuffer );

		int yStart = dataWindow.min.y;
		int yEnd = dataWindow.max.y;
		int yStep = 1;
		try
		{
			for( int y=yStart; y!=(yEnd+yStep); y+=yStep )
			{
				m_inputFile->readPixels( y );
				memcpy( (char *)transferDestination, (const char *)tmpBufferTransferStart, tmpBufferTransferLength );
				transferDestination += pixelDimensions.x;
			}
		}
		catch( Iex::InputExc &e )
		{
			// so we can read incomplete files
			msg( Msg::Warning, "EXRImageReader::readChannel", e.what() );
		}
	}

#ifndef NDEBUG
	for ( typename DataType::ValueType::const_iterator it = data->readable().begin(); it != data->readable().end(); ++it )
	{
		assert( *it == *it ); // Will fail iff NaN
	}
#endif

	return data;
}

DataPtr EXRImageReader::readChannel( const string &name, const Imath::Box2i &dataWindow )
{
	open( true );

	try
	{

		const Channel *channel = m_inputFile->header().channels().findChannel( name.c_str() );
		assert( channel );
		assert( channel->xSampling==1 ); /// \todo Support subsampling when we have a need for it
		assert( channel->ySampling==1 );

		switch( channel->type )
		{

			case UINT :
				BOOST_STATIC_ASSERT( sizeof( unsigned int ) == 4 );
				return readTypedChannel<unsigned int>( name, dataWindow, channel );

			case HALF :
				return readTypedChannel<half>( name, dataWindow, channel );

			case FLOAT :
				BOOST_STATIC_ASSERT( sizeof( float ) == 4 );
				return readTypedChannel<float>( name, dataWindow, channel );

			default:
				throw IOException( ( boost::format( "EXRImageReader : Unsupported data type for channel \"%s\"" ) % name ).str() );

		}

	}
	catch ( Exception &e )
	{
		throw;
	}
	catch( Iex::BaseExc &e )
	{
		std::string s = ( boost::format( "EXRImageReader : %s" ) % e.what() ).str();
		e.assign( s.c_str() );
		throw e;
	}
	catch ( std::exception &e )
	{
		throw IOException( ( boost::format( "EXRImageReader : %s" ) % e.what() ).str() );
	}
	catch ( ... )
	{
		throw IOException( "EXRImageReader : Unexpected error" );
	}
}

bool EXRImageReader::open( bool throwOnFailure )
{
	if( m_inputFile && fileName()==m_inputFile->fileName() )
	{
		// we already opened the right file successfully
		return true;
	}

	delete m_inputFile;
	m_inputFile = 0;

	try
	{
		m_inputFile = new Imf::InputFile( fileName().c_str() );
	}
	catch( ... )
	{
		delete m_inputFile;
		m_inputFile = 0;
		if( !throwOnFailure )
		{
			return false;
		}
		else
		{
			throw IOException( string( "Failed to open file \"" ) + fileName() + "\"" );
		}
	}

	return true;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include <boost/python.hpp>
#include <cassert>

#include "boost/format.hpp"

#include "IECoreGL/IECoreGL.h"

#include "maya/MPxNode.h"
#include "maya/MPxLocatorNode.h"
#include "maya/MPxDeformerNode.h"
#include "maya/MPxObjectSet.h"
#include "maya/MPxFieldNode.h"
#include "maya/MGlobal.h"

#include "IECore/Parameterised.h"
#include "IECore/LevelFilteredMessageHandler.h"

#include "IECoreMaya/IECoreMaya.h"
#include "IECoreMaya/CacheSet.h"
#include "IECoreMaya/ParameterisedHolder.h"
#include "IECoreMaya/TransientParameterisedHolderNode.h"
#include "IECoreMaya/OpHolder.h"
#include "IECoreMaya/PythonCmd.h"
#include "IECoreMaya/ProceduralHolder.h"
#include "IECoreMaya/ProceduralHolderUI.h"
#include "IECoreMaya/SystemExitCmd.h"
#include "IECoreMaya/MessageHandler.h"
#include "IECoreMaya/ObjectData.h"
#include "IECoreMaya/ConverterHolder.h"
#include "IECoreMaya/ImageFile.h"
#include "IECoreMaya/ImageTextureNode.h"

namespace IECoreMaya
{

static unsigned long g_refCount = 0;

MStatus initialize(MFnPlugin &plugin)
{
	MStatus s = MS::kSuccess;

	if (g_refCount == 0)
	{

		if( MGlobal::mayaState()==MGlobal::kInteractive )
		{
			IECoreGL::init( true );
		}

		// register plugin

		s = plugin.registerData( ObjectData::typeName, ObjectData::id, ObjectData::creator);

		s = plugin.registerNode( "ieCacheSet", CacheSet::id, CacheSet::creator, CacheSet::initialize,
			MPxNode::kObjectSet );

		s = plugin.registerNode( ParameterisedHolderNode::typeName, ParameterisedHolderNode::id,
			ParameterisedHolderNode::creator, ParameterisedHolderNode::initialize );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderLocator::typeName, ParameterisedHolderLocator::id,
			ParameterisedHolderLocator::creator, ParameterisedHolderLocator::initialize, MPxNode::kLocatorNode );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderDeformer::typeName, ParameterisedHolderDeformer::id,
			ParameterisedHolderDeformer::creator, ParameterisedHolderDeformer::initialize, MPxNode::kDeformerNode );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderField::typeName, ParameterisedHolderField::id,
			ParameterisedHolderField::creator, ParameterisedHolderField::initialize, MPxNode::kFieldNode );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderSet::typeName, ParameterisedHolderSet::id,
			ParameterisedHolderSet::creator, ParameterisedHolderSet::initialize, MPxNode::kObjectSet );
		assert( s );

		s = plugin.registerShape( ParameterisedHolderSurfaceShape::typeName, ParameterisedHolderSurfaceShape::id,
			ParameterisedHolderSurfaceShape::creator, ParameterisedHolderSurfaceShape::initialize, ProceduralHolderUI::creator );
		assert( s );

		s = plugin.registerShape( ParameterisedHolderComponentShape::typeName, ParameterisedHolderComponentShape::id,
			ParameterisedHolderComponentShape::creator, ParameterisedHolderComponentShape::initialize, ProceduralHolderUI::creator );
		assert( s );

		s = plugin.registerShape( "ieProceduralHolder", ProceduralHolder::id,
			ProceduralHolder::creator, ProceduralHolder::initialize, ProceduralHolderUI::creator );
		assert( s );

		s = plugin.registerNode( "ieOpHolderNode", OpHolderNode::id,
			OpHolderNode::creator, OpHolderNode::initialize );
		assert( s );

		s = plugin.registerNode( "ieConverterHolder", ConverterHolder::id,
			ConverterHolder::creator, ConverterHolder::initialize );
		assert( s );

		s = plugin.registerNode( TransientParameterisedHolderNode::typeName, TransientParameterisedHolderNode::id,
			TransientParameterisedHolderNode::creator, TransientParameterisedHolderNode::initialize );
		assert( s );

		const MString texture2dClassify( "texture/2d" );
		s = plugin.registerNode( "ieImageTexture", ImageTextureNode::id, ImageTextureNode::creator, ImageTextureNode::initialize,	MPxNode::kDependNode, &texture2dClassify );
		assert( s );

		s = plugin.registerCommand( "iePython", PythonCmd::creator, PythonCmd::newSyntax );
		PythonCmd::initialize();

		s = plugin.registerCommand( "ieSystemExit", SystemExitCmd::creator );

		MStringArray imageFileExtensions;
		imageFileExtensions.append( "exr" );

		s = plugin.registerImageFile( "ieImageFile", ImageFile::creator, imageFileExtensions);
		assert( s );

		/// \todo This may well need to change, depending on how we allow people to install
		/// the mel files.
		MString cmd = "source \"IECoreMaya/IECoreMaya.mel\";";
		s = MGlobal::executeCommand(cmd);

		if( !getenv( "IECOREMAYA_DISABLEOUTPUTREDIRECTION" ) )
		{
			IECore::MessageHandlerPtr h = new IECoreMaya::MessageHandler;
			h = new IECore::LevelFilteredMessageHandler( h, IECore::LevelFilteredMessageHandler::defaultLevel() );
			IECore::MessageHandler::pushHandler( h );
		}
	}

	g_refCount ++;

	return s;
}

MStatus uninitialize(MFnPlugin &plugin)
{
	MStatus s = MS::kSuccess;

	assert( g_refCount > 0 );

	g_refCount --;

	if (g_refCount == 0)
	{
		// unregister plugin

		s = plugin.deregisterNode( CacheSet::id );
		s = plugin.deregisterNode( ParameterisedHolderNode::id );
		s = plugin.deregisterNode( ParameterisedHolderLocator::id );
		s = plugin.deregisterNode( ParameterisedHolderDeformer::id );
		s = plugin.deregisterNode( ParameterisedHolderField::id );
		s = plugin.deregisterNode( ParameterisedHolderSet::id );
		s = plugin.deregisterNode( ParameterisedHolderSurfaceShape::id );
		s = plugin.deregisterNode( ParameterisedHolderComponentShape::id );
		s = plugin.deregisterNode( ProceduralHolder::id );
		s = plugin.deregisterNode( OpHolderNode::id );
		s = plugin.deregisterNode( ConverterHolder::id );
		s = plugin.deregisterNode( TransientParameterisedHolderNode::id );
		s = plugin.deregisterNode( ImageTextureNode::id );

		s = plugin.deregisterCommand( "iePython" );
		s = plugin.deregisterCommand( "ieSystemExit" );
		PythonCmd::uninitialize();

		s = plugin.deregisterData( ObjectData::id );

		s = plugin.deregisterImageFile( "ieImageFile" );

		// \todo Should we also pop our message handler here if we pushed one in initialize?
		// We're not doing that for now as IECore.Log.setLogLevel messes with the balancing of the
		// stack so i'm not sure popping is a good idea. Also even if we fix that then there's no real
		// guarantee that we're popping the one we pushed (other people could have pushed their own
		// handlers since ours, and not popped 'em). Not sure - maybe we need some guidelines as to
		// the nesting of handlers?
	}

	return s;
}

}
<commit_msg>Removed accidental check-in<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include <boost/python.hpp>
#include <cassert>

#include "boost/format.hpp"

#include "IECoreGL/IECoreGL.h"

#include "maya/MPxNode.h"
#include "maya/MPxLocatorNode.h"
#include "maya/MPxDeformerNode.h"
#include "maya/MPxObjectSet.h"
#include "maya/MPxFieldNode.h"
#include "maya/MGlobal.h"

#include "IECore/Parameterised.h"
#include "IECore/LevelFilteredMessageHandler.h"

#include "IECoreMaya/IECoreMaya.h"
#include "IECoreMaya/CacheSet.h"
#include "IECoreMaya/ParameterisedHolder.h"
#include "IECoreMaya/TransientParameterisedHolderNode.h"
#include "IECoreMaya/OpHolder.h"
#include "IECoreMaya/PythonCmd.h"
#include "IECoreMaya/ProceduralHolder.h"
#include "IECoreMaya/ProceduralHolderUI.h"
#include "IECoreMaya/SystemExitCmd.h"
#include "IECoreMaya/MessageHandler.h"
#include "IECoreMaya/ObjectData.h"
#include "IECoreMaya/ConverterHolder.h"
#include "IECoreMaya/ImageFile.h"

namespace IECoreMaya
{

static unsigned long g_refCount = 0;

MStatus initialize(MFnPlugin &plugin)
{
	MStatus s = MS::kSuccess;

	if (g_refCount == 0)
	{

		if( MGlobal::mayaState()==MGlobal::kInteractive )
		{
			IECoreGL::init( true );
		}

		// register plugin

		s = plugin.registerData( ObjectData::typeName, ObjectData::id, ObjectData::creator);

		s = plugin.registerNode( "ieCacheSet", CacheSet::id, CacheSet::creator, CacheSet::initialize,
			MPxNode::kObjectSet );

		s = plugin.registerNode( ParameterisedHolderNode::typeName, ParameterisedHolderNode::id,
			ParameterisedHolderNode::creator, ParameterisedHolderNode::initialize );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderLocator::typeName, ParameterisedHolderLocator::id,
			ParameterisedHolderLocator::creator, ParameterisedHolderLocator::initialize, MPxNode::kLocatorNode );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderDeformer::typeName, ParameterisedHolderDeformer::id,
			ParameterisedHolderDeformer::creator, ParameterisedHolderDeformer::initialize, MPxNode::kDeformerNode );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderField::typeName, ParameterisedHolderField::id,
			ParameterisedHolderField::creator, ParameterisedHolderField::initialize, MPxNode::kFieldNode );
		assert( s );

		s = plugin.registerNode( ParameterisedHolderSet::typeName, ParameterisedHolderSet::id,
			ParameterisedHolderSet::creator, ParameterisedHolderSet::initialize, MPxNode::kObjectSet );
		assert( s );

		s = plugin.registerShape( ParameterisedHolderSurfaceShape::typeName, ParameterisedHolderSurfaceShape::id,
			ParameterisedHolderSurfaceShape::creator, ParameterisedHolderSurfaceShape::initialize, ProceduralHolderUI::creator );
		assert( s );

		s = plugin.registerShape( ParameterisedHolderComponentShape::typeName, ParameterisedHolderComponentShape::id,
			ParameterisedHolderComponentShape::creator, ParameterisedHolderComponentShape::initialize, ProceduralHolderUI::creator );
		assert( s );

		s = plugin.registerShape( "ieProceduralHolder", ProceduralHolder::id,
			ProceduralHolder::creator, ProceduralHolder::initialize, ProceduralHolderUI::creator );
		assert( s );

		s = plugin.registerNode( "ieOpHolderNode", OpHolderNode::id,
			OpHolderNode::creator, OpHolderNode::initialize );
		assert( s );

		s = plugin.registerNode( "ieConverterHolder", ConverterHolder::id,
			ConverterHolder::creator, ConverterHolder::initialize );
		assert( s );

		s = plugin.registerNode( TransientParameterisedHolderNode::typeName, TransientParameterisedHolderNode::id,
			TransientParameterisedHolderNode::creator, TransientParameterisedHolderNode::initialize );
		assert( s );

		s = plugin.registerCommand( "iePython", PythonCmd::creator, PythonCmd::newSyntax );
		PythonCmd::initialize();

		s = plugin.registerCommand( "ieSystemExit", SystemExitCmd::creator );

		MStringArray imageFileExtensions;
		imageFileExtensions.append( "exr" );

		s = plugin.registerImageFile( "ieImageFile", ImageFile::creator, imageFileExtensions);
		assert( s );

		/// \todo This may well need to change, depending on how we allow people to install
		/// the mel files.
		MString cmd = "source \"IECoreMaya/IECoreMaya.mel\";";
		s = MGlobal::executeCommand(cmd);

		if( !getenv( "IECOREMAYA_DISABLEOUTPUTREDIRECTION" ) )
		{
			IECore::MessageHandlerPtr h = new IECoreMaya::MessageHandler;
			h = new IECore::LevelFilteredMessageHandler( h, IECore::LevelFilteredMessageHandler::defaultLevel() );
			IECore::MessageHandler::pushHandler( h );
		}
	}

	g_refCount ++;

	return s;
}

MStatus uninitialize(MFnPlugin &plugin)
{
	MStatus s = MS::kSuccess;

	assert( g_refCount > 0 );

	g_refCount --;

	if (g_refCount == 0)
	{
		// unregister plugin

		s = plugin.deregisterNode( CacheSet::id );
		s = plugin.deregisterNode( ParameterisedHolderNode::id );
		s = plugin.deregisterNode( ParameterisedHolderLocator::id );
		s = plugin.deregisterNode( ParameterisedHolderDeformer::id );
		s = plugin.deregisterNode( ParameterisedHolderField::id );
		s = plugin.deregisterNode( ParameterisedHolderSet::id );
		s = plugin.deregisterNode( ParameterisedHolderSurfaceShape::id );
		s = plugin.deregisterNode( ParameterisedHolderComponentShape::id );
		s = plugin.deregisterNode( ProceduralHolder::id );
		s = plugin.deregisterNode( OpHolderNode::id );
		s = plugin.deregisterNode( ConverterHolder::id );
		s = plugin.deregisterNode( TransientParameterisedHolderNode::id );

		s = plugin.deregisterCommand( "iePython" );
		s = plugin.deregisterCommand( "ieSystemExit" );
		PythonCmd::uninitialize();

		s = plugin.deregisterData( ObjectData::id );

		s = plugin.deregisterImageFile( "ieImageFile" );

		// \todo Should we also pop our message handler here if we pushed one in initialize?
		// We're not doing that for now as IECore.Log.setLogLevel messes with the balancing of the
		// stack so i'm not sure popping is a good idea. Also even if we fix that then there's no real
		// guarantee that we're popping the one we pushed (other people could have pushed their own
		// handlers since ours, and not popped 'em). Not sure - maybe we need some guidelines as to
		// the nesting of handlers?
	}

	return s;
}

}
<|endoftext|>


<commit_before>#ifndef THREADPOOL_BASE_HPP_
#define THREADPOOL_BASE_HPP_

#include <queue>
#include <stdexcept>
#include <future>

#include "ThreadManager.hh"

template<class T>
class ThreadPool_base {
public:
    enum class state {
      STOP = 0,
      PAUSE,
      START
    };
public:
    ThreadPool_base(unsigned int nbThreads,
                    ThreadManager& manager) :
  threadRefCount(0)
  , manager(manager)
  , status(state::STOP)
  , maxParallelism(nbThreads) {
      if (nbThreads == 0)
        throw std::out_of_range("The ThreadPool must have at least a thread");
    };

    virtual ~ThreadPool_base() {
      if (this->status.load(std::memory_order_seq_cst) != state::STOP) {
        this->stop();
      }
    };

public:
    std::pair<bool, std::string>
    start() {
      if (this->status.load(std::memory_order_seq_cst) != state::STOP) {
          return std::make_pair(false, "ThreadPool has already been started");
      }

      status.store(state::START, std::memory_order_seq_cst);       // we can now exectue tasks
      return std::make_pair(true, "");
    };

    std::pair<bool, std::string> pause() {
      if (this->status.load(std::memory_order_seq_cst) != state::START) {
          return std::make_pair(false, "ThreadPool is not started");
      }
      this->status.store(state::PAUSE, std::memory_order_acquire);
      return std::make_pair(true, "");
    };

    std::pair<bool, std::string> unpause() {
      if (this->status.load(std::memory_order_seq_cst) != state::PAUSE) {
          return std::make_pair(false, "ThreadPool is not paused");
      }
      status.store(state::START, std::memory_order_acquire);
      return std::make_pair(true, "");
    }
    std::pair<bool, std::string>
    stop() {
      if (this->status.load(std::memory_order_seq_cst) == state::STOP) {
          return std::make_pair(false, "ThreadPool is already stopped");
      }
      this->status.store(state::STOP, std::memory_order_acquire);
      return std::make_pair(true, "");
    };

public:
  template<class F, class... Args>
  auto addTask(F&& function, Args&&... args)
      -> std::future<typename std::result_of<F(Args...)>::type> {
      using return_type = typename std::result_of<F(Args...)>::type;

      if (this->status.load(std::memory_order_release) == state::STOP)
        throw std::runtime_error("Can't add task on stopped ThreadPool");

      auto task = std::make_shared<std::packaged_task<return_type()> >
              (std::bind(std::forward<F>(function), std::forward<Args>(args)...));
      std::future<return_type> futureResult = task->get_future();

      {
        std::lock_guard<std::mutex> guard(this->taskMutex);
        taskContainer.emplace([this, task]() {
          (*task)();
          {
            std::lock_guard<std::mutex> guardRef(this->refCountMutex);
            --(this->threadRefCount);
          }
          this->startTask();
        });
      }
    bool startCondition;
    {
      std::lock_guard<std::mutex> guardRef(this->refCountMutex);
      startCondition = this->threadRefCount < this->maxParallelism;
    }
    if (startCondition) {
      this->startTask();
    }
    return futureResult;
  }

private:
  void
  startTask() {
    std::lock_guard<std::mutex> guardRef(this->refCountMutex);
    std::lock_guard<std::mutex> guardTask(this->taskMutex);
    std::function<void ()> task;

    if (this->taskContainer.empty()
    || this->threadRefCount >= this->maxParallelism) // Handle later or already handled
      return ;
    ++this->threadRefCount;
    task = std::move(this->taskContainer.front());
    this->taskContainer.pop();
    manager.runTask(task);
  }

protected:
    std::queue<T> taskContainer;
    std::mutex    taskMutex;

    unsigned int  threadRefCount;
    std::mutex    refCountMutex;

    ThreadManager& manager;

private:
    std::atomic<state> 	status;
    unsigned int      maxParallelism;
};

#endif /* end of include guard: THREADPOOL_BASE_HPP_ */
<commit_msg>Don't start task in the pool is paused and restart the system when unpause<commit_after>#ifndef THREADPOOL_BASE_HPP_
#define THREADPOOL_BASE_HPP_

#include <queue>
#include <stdexcept>
#include <future>

#include "ThreadManager.hh"

template<class T>
class ThreadPool_base {
public:
    enum class state {
      STOP = 0,
      PAUSE,
      START
    };
public:
    ThreadPool_base(unsigned int nbThreads,
                    ThreadManager& manager) :
  threadRefCount(0)
  , manager(manager)
  , status(state::STOP)
  , maxParallelism(nbThreads) {
      if (nbThreads == 0)
        throw std::invalid_argument("The ThreadPool must have at least a thread");
    };

    virtual ~ThreadPool_base() {
      if (this->status.load(std::memory_order_seq_cst) != state::STOP) {
        this->stop();
      }
    };

public:
    std::pair<bool, std::string>
    start() {
      if (this->status.load(std::memory_order_seq_cst) != state::STOP) {
          return std::make_pair(false, "ThreadPool has already been started");
      }

      status.store(state::START, std::memory_order_seq_cst);       // we can now exectue tasks
      return std::make_pair(true, "");
    };

    std::pair<bool, std::string> pause() {
      if (this->status.load(std::memory_order_seq_cst) != state::START) {
          return std::make_pair(false, "ThreadPool is not started");
      }
      this->status.store(state::PAUSE, std::memory_order_acquire);
      return std::make_pair(true, "");
    };

    std::pair<bool, std::string> unpause() {
      if (this->status.load(std::memory_order_seq_cst) != state::PAUSE) {
          return std::make_pair(false, "ThreadPool is not paused");
      }
      status.store(state::START, std::memory_order_acquire);
      this->startTask();
      return std::make_pair(true, "");
    }
    std::pair<bool, std::string>
    stop() {
      if (this->status.load(std::memory_order_seq_cst) == state::STOP) {
          return std::make_pair(false, "ThreadPool is already stopped");
      }
      this->status.store(state::STOP, std::memory_order_acquire);
      return std::make_pair(true, "");
    };

public:
  template<class F, class... Args>
  auto addTask(F&& function, Args&&... args)
    -> std::future<typename std::result_of<F(Args...)>::type> {
    using return_type = typename std::result_of<F(Args...)>::type;

    if (this->status.load(std::memory_order_release) == state::STOP)
      throw std::runtime_error("Can't add task on stopped ThreadPool");

    auto task = std::make_shared<std::packaged_task<return_type()> >
            (std::bind(std::forward<F>(function), std::forward<Args>(args)...));
    std::future<return_type> futureResult = task->get_future();

    {
      std::lock_guard<std::mutex> guard(this->taskMutex);
      taskContainer.emplace([this, task]() {
        (*task)();
        {
          std::lock_guard<std::mutex> guardRef(this->refCountMutex);
          --(this->threadRefCount);
        }
        this->startTask();
      });
    }
    this->startTask();
    return futureResult;
  }

private:
  void
  startTask() {
    std::lock_guard<std::mutex> guardRef(this->refCountMutex);
    std::lock_guard<std::mutex> guardTask(this->taskMutex);
    std::function<void ()> task;

    if (this->taskContainer.empty()
    || this->threadRefCount >= this->maxParallelism
    || this->status.load(std::memory_order_release) != state::START) // Handle later or already handled
      return ;
    ++this->threadRefCount;
    task = std::move(this->taskContainer.front());
    this->taskContainer.pop();
    manager.runTask(task);
  }

protected:
    std::queue<T> taskContainer;
    std::mutex    taskMutex;

    unsigned int  threadRefCount;
    std::mutex    refCountMutex;

    ThreadManager& manager;

private:
    std::atomic<state> 	status;
    unsigned int      maxParallelism;
};

#endif /* end of include guard: THREADPOOL_BASE_HPP_ */
<|endoftext|>


<commit_before>///
/// @file      calculator.hpp
/// @brief     calculator::eval(const std::string&) evaluates an integer
///            arithmetic expression and returns the result. If an error
///            occurs a calculator::error exception is thrown.
///            <https://github.com/kimwalisch/calculator>
/// @author    Kim Walisch, <kim.walisch@gmail.com>
/// @copyright Copyright (C) 2013-2018 Kim Walisch
/// @license   BSD 2-Clause, https://opensource.org/licenses/BSD-2-Clause
/// @version   1.3
///
/// == Supported operators ==
///
/// OPERATOR    NAME                     ASSOCIATIVITY    PRECEDENCE
///
/// |           Bitwise Inclusive OR    Left               4
/// ^           Bitwise Exclusive OR    Left               5
/// &           Bitwise AND             Left               6
/// <<          Shift Left              Left               9
/// >>          Shift Right             Left               9
/// +           Addition                Left              10
/// -           Subtraction             Left              10
/// *           Multiplication          Left              20
/// /           Division                Left              20
/// %           Modulo                  Left              20
/// **          Raise to power          Right             30
/// e, E        Scientific notation     Right             40
/// ~           Unary complement        Left              99
///
/// The operator precedence has been set according to (uses the C and
/// C++ operator precedence): https://en.wikipedia.org/wiki/Order_of_operations
/// Operators with higher precedence are evaluated before operators
/// with relatively lower precedence. Unary operators are set to have
/// the highest precedence, this is not strictly correct for the power
/// operator e.g. "-3**2" = 9 but a lot of software tools (Bash shell,
/// Microsoft Excel, GNU bc, ...) use the same convention.
///
/// == Examples of valid expressions ==
///
/// "65536 >> 15"                       = 2
/// "2**16"                             = 65536
/// "(0 + 0xDf234 - 1000)*3/2%999"      = 828
/// "-(2**2**2**2)"                     = -65536
/// "(0 + ~(0xDF234 & 1000) *3) /-2"    = 817
/// "(2**16) + (1 << 16) >> 0X5"        = 4096
/// "5*-(2**(9+7))/3+5*(1 & 0xFf123)"   = -109221
///
/// == About the algorithm used ==
///
/// calculator::eval(std::string&) relies on the ExpressionParser
/// class which is a simple C++ operator precedence parser with infix
/// notation for integer arithmetic expressions.
/// ExpressionParser has its roots in a JavaScript parser published
/// at: http://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/114961#114961
/// The same author has also published an article about his operator
/// precedence algorithm at PerlMonks:
/// http://www.perlmonks.org/?node_id=554516
///

#ifndef CALCULATOR_HPP
#define CALCULATOR_HPP

#include <stdexcept>
#include <string>
#include <sstream>
#include <stack>
#include <cstddef>
#include <cctype>

namespace calculator
{

/// calculator::eval() throws a calculator::error if it fails
/// to evaluate the expression string.
///
class error : public std::runtime_error
{
public:
  error(const std::string& expr, const std::string& message)
    : std::runtime_error(message),
      expr_(expr)
  { }
#if __cplusplus >= 201103L || \
    (defined(_MSC_VER) && _MSC_VER >= 1800)
  ~error() { }
#else
  ~error() throw() { }
#endif
  std::string expression() const
  {
    return expr_;
  }
private:
  std::string expr_;
};

template <typename T>
class ExpressionParser
{
public:
  /// Evaluate an integer arithmetic expression and return its result.
  /// @throw error if parsing fails.
  ///
  T eval(const std::string& expr)
  {
    T result = 0;
    index_ = 0;
    expr_ = expr;
    try
    {
      result = parseExpr();
      if (!isEnd())
        unexpected();
    }
    catch (const calculator::error&)
    {
      while(!stack_.empty())
        stack_.pop();
      throw;
    }
    return result;
  }

  /// Get the integer value of a character.
  T eval(char c)
  {
    std::string expr(1, c);
    return eval(expr);
  }

private:
  enum
  {
    OPERATOR_NULL,
    OPERATOR_BITWISE_OR,     /// |
    OPERATOR_BITWISE_XOR,    /// ^
    OPERATOR_BITWISE_AND,    /// &
    OPERATOR_BITWISE_SHL,    /// <<
    OPERATOR_BITWISE_SHR,    /// >>
    OPERATOR_ADDITION,       /// +
    OPERATOR_SUBTRACTION,    /// -
    OPERATOR_MULTIPLICATION, /// *
    OPERATOR_DIVISION,       /// /
    OPERATOR_MODULO,         /// %
    OPERATOR_POWER,          /// **
    OPERATOR_EXPONENT        /// e, E
  };

  struct Operator
  {
    /// Operator, one of the OPERATOR_* enum definitions
    int op;
    int precedence;
    /// 'L' = left or 'R' = right
    int associativity;
    Operator(int opr, int prec, int assoc) :
      op(opr),
      precedence(prec),
      associativity(assoc)
    { }
  };

  struct OperatorValue
  {
    Operator op;
    T value;
    OperatorValue(const Operator& opr, T val) :
      op(opr),
      value(val)
    { }
    int getPrecedence() const
    {
      return op.precedence;
    }
    bool isNull() const
    {
      return op.op == OPERATOR_NULL;
    }
  };

  /// Expression string
  std::string expr_;
  /// Current expression index, incremented whilst parsing
  std::size_t index_;
  /// The current operator and its left value
  /// are pushed onto the stack if the operator on
  /// top of the stack has lower precedence.
  std::stack<OperatorValue> stack_;

  /// Exponentiation by squaring, x^n.
  static T pow(T x, T n)
  {
    T res = 1;

    while (n > 0)
    {
      if (n % 2 != 0)
      {
        res *= x;
        n -= 1;
      }
      n /= 2;

      if (n > 0)
        x *= x;
    }

    return res;
  }

  T checkZero(T value) const
  {
    if (value == 0)
    {
      std::string divOperators("/%");
      std::size_t division = expr_.find_last_of(divOperators, index_ - 2);
      std::ostringstream msg;
      msg << "Parser error: division by 0";
      if (division != std::string::npos)
        msg << " (error token is \""
            << expr_.substr(division, expr_.size() - division)
            << "\")";
      throw calculator::error(expr_, msg.str());
    }
    return value;
  }

  T calculate(T v1, T v2, const Operator& op) const
  {
    switch (op.op)
    {
      case OPERATOR_BITWISE_OR:     return v1 | v2;
      case OPERATOR_BITWISE_XOR:    return v1 ^ v2;
      case OPERATOR_BITWISE_AND:    return v1 & v2;
      case OPERATOR_BITWISE_SHL:    return v1 << v2;
      case OPERATOR_BITWISE_SHR:    return v1 >> v2;
      case OPERATOR_ADDITION:       return v1 + v2;
      case OPERATOR_SUBTRACTION:    return v1 - v2;
      case OPERATOR_MULTIPLICATION: return v1 * v2;
      case OPERATOR_DIVISION:       return v1 / checkZero(v2);
      case OPERATOR_MODULO:         return v1 % checkZero(v2);
      case OPERATOR_POWER:          return pow(v1, v2);
      case OPERATOR_EXPONENT:       return v1 * pow(10, v2);
      default:                      return 0;
    }
  }

  bool isEnd() const
  {
    return index_ >= expr_.size();
  }

  /// Returns the character at the current expression index or
  /// 0 if the end of the expression is reached.
  ///
  char getCharacter() const
  {
    if (!isEnd())
      return expr_[index_];
    return 0;
  }

  /// Parse str at the current expression index.
  /// @throw error if parsing fails.
  ///
  void expect(const std::string& str)
  {
    if (expr_.compare(index_, str.size(), str) != 0)
      unexpected();
    index_ += str.size();
  }

  void unexpected() const
  {
    std::ostringstream msg;
    msg << "Syntax error: unexpected token \""
        << expr_.substr(index_, expr_.size() - index_)
        << "\" at index "
        << index_;
    throw calculator::error(expr_, msg.str());
  }

  /// Eat all white space characters at the
  /// current expression index.
  ///
  void eatSpaces()
  {
    while (std::isspace(getCharacter()) != 0)
      index_++;
  }

  /// Parse a binary operator at the current expression index.
  /// @return Operator with precedence and associativity.
  ///
  Operator parseOp()
  {
    eatSpaces();
    switch (getCharacter())
    {
      case '|': index_++;     return Operator(OPERATOR_BITWISE_OR,      4, 'L');
      case '^': index_++;     return Operator(OPERATOR_BITWISE_XOR,     5, 'L');
      case '&': index_++;     return Operator(OPERATOR_BITWISE_AND,     6, 'L');
      case '<': expect("<<"); return Operator(OPERATOR_BITWISE_SHL,     9, 'L');
      case '>': expect(">>"); return Operator(OPERATOR_BITWISE_SHR,     9, 'L');
      case '+': index_++;     return Operator(OPERATOR_ADDITION,       10, 'L');
      case '-': index_++;     return Operator(OPERATOR_SUBTRACTION,    10, 'L');
      case '/': index_++;     return Operator(OPERATOR_DIVISION,       20, 'L');
      case '%': index_++;     return Operator(OPERATOR_MODULO,         20, 'L');
      case '*': index_++; if (getCharacter() != '*')
                              return Operator(OPERATOR_MULTIPLICATION, 20, 'L');
                index_++;     return Operator(OPERATOR_POWER,          30, 'R');
      case 'e': index_++;     return Operator(OPERATOR_EXPONENT,       40, 'R');
      case 'E': index_++;     return Operator(OPERATOR_EXPONENT,       40, 'R');
      default :               return Operator(OPERATOR_NULL,            0, 'L');
    }
  }

  static T toInteger(char c)
  {
    if (c >= '0' && c <= '9') return c -'0';
    if (c >= 'a' && c <= 'f') return c -'a' + 0xa;
    if (c >= 'A' && c <= 'F') return c -'A' + 0xa;
    T noDigit = 0xf + 1;
    return noDigit;
  }

  T getInteger() const
  {
    return toInteger(getCharacter());
  }

  T parseDecimal()
  {
    T value = 0;
    for (T d; (d = getInteger()) <= 9; index_++)
      value = value * 10 + d;
    return value;
  }

  T parseHex()
  {
    index_ = index_ + 2;
    T value = 0;
    for (T h; (h = getInteger()) <= 0xf; index_++)
      value = value * 0x10 + h;
    return value;
  }

  bool isHex() const
  {
    if (index_ + 2 < expr_.size())
    {
      char x = expr_[index_ + 1];
      char h = expr_[index_ + 2];
      return (std::tolower(x) == 'x' && toInteger(h) <= 0xf);
    }
    return false;
  }

  /// Parse an integer value at the current expression index.
  /// The unary `+', `-' and `~' operators and opening
  /// parentheses `(' cause recursion.
  ///
  T parseValue()
  {
    T val = 0;
    eatSpaces();
    switch (getCharacter())
    {
      case '0': if (isHex())
                  val = parseHex();
                else
                  val = parseDecimal();
                break;
      case '1': case '2': case '3': case '4': case '5':
      case '6': case '7': case '8': case '9':
                val = parseDecimal();
                break;
      case '(': index_++;
                val = parseExpr();
                eatSpaces();
                if (getCharacter() != ')')
                {
                  if (!isEnd())
                    unexpected();
                  throw calculator::error(expr_, "Syntax error: `)' expected at end of expression");
                }
                index_++; break;
      case '~': index_++; val = ~parseValue(); break;
      case '+': index_++; val =  parseValue(); break;
      case '-': index_++; val =  parseValue() * static_cast<T>(-1);
                break;
      default : if (!isEnd())
                  unexpected();
                throw calculator::error(expr_, "Syntax error: value expected at end of expression");
    }
    return val;
  }

  /// Parse all operations of the current parenthesis
  /// level and the levels above, when done
  /// return the result (value).
  ///
  T parseExpr()
  {
    stack_.push(OperatorValue(Operator(OPERATOR_NULL, 0, 'L'), 0));
    // first parse value on the left
    T value = parseValue();

    while (!stack_.empty())
    {
      // parse an operator (+, -, *, ...)
      Operator op(parseOp());
      while (op.precedence  < stack_.top().getPrecedence() || (
             op.precedence == stack_.top().getPrecedence() &&
             op.associativity == 'L'))
      {
        // end reached
        if (stack_.top().isNull())
        {
          stack_.pop();
          return value;
        }
        // do the calculation ("reduce"), producing a new value
        value = calculate(stack_.top().value, value, stack_.top().op);
        stack_.pop();
      }

      // store on stack_ and continue parsing ("shift")
      stack_.push(OperatorValue(op, value));
      // parse value on the right
      value = parseValue();
    }
    return 0;
  }
};

template <typename T>
inline T eval(const std::string& expression)
{
  ExpressionParser<T> parser;
  return parser.eval(expression);
}

template <typename T>
inline T eval(char c)
{
  ExpressionParser<T> parser;
  return parser.eval(c);
}

inline int eval(const std::string& expression)
{
  return eval<int>(expression);
}

inline int eval(char c)
{
  return eval<int>(c);
}

} // namespace calculator

#endif
<commit_msg>Silence clang-cl -Wdeprecated warning<commit_after>///
/// @file      calculator.hpp
/// @brief     calculator::eval(const std::string&) evaluates an integer
///            arithmetic expression and returns the result. If an error
///            occurs a calculator::error exception is thrown.
///            <https://github.com/kimwalisch/calculator>
/// @author    Kim Walisch, <kim.walisch@gmail.com>
/// @copyright Copyright (C) 2013-2018 Kim Walisch
/// @license   BSD 2-Clause, https://opensource.org/licenses/BSD-2-Clause
/// @version   1.4
///
/// == Supported operators ==
///
/// OPERATOR    NAME                     ASSOCIATIVITY    PRECEDENCE
///
/// |           Bitwise Inclusive OR    Left               4
/// ^           Bitwise Exclusive OR    Left               5
/// &           Bitwise AND             Left               6
/// <<          Shift Left              Left               9
/// >>          Shift Right             Left               9
/// +           Addition                Left              10
/// -           Subtraction             Left              10
/// *           Multiplication          Left              20
/// /           Division                Left              20
/// %           Modulo                  Left              20
/// **          Raise to power          Right             30
/// e, E        Scientific notation     Right             40
/// ~           Unary complement        Left              99
///
/// The operator precedence has been set according to (uses the C and
/// C++ operator precedence): https://en.wikipedia.org/wiki/Order_of_operations
/// Operators with higher precedence are evaluated before operators
/// with relatively lower precedence. Unary operators are set to have
/// the highest precedence, this is not strictly correct for the power
/// operator e.g. "-3**2" = 9 but a lot of software tools (Bash shell,
/// Microsoft Excel, GNU bc, ...) use the same convention.
///
/// == Examples of valid expressions ==
///
/// "65536 >> 15"                       = 2
/// "2**16"                             = 65536
/// "(0 + 0xDf234 - 1000)*3/2%999"      = 828
/// "-(2**2**2**2)"                     = -65536
/// "(0 + ~(0xDF234 & 1000) *3) /-2"    = 817
/// "(2**16) + (1 << 16) >> 0X5"        = 4096
/// "5*-(2**(9+7))/3+5*(1 & 0xFf123)"   = -109221
///
/// == About the algorithm used ==
///
/// calculator::eval(std::string&) relies on the ExpressionParser
/// class which is a simple C++ operator precedence parser with infix
/// notation for integer arithmetic expressions.
/// ExpressionParser has its roots in a JavaScript parser published
/// at: http://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/114961#114961
/// The same author has also published an article about his operator
/// precedence algorithm at PerlMonks:
/// http://www.perlmonks.org/?node_id=554516
///

#ifndef CALCULATOR_HPP
#define CALCULATOR_HPP

#include <stdexcept>
#include <string>
#include <sstream>
#include <stack>
#include <cstddef>
#include <cctype>

namespace calculator
{

/// calculator::eval() throws a calculator::error if it fails
/// to evaluate the expression string.
///
class error : public std::runtime_error
{
public:
  error(const std::string& expr, const std::string& message)
    : std::runtime_error(message),
      expr_(expr)
  { }
#if __cplusplus < 201103L
  ~error() throw() { }
#endif
  std::string expression() const
  {
    return expr_;
  }
private:
  std::string expr_;
};

template <typename T>
class ExpressionParser
{
public:
  /// Evaluate an integer arithmetic expression and return its result.
  /// @throw error if parsing fails.
  ///
  T eval(const std::string& expr)
  {
    T result = 0;
    index_ = 0;
    expr_ = expr;
    try
    {
      result = parseExpr();
      if (!isEnd())
        unexpected();
    }
    catch (const calculator::error&)
    {
      while(!stack_.empty())
        stack_.pop();
      throw;
    }
    return result;
  }

  /// Get the integer value of a character.
  T eval(char c)
  {
    std::string expr(1, c);
    return eval(expr);
  }

private:
  enum
  {
    OPERATOR_NULL,
    OPERATOR_BITWISE_OR,     /// |
    OPERATOR_BITWISE_XOR,    /// ^
    OPERATOR_BITWISE_AND,    /// &
    OPERATOR_BITWISE_SHL,    /// <<
    OPERATOR_BITWISE_SHR,    /// >>
    OPERATOR_ADDITION,       /// +
    OPERATOR_SUBTRACTION,    /// -
    OPERATOR_MULTIPLICATION, /// *
    OPERATOR_DIVISION,       /// /
    OPERATOR_MODULO,         /// %
    OPERATOR_POWER,          /// **
    OPERATOR_EXPONENT        /// e, E
  };

  struct Operator
  {
    /// Operator, one of the OPERATOR_* enum definitions
    int op;
    int precedence;
    /// 'L' = left or 'R' = right
    int associativity;
    Operator(int opr, int prec, int assoc) :
      op(opr),
      precedence(prec),
      associativity(assoc)
    { }
  };

  struct OperatorValue
  {
    Operator op;
    T value;
    OperatorValue(const Operator& opr, T val) :
      op(opr),
      value(val)
    { }
    int getPrecedence() const
    {
      return op.precedence;
    }
    bool isNull() const
    {
      return op.op == OPERATOR_NULL;
    }
  };

  /// Expression string
  std::string expr_;
  /// Current expression index, incremented whilst parsing
  std::size_t index_;
  /// The current operator and its left value
  /// are pushed onto the stack if the operator on
  /// top of the stack has lower precedence.
  std::stack<OperatorValue> stack_;

  /// Exponentiation by squaring, x^n.
  static T pow(T x, T n)
  {
    T res = 1;

    while (n > 0)
    {
      if (n % 2 != 0)
      {
        res *= x;
        n -= 1;
      }
      n /= 2;

      if (n > 0)
        x *= x;
    }

    return res;
  }

  T checkZero(T value) const
  {
    if (value == 0)
    {
      std::string divOperators("/%");
      std::size_t division = expr_.find_last_of(divOperators, index_ - 2);
      std::ostringstream msg;
      msg << "Parser error: division by 0";
      if (division != std::string::npos)
        msg << " (error token is \""
            << expr_.substr(division, expr_.size() - division)
            << "\")";
      throw calculator::error(expr_, msg.str());
    }
    return value;
  }

  T calculate(T v1, T v2, const Operator& op) const
  {
    switch (op.op)
    {
      case OPERATOR_BITWISE_OR:     return v1 | v2;
      case OPERATOR_BITWISE_XOR:    return v1 ^ v2;
      case OPERATOR_BITWISE_AND:    return v1 & v2;
      case OPERATOR_BITWISE_SHL:    return v1 << v2;
      case OPERATOR_BITWISE_SHR:    return v1 >> v2;
      case OPERATOR_ADDITION:       return v1 + v2;
      case OPERATOR_SUBTRACTION:    return v1 - v2;
      case OPERATOR_MULTIPLICATION: return v1 * v2;
      case OPERATOR_DIVISION:       return v1 / checkZero(v2);
      case OPERATOR_MODULO:         return v1 % checkZero(v2);
      case OPERATOR_POWER:          return pow(v1, v2);
      case OPERATOR_EXPONENT:       return v1 * pow(10, v2);
      default:                      return 0;
    }
  }

  bool isEnd() const
  {
    return index_ >= expr_.size();
  }

  /// Returns the character at the current expression index or
  /// 0 if the end of the expression is reached.
  ///
  char getCharacter() const
  {
    if (!isEnd())
      return expr_[index_];
    return 0;
  }

  /// Parse str at the current expression index.
  /// @throw error if parsing fails.
  ///
  void expect(const std::string& str)
  {
    if (expr_.compare(index_, str.size(), str) != 0)
      unexpected();
    index_ += str.size();
  }

  void unexpected() const
  {
    std::ostringstream msg;
    msg << "Syntax error: unexpected token \""
        << expr_.substr(index_, expr_.size() - index_)
        << "\" at index "
        << index_;
    throw calculator::error(expr_, msg.str());
  }

  /// Eat all white space characters at the
  /// current expression index.
  ///
  void eatSpaces()
  {
    while (std::isspace(getCharacter()) != 0)
      index_++;
  }

  /// Parse a binary operator at the current expression index.
  /// @return Operator with precedence and associativity.
  ///
  Operator parseOp()
  {
    eatSpaces();
    switch (getCharacter())
    {
      case '|': index_++;     return Operator(OPERATOR_BITWISE_OR,      4, 'L');
      case '^': index_++;     return Operator(OPERATOR_BITWISE_XOR,     5, 'L');
      case '&': index_++;     return Operator(OPERATOR_BITWISE_AND,     6, 'L');
      case '<': expect("<<"); return Operator(OPERATOR_BITWISE_SHL,     9, 'L');
      case '>': expect(">>"); return Operator(OPERATOR_BITWISE_SHR,     9, 'L');
      case '+': index_++;     return Operator(OPERATOR_ADDITION,       10, 'L');
      case '-': index_++;     return Operator(OPERATOR_SUBTRACTION,    10, 'L');
      case '/': index_++;     return Operator(OPERATOR_DIVISION,       20, 'L');
      case '%': index_++;     return Operator(OPERATOR_MODULO,         20, 'L');
      case '*': index_++; if (getCharacter() != '*')
                              return Operator(OPERATOR_MULTIPLICATION, 20, 'L');
                index_++;     return Operator(OPERATOR_POWER,          30, 'R');
      case 'e': index_++;     return Operator(OPERATOR_EXPONENT,       40, 'R');
      case 'E': index_++;     return Operator(OPERATOR_EXPONENT,       40, 'R');
      default :               return Operator(OPERATOR_NULL,            0, 'L');
    }
  }

  static T toInteger(char c)
  {
    if (c >= '0' && c <= '9') return c -'0';
    if (c >= 'a' && c <= 'f') return c -'a' + 0xa;
    if (c >= 'A' && c <= 'F') return c -'A' + 0xa;
    T noDigit = 0xf + 1;
    return noDigit;
  }

  T getInteger() const
  {
    return toInteger(getCharacter());
  }

  T parseDecimal()
  {
    T value = 0;
    for (T d; (d = getInteger()) <= 9; index_++)
      value = value * 10 + d;
    return value;
  }

  T parseHex()
  {
    index_ = index_ + 2;
    T value = 0;
    for (T h; (h = getInteger()) <= 0xf; index_++)
      value = value * 0x10 + h;
    return value;
  }

  bool isHex() const
  {
    if (index_ + 2 < expr_.size())
    {
      char x = expr_[index_ + 1];
      char h = expr_[index_ + 2];
      return (std::tolower(x) == 'x' && toInteger(h) <= 0xf);
    }
    return false;
  }

  /// Parse an integer value at the current expression index.
  /// The unary `+', `-' and `~' operators and opening
  /// parentheses `(' cause recursion.
  ///
  T parseValue()
  {
    T val = 0;
    eatSpaces();
    switch (getCharacter())
    {
      case '0': if (isHex())
                  val = parseHex();
                else
                  val = parseDecimal();
                break;
      case '1': case '2': case '3': case '4': case '5':
      case '6': case '7': case '8': case '9':
                val = parseDecimal();
                break;
      case '(': index_++;
                val = parseExpr();
                eatSpaces();
                if (getCharacter() != ')')
                {
                  if (!isEnd())
                    unexpected();
                  throw calculator::error(expr_, "Syntax error: `)' expected at end of expression");
                }
                index_++; break;
      case '~': index_++; val = ~parseValue(); break;
      case '+': index_++; val =  parseValue(); break;
      case '-': index_++; val =  parseValue() * static_cast<T>(-1);
                break;
      default : if (!isEnd())
                  unexpected();
                throw calculator::error(expr_, "Syntax error: value expected at end of expression");
    }
    return val;
  }

  /// Parse all operations of the current parenthesis
  /// level and the levels above, when done
  /// return the result (value).
  ///
  T parseExpr()
  {
    stack_.push(OperatorValue(Operator(OPERATOR_NULL, 0, 'L'), 0));
    // first parse value on the left
    T value = parseValue();

    while (!stack_.empty())
    {
      // parse an operator (+, -, *, ...)
      Operator op(parseOp());
      while (op.precedence  < stack_.top().getPrecedence() || (
             op.precedence == stack_.top().getPrecedence() &&
             op.associativity == 'L'))
      {
        // end reached
        if (stack_.top().isNull())
        {
          stack_.pop();
          return value;
        }
        // do the calculation ("reduce"), producing a new value
        value = calculate(stack_.top().value, value, stack_.top().op);
        stack_.pop();
      }

      // store on stack_ and continue parsing ("shift")
      stack_.push(OperatorValue(op, value));
      // parse value on the right
      value = parseValue();
    }
    return 0;
  }
};

template <typename T>
inline T eval(const std::string& expression)
{
  ExpressionParser<T> parser;
  return parser.eval(expression);
}

template <typename T>
inline T eval(char c)
{
  ExpressionParser<T> parser;
  return parser.eval(c);
}

inline int eval(const std::string& expression)
{
  return eval<int>(expression);
}

inline int eval(char c)
{
  return eval<int>(c);
}

} // namespace calculator

#endif
<|endoftext|>