text:
/*
	This file is part of cpp-ethereum.
	cpp-ethereum 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 3 of the License, or
	(at your option) any later version.
	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ClientModel.cpp
 * @author Yann yann@ethdev.com
 * @author Arkadiy Paronyan arkadiy@ethdev.com
 * @date 2015
 * Ethereum IDE client.
 */

// Make sure boost/asio.hpp is included before windows.h.
#include <boost/asio.hpp>

#include "ClientModel.h"
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include <QStandardPaths>
#include <jsonrpccpp/server.h>
#include <libethcore/CommonJS.h>
#include <libethcore/KeyManager.h>
#include <libsolidity/ast/Types.h>
#include <libethereum/Transaction.h>
#include <libwebthree/WebThree.h>
#include <libdevcore/FixedHash.h>
#include <libweb3jsonrpc/MemoryDB.h>
#include <libweb3jsonrpc/Web3.h>
#include "DebuggingStateWrapper.h"
#include "Exceptions.h"
#include "QContractDefinition.h"
#include "QVariableDeclaration.h"
#include "ContractCallDataEncoder.h"
#include "CodeModel.h"
#include "QEther.h"
#include "Web3Server.h"
#include "MixClient.h"

using namespace dev;
using namespace dev::eth;
using namespace dev::solidity;
using namespace std;

namespace dev
{
namespace mix
{

class RpcConnector: public jsonrpc::AbstractServerConnector
{
public:
	virtual bool StartListening() override { return true; }
	virtual bool StopListening() override { return true; }
	virtual bool SendResponse(string const& _response, void*) override
	{
		m_response = QString::fromStdString(_response);
		return true;
	}
	QString response() const { return m_response; }

private:
	QString m_response;
};

ClientModel::ClientModel():
	m_running(false)
{
	qRegisterMetaType<QBigInt*>("QBigInt*");
	qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>");
	qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
	qRegisterMetaType<QSolidityType*>("QSolidityType*");
	qRegisterMetaType<QMachineState*>("QMachineState");
	qRegisterMetaType<QInstruction*>("QInstruction");
	qRegisterMetaType<QCode*>("QCode");
	qRegisterMetaType<QCallData*>("QCallData");
	qRegisterMetaType<RecordLogEntry*>("RecordLogEntry*");
}

ClientModel::~ClientModel()
{
	m_runFuture.waitForFinished();
	QString tempDir = (
		m_dbpath != QString() ?
		QStandardPaths::writableLocation(QStandardPaths::TempLocation) + m_dbpath :
		QStandardPaths::writableLocation(QStandardPaths::TempLocation)
	);
	QDir dir(tempDir);
	dir.removeRecursively();
}

void ClientModel::manageException() const
{
	try
	{
		throw;
	}
	catch (boost::exception const& _e)
	{
		cerr << boost::diagnostic_information(_e);
		emit internalError("Internal error: " + QString::fromStdString(boost::diagnostic_information(_e)));
	}
	catch (exception const& _e)
	{
		cerr << _e.what();
		emit internalError("Internal error: " + QString::fromStdString(_e.what()));
	}
	catch (...)
	{
		cerr << boost::current_exception_diagnostic_information();
		emit internalError("Internal error: " + QString::fromStdString(boost::current_exception_diagnostic_information()));
	}
}

void ClientModel::init(QString _dbpath)
{
	try
	{
		m_dbpath = _dbpath;
		if (m_dbpath.isEmpty())
			m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
		else
			m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString() + m_dbpath.toStdString()));

		m_ethAccounts = make_shared<FixedAccountHolder>([=](){return m_client.get();}, vector<KeyPair>());
		auto ethFace = new Web3Server(*m_client.get(), *m_ethAccounts.get());
		m_web3Server.reset(new ModularServer<rpc::EthFace, rpc::DBFace, rpc::Web3Face>(ethFace, new rpc::MemoryDB(), new rpc::Web3()));
		m_rpcConnectorId = m_web3Server->addConnector(new RpcConnector());
		connect(ethFace, &Web3Server::newTransaction, this, [=]() {
			onNewTransaction(RecordLogEntry::TxSource::Web3);
		}, Qt::DirectConnection);
	}
	catch (...)
	{
		manageException();
	}
}

QString ClientModel::apiCall(QString const& _message)
{
	try
	{
		auto connector = static_cast<RpcConnector*>(m_web3Server->connector(m_rpcConnectorId));
		connector->OnRequest(_message.toStdString(), nullptr);
		return connector->response();
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

void ClientModel::mine()
{
	try
	{
		if (m_mining)
			return;
		m_mining = true;
		emit miningStarted();
		emit miningStateChanged();
		m_runFuture = QtConcurrent::run([=]()
		{
			try
			{
				this_thread::sleep_for(chrono::seconds(1)); //ensure not future time
				m_client->mine();
				m_mining = false;
				emit newBlock();
				emit miningComplete();
			}
			catch (...)
			{
				m_mining = false;
				cerr << boost::current_exception_diagnostic_information();
				emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
				return;
			}
			emit miningStateChanged();
		});
	}
	catch (...)
	{
		manageException();
		m_mining = false;
	}
}

QString ClientModel::newSecret()
{
	try
	{
		KeyPair a = KeyPair::create();
		return QString::fromStdString(dev::toHex(a.secret().ref()));
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

QString ClientModel::address(QString const& _secret)
{
	try
	{
		return QString::fromStdString(dev::toHex(KeyPair(Secret(_secret.toStdString())).address().ref()));
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

QString ClientModel::toHex(QString const& _int)
{
	try
	{
		return QString::fromStdString(dev::toHex(dev::u256(_int.toStdString())));
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

QString ClientModel::encodeAbiString(QString _string)
{
	try
	{
		ContractCallDataEncoder encoder;
		return QString::fromStdString(dev::toHex(encoder.encodeBytes(_string)));
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

QString ClientModel::encodeStringParam(QString const& _param)
{
	try
	{
		ContractCallDataEncoder encoder;
		return QString::fromStdString(dev::toHex(encoder.encodeStringParam(_param, 32)));
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

QStringList ClientModel::encodeParams(QVariant const& _param, QString const& _contract, QString const& _function)
{
	QStringList ret;
	try
	{
		CompiledContract const* compilerRes = m_codeModel->contract(_contract);
		QList<QVariableDeclaration*> paramsList;
		shared_ptr<QContractDefinition> contractDef = compilerRes->sharedContract();
		if (_contract == _function)
			paramsList = contractDef->constructor()->parametersList();
		else
			for (QFunctionDefinition* tf: contractDef->functionsList())
				if (tf->name() == _function)
				{
					paramsList = tf->parametersList();
					break;
				}
		if (paramsList.length() > 0)
			for (QVariableDeclaration* var: paramsList)
			{
				ContractCallDataEncoder encoder;
				QSolidityType const* type = var->type();
				QVariant value = _param.toMap().value(var->name());
				encoder.encode(value, type->type());
				ret.push_back(QString::fromStdString(dev::toHex(encoder.encodedData())));
			}
	}
	catch (...)
	{
		manageException();
	}
	return ret;
}

QVariantMap ClientModel::contractAddresses() const
{
	QVariantMap res;
	try
	{
		for (auto const& c: m_contractAddresses)
		{
			res.insert(serializeToken(c.first), QString::fromStdString(toJS(c.second))); //key will be like <Contract - 0>
			res.insert(c.first.first, QString::fromStdString(toJS(c.second))); //we keep name like Contract (compatibility with old projects)
		}
	}
	catch (...)
	{
		manageException();
	}
	return res;
}

QVariantList ClientModel::gasCosts() const
{
	QVariantList res;
	try
	{
		for (auto const& c: m_gasCosts)
			res.append(QVariant::fromValue(static_cast<int>(c)));
	}
	catch (...)
	{
		manageException();
	}
	return res;
}

void ClientModel::addAccount(QString const& _secret)
{
	try
	{
		KeyPair key(Secret(_secret.toStdString()));
		m_accountsSecret.push_back(key);
		Address address = key.address();
		m_accounts[address] = Account(u256(0), Account::NormalCreation);
		m_ethAccounts->setAccounts(m_accountsSecret);
	}
	catch (...)
	{
		manageException();
	}
}

QString ClientModel::resolveAddress(QString const& _secret)
{
	try
	{
		KeyPair key(Secret(_secret.toStdString()));
		return "0x" + QString::fromStdString(key.address().hex());
	}
	catch (...)
	{
		manageException();
		return QString();
	}
}

void ClientModel::setupScenario(QVariantMap _scenario)
{
	try
	{
		setupStarted();
		onStateReset();
		WriteGuard(x_queueTransactions);
		m_running = true;

		QVariantList blocks = _scenario.value("blocks").toList();
		QVariantList stateAccounts = _scenario.value("accounts").toList();
		QVariantList stateContracts = _scenario.value("contracts").toList();

		m_accounts.clear();
		m_accountsSecret.clear();
		for (auto const& b: stateAccounts)
		{
			QVariantMap account = b.toMap();
			Address address = {};
			if (account.contains("secret"))
			{
				KeyPair key(Secret(account.value("secret").toString().toStdString()));
				m_accountsSecret.push_back(key);
				address = key.address();
			}
			else if (account.contains("address"))
				address = Address(fromHex(account.value("address").toString().toStdString()));
			if (!address)
				continue;

			m_accounts[address] = Account(0, qvariant_cast<QEther*>(account.value("balance"))->toU256Wei(), Account::NormalCreation);
		}

		m_ethAccounts->setAccounts(m_accountsSecret);

		auto ethFace = new Web3Server(*m_client.get(), *m_ethAccounts.get());
		m_web3Server.reset(new ModularServer<rpc::EthFace, rpc::DBFace, rpc::Web3Face>(ethFace, new rpc::MemoryDB(), new rpc::Web3()));
		m_rpcConnectorId = m_web3Server->addConnector(new RpcConnector());
		connect(ethFace, &Web3Server::newTransaction, this, [=]() {
			onNewTransaction(RecordLogEntry::TxSource::Web3);
		}, Qt::DirectConnection);

		for (auto const& c: stateContracts)
		{
			QVariantMap contract = c.toMap();
			Address address = Address(fromHex(contract.value("address").toString().toStdString()));
			Account account(0, qvariant_cast<QEther*>(contract.value("balance"))->toU256Wei(), Account::ContractConception);
			bytes code = fromHex(contract.value("code").toString().toStdString());
			account.setCode(move(code));
			QVariantMap storageMap = contract.value("storage").toMap();
			for(auto s = storageMap.cbegin(); s != storageMap.cend(); ++s)
				account.setStorage(fromBigEndian<u256>(fromHex(s.key().toStdString())), fromBigEndian<u256>(fromHex(s.value().toString().toStdString())));

			m_accounts[address] = account;
		}

		bool trToExecute = false;
		for (auto const& b: blocks)
		{
			QVariantList transactions = b.toMap().value("transactions").toList();
			if (transactions.size() > 0)
			{
				m_queueTransactions.push_back(transactions);
				trToExecute = true;
			}
		}
		m_client->resetState(m_accounts, Secret(_scenario.value("miner").toMap().value("secret").toString().toStdString()));
		if (m_queueTransactions.count() > 0 && trToExecute)
		{
			m_executionCtx = ExecutionCtx::Rebuild;
			setupExecutionChain();
			processNextTransactions();
		}
		else
		{
			m_running = false;
			setupFinished();
		}
	}
	catch (...)
	{
		manageException();
		m_running = false;
	}
}

void ClientModel::setupExecutionChain()
{
	connect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions, Qt::QueuedConnection);
	connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection);
	connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection);
}

void ClientModel::stopExecution()
{
	disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions);
	disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock);
	disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution);
	m_running = false;
	if (m_executionCtx == ExecutionCtx::Rebuild)
		setupFinished();
	m_executionCtx = ExecutionCtx::Idle;
}

void ClientModel::finalizeBlock()
{
	if (m_queueTransactions.size() > 0)
		m_queueTransactions.pop_front();// pop last execution group. The last block is never mined (pending block)
	if (m_queueTransactions.size() > 0)
		mine();
	else
	{
		stopExecution();
		emit runComplete();
	}
}

TransactionSettings ClientModel::transaction(QVariant const& _tr) const
{
	QVariantMap transaction = _tr.toMap();
	QString contractId = transaction.value("contractId").toString();
	QString functionId = transaction.value("functionId").toString();
	bool gasAuto = transaction.value("gasAuto").toBool();
	u256 gas = 0;
	if (transaction.value("gas").data())
		gas = boost::get<u256>(qvariant_cast<QBigInt*>(transaction.value("gas"))->internalValue());
	else
		gasAuto = true;

	u256 value = (qvariant_cast<QEther*>(transaction.value("value")))->toU256Wei();
	u256 gasPrice = (qvariant_cast<QEther*>(transaction.value("gasPrice")))->toU256Wei();
	QString sender = transaction.value("sender").toString();
	bool isContractCreation = transaction.value("isContractCreation").toBool();
	bool isFunctionCall = transaction.value("isFunctionCall").toBool();
	if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later
		contractId = m_codeModel->contracts().keys()[0];
	Secret f = Secret(sender.toStdString());
	TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall);
	transactionSettings.parameterValues = transaction.value("parameters").toMap();
	if (contractId == functionId || functionId == "Constructor")
		transactionSettings.functionId.clear();
	return transactionSettings;
}

void ClientModel::processNextTransactions()
{
	WriteGuard(x_queueTransactions);
	vector<TransactionSettings> transactionSequence;
	for (auto const& t: m_queueTransactions.front())
	{
		TransactionSettings transactionSettings = transaction(t);
		transactionSequence.push_back(transactionSettings);
	}
	executeSequence(transactionSequence);
}

void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence)
{
	if (m_running)
	{
		qWarning() << "Waiting for current execution to complete";
		m_runFuture.waitForFinished();
	}
	emit runStarted();
	//run sequence
	m_runFuture = QtConcurrent::run([=]()
	{
		try
		{
			for (TransactionSettings const& transaction: _sequence)
			{
				pair<QString, int> ctrInstance = resolvePair(transaction.contractId);
				QString address = resolveToken(ctrInstance);
				if (!transaction.isFunctionCall)
				{
					callAddress(Address(address.toStdString()), bytes(), transaction);
					m_gasCosts.append(m_client->lastExecution().gasUsed);
					onNewTransaction(RecordLogEntry::TxSource::MixGui);
					continue;
				}
				ContractCallDataEncoder encoder;
				//encode data
				CompiledContract const* compilerRes = m_codeModel->contract(ctrInstance.first);
				QFunctionDefinition const* f = nullptr;
				shared_ptr<QContractDefinition> contractDef = compilerRes->sharedContract();
				if (transaction.functionId.isEmpty())
					f = contractDef->constructor();
				else
					for (QFunctionDefinition const* tf: contractDef->functionsList())
						if (tf->name() == transaction.functionId)
						{
							f = tf;
							break;
						}
				if (!f)
				{
					emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code."));
					return;
				}
				if (!transaction.functionId.isEmpty())
					encoder.encode(f);
				for (int k = 0; k < f->parametersList().length(); ++k) //QVariableDeclaration const* p: f->parametersList())
				{
					QVariableDeclaration const* p = f->parametersList().at(k);
					QSolidityType const* type = p->type();
					QVariant value;
					if (p->name().isEmpty())
						value = transaction.parameterValues.value(QString::number(k));
					else
						value = transaction.parameterValues.value(p->name());

					if (type->type().type == SolidityType::Type::Address)
					{
						if (type->array())
						{
							QJsonArray jsonDoc = QJsonDocument::fromJson(value.toString().toUtf8()).array();
							int k = 0;
							for (QJsonValue const& item: jsonDoc)
							{
								if (item.toString().startsWith("<"))
								{
									pair<QString, int> ctrParamInstance = resolvePair(item.toString());
									jsonDoc.replace(k, resolveToken(ctrParamInstance));
								}
								k++;
							}
							QJsonDocument doc(jsonDoc);
							value = QVariant(doc.toJson(QJsonDocument::Compact));
						}
						else if (value.toString().startsWith("<"))
						{
							pair<QString, int> ctrParamInstance = resolvePair(value.toString());
							value = QVariant(resolveToken(ctrParamInstance));
						}
					}
					encoder.encode(value, type->type());
				}

				if (transaction.functionId.isEmpty() || transaction.functionId == ctrInstance.first)
				{
					bytes param = encoder.encodedData();
					m_codeModel->linkLibraries(ctrInstance.first, m_deployedLibraries);
					eth::LinkerObject object = m_codeModel->contract(ctrInstance.first)->linkerObject();
					bytes contractCode = object.bytecode;
					if (!object.linkReferences.empty())
					{
						for (auto const& ref: object.linkReferences)
							emit runFailed(QString::fromStdString(ref.second));
						emit runFailed(ctrInstance.first + " deployment. Cannot link referenced libraries:");
					}
					contractCode.insert(contractCode.end(), param.begin(), param.end());
					Address newAddress = deployContract(contractCode, transaction);
					if (compilerRes->contract()->isLibrary())
						m_deployedLibraries[ctrInstance.first] = QString::fromStdString(newAddress.hex());
					else
					{
						pair<QString, int> contractToken = retrieveToken(transaction.contractId);
						m_contractAddresses[contractToken] = newAddress;
						m_contractNames[newAddress] = contractToken.first;
						contractAddressesChanged();
					}
				}
				else
				{
					auto contractAddressIter = m_contractAddresses.find(ctrInstance);
					if (contractAddressIter == m_contractAddresses.end())
					{
						emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId);
						return;
					}
					else
						callAddress(contractAddressIter->second, encoder.encodedData(), transaction);
				}
				m_gasCosts.append(m_client->lastExecution().gasUsed);
				gasCostsChanged();
				onNewTransaction(RecordLogEntry::TxSource::MixGui);
				TransactionException exception = m_client->lastExecution().excepted;
				if (exception != TransactionException::None)
					return;
			}
			emit runComplete();
		}
		catch(boost::exception const&)
		{
			cerr << boost::current_exception_diagnostic_information();
			emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
			return;
		}
		catch(exception const& e)
		{
			cerr << boost::current_exception_diagnostic_information();
			emit runFailed(e.what());
			return;
		}
		catch(...)
		{
			cerr << boost::current_exception_diagnostic_information();
			emit runFailed("Unknown Error");
			return;
		}
		emit runStateChanged();
	});
}

void ClientModel::executeTr(QVariantMap _tr)
{
	try
	{
		WriteGuard(x_queueTransactions);
		QVariantList trs;
		trs.push_back(_tr);
		m_queueTransactions.push_back(trs);
		if (!m_running)
		{
			m_running = true;
			m_executionCtx = ExecutionCtx::ExecuteTx;
			setupExecutionChain();
			processNextTransactions();
		}
	}
	catch (...)
	{
		manageException();
		m_running = false;
	}
}

pair<QString, int> ClientModel::resolvePair(QString const& _contractId)
{
	pair<QString, int> ret = make_pair(_contractId, 0);
	if (_contractId.startsWith("<") && _contractId.endsWith(">"))
	{
		QStringList values = ret.first.remove("<").remove(">").split(" - ");
		ret = make_pair(values[0], values[1].toUInt());
	}
	if (_contractId.startsWith("0x"))
		ret = make_pair(_contractId, -2);
	return ret;
}

QString ClientModel::resolveToken(pair<QString, int> const& _value)
{
	if (_value.second == -2) //-2: first contains a real address
		return _value.first;
	else if (m_contractAddresses.size() > 0 && m_contractAddresses.find(_value) != m_contractAddresses.end())
		return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref()));
	else
		return _value.first;
}

pair<QString, int> ClientModel::retrieveToken(QString const& _value)
{
	pair<QString, int> ret;
	ret.first = _value;
	ret.second = m_contractAddresses.size();
	return ret;
}

QString ClientModel::serializeToken(pair<QString, int> const& _value) const
{
	return "<" + _value.first + " - " + QString::number(_value.second) + ">";
}

void ClientModel::showDebugger()
{
	ExecutionResult last = m_client->lastExecution();
	showDebuggerForTransaction(last);
}

QVariantMap ClientModel::contractStorageByIndex(unsigned _index, QString const& _contractAddress)
{
	try
	{
		ExecutionResult e = m_client->execution(_index);
		if (!e.machineStates.empty())
		{
			MachineState state = e.machineStates.back();
			auto nameIter = m_contractNames.find(Address(_contractAddress.toStdString()));
			CompiledContract const* compilerRes = m_codeModel->contract(nameIter->second);
			return contractStorageByMachineState(state, compilerRes);
		}
		else
			return QVariantMap();
	}
	catch (...)
	{
		manageException();
		return QVariantMap();
	}
}

QVariantMap ClientModel::contractStorage(unordered_map<u256, u256> _storage, CompiledContract const* _contract)
{
	QVariantMap storage;
	try
	{
		QVariantList storageDeclarationList;
		QVariantMap storageValues;
		for (auto const& slot: _contract->storage())
		{
			for (auto const& stateVar: slot)
			{
				if (stateVar.type.name.startsWith("mapping"))
					continue; //mapping type not yet managed

				auto storageDec = new QVariableDeclaration(0, stateVar.name.toStdString(), stateVar.type);
				storageDeclarationList.push_back(QVariant::fromValue(storageDec));
				storageValues[storageDec->name()] = formatStorageValue(storageDec->type()->type(), _storage, stateVar.offset, stateVar.slot);
			}
		}
		storage["variables"] = storageDeclarationList;
		storage["values"] = storageValues;
	}
	catch (...)
	{
		manageException();
	}
	return storage;
}

QVariantMap ClientModel::contractStorageByMachineState(MachineState const& _state, CompiledContract const* _contract)
{
	try
	{
		return contractStorage(_state.storage, _contract);
	}
	catch (...)
	{
		manageException();
		return QVariantMap();
	}
}

void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t, QString const& _label)
{
	try
	{
		//we need to wrap states in a QObject before sending to QML.
		QDebugData* debugData = new QDebugData(_label);
		QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership);
		QList<QCode*> codes;
		QList<QHash<int, int>> codeMaps;
		QList<AssemblyItems> codeItems;
		QList<CompiledContract const*> contracts;
		for (MachineCode const& code: _t.executionCode)
		{
			QHash<int, int> codeMap;
			codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code, codeMap));
			codeMaps.push_back(move(codeMap));
			//try to resolve contract for source level debugging
			auto nameIter = m_contractNames.find(code.address);
			CompiledContract const* compilerRes = m_codeModel->contract(nameIter->second); //returned object is guaranteed to live till the end of event handler in main thread
			if (nameIter != m_contractNames.end() && compilerRes)
			{
				eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems();
				codes.back()->setDocument(compilerRes->documentId());
				codeItems.push_back(move(assemblyItems));
				contracts.push_back(compilerRes);
			}
			else
			{
				codeItems.push_back(AssemblyItems());
				contracts.push_back(nullptr);
			}
		}

		QList<QCallData*> data;
		for (bytes const& d: _t.transactionData)
			data.push_back(QMachineState::getDebugCallData(debugData, d));

		QVariantList states;
		QVariantList solCallStack;
		map<int, QVariableDeclaration*> solLocals; //<stack pos, decl>
		map<QString, SolidityDeclaration> localDecl; //<name, solDecl>
		unsigned prevInstructionIndex = 0;

		for (MachineState const& s: _t.machineStates)
		{
			int instructionIndex = codeMaps[s.codeIndex][static_cast<unsigned>(s.curPC)];
			QSolState* solState = nullptr;
			if (!codeItems[s.codeIndex].empty() && contracts[s.codeIndex])
			{
				CompiledContract const* contract = contracts[s.codeIndex];
				AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex];

				if (instruction.type() == eth::Push)
				{
					//register new local variable initialization
					auto localIter = contract->locals().find(LocationPair(instruction.location().start, instruction.location().end));
					if (localIter != contract->locals().end())
					{
						if (localDecl.find(localIter.value().name) == localDecl.end())
						{
							localDecl[localIter.value().name] = localIter.value();
							solLocals[s.stack.size()] = new QVariableDeclaration(debugData, localIter.value().name.toStdString(), localIter.value().type);
						}
					}
				}

				if (instruction.type() == eth::Tag)
				{
					//track calls into functions
					AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex];
					QString functionName = m_codeModel->resolveFunctionName(instruction.location());
					if (!functionName.isEmpty() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty()))
						solCallStack.push_front(QVariant::fromValue(functionName));
					else if (prevInstruction.getJumpType() == AssemblyItem::JumpType::OutOfFunction && !solCallStack.empty())
					{
						solCallStack.pop_front();
						solLocals.clear();
						localDecl.clear();
					}
				}

				//format solidity context values
				QVariantMap locals;
				QVariantList localDeclarations;
				QVariantMap localValues;
				for (auto l: solLocals)
					if (l.first < (int)s.stack.size())
					{
						if (l.second->type()->name().startsWith("mapping"))
							break; //mapping type not yet managed
						localDeclarations.push_back(QVariant::fromValue(l.second));
						DataLocation loc = l.second->dataLocation();
						if (loc == DataLocation::Memory)
						{
							u256 pos = s.stack[l.first];
							u256 offset = pos;
							localValues[l.second->name()] = formatMemoryValue(l.second->type()->type(), s.memory, offset);
						}
						else if (loc == DataLocation::Storage)
							localValues[l.second->name()] = formatStorageValue(
								l.second->type()->type(),
								s.storage,
								localDecl[l.second->name()].offset,
								localDecl[l.second->name()].slot
							);
						else
						{
							ContractCallDataEncoder decoder;
							u256 pos = 0;
							bytes val = toBigEndian(s.stack[l.first]);
							localValues[l.second->name()] = decoder.decodeType(l.second->type()->type(), val, pos);
						}
					}
				locals["variables"] = localDeclarations;
				locals["values"] = localValues;

				QVariantMap storage = contractStorageByMachineState(s, contract);
				prevInstructionIndex = instructionIndex;

				// filter out locations that match whole function or contract
				SourceLocation instructionLocation = instruction.location();
				QString source;
				if (instructionLocation.sourceName)
					source = QString::fromUtf8(instructionLocation.sourceName->c_str());
				if (m_codeModel->isContractOrFunctionLocation(instructionLocation))
					instructionLocation = dev::SourceLocation(-1, -1, instructionLocation.sourceName);

				solState = new QSolState(debugData, move(storage), move(solCallStack), move(locals), instructionLocation.start, instructionLocation.end, source);
			}
			states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState)));
		}

		debugData->setStates(move(states));
		debugDataReady(debugData);
	}
	catch (...)
	{
		manageException();
	}
}

QVariant ClientModel::formatMemoryValue(SolidityType const& _type, bytes const& _value, u256& _offset)
{
	ContractCallDataEncoder decoder;
	return decoder.formatMemoryValue(_type, _value, _offset);
}

QVariant ClientModel::formatStorageValue(SolidityType const& _type, unordered_map<u256, u256> const& _storage, unsigned const& _offset, u256 const& _slot)
{
	ContractCallDataEncoder decoder;
	u256 endSlot;
	return decoder.formatStorageValue(_type, _storage, _offset, _slot, endSlot);
}

void ClientModel::emptyRecord()
{
	try
	{
		debugDataReady(new QDebugData());
	}
	catch (...)
	{
		manageException();
	}
}

void ClientModel::debugRecord(unsigned _index, QString const& _label)
{
	try
	{
		ExecutionResult e = m_client->execution(_index);
		showDebuggerForTransaction(e, _label);
	}
	catch (...)
	{
		manageException();
	}
}

Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction)
{
	eth::TransactionSkeleton ts;
	ts.creation = true;
	ts.value = _ctrTransaction.value;
	ts.data = _code;
	ts.gas = _ctrTransaction.gas;
	ts.gasPrice = _ctrTransaction.gasPrice;
	ts.from = toAddress(_ctrTransaction.sender);
	return m_client->submitTransaction(ts, _ctrTransaction.sender, _ctrTransaction.gasAuto).second;
}

void ClientModel::callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{
	eth::TransactionSkeleton ts;
	ts.creation = false;
	ts.value = _tr.value;
	ts.to = _contract;
	ts.data = _data;
	ts.gas = _tr.gas;
	ts.gasPrice = _tr.gasPrice;
	ts.from = toAddress(_tr.sender);
	m_client->submitTransaction(ts, _tr.sender, _tr.gasAuto);
}

RecordLogEntry* ClientModel::lastBlock() const
{
	try
	{
		eth::BlockHeader blockInfo = m_client->blockInfo();
		stringstream strGas;
		strGas << blockInfo.gasUsed();
		stringstream strNumber;
		strNumber << blockInfo.number();
		RecordLogEntry* record =  new RecordLogEntry(
			0,
			QString::fromStdString(strNumber.str()),
			tr(" - Block - "),
			tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))),
			QString(),
			QString(),
			QString(),
			false,
			RecordLogEntry::RecordType::Block,
			QString::fromStdString(strGas.str()),
			"0",
			"0",
			QString(),
			tr("Block"),
			QVariantMap(),
			QVariantMap(),
			QVariantList(),
			RecordLogEntry::TxSource::MixGui,
			RecordLogEntry::TransactionException::None
		);
		QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
		return record;
	}
	catch (...)
	{
		manageException();
		return nullptr;
	}
}

QString ClientModel::lastTransactionIndex() const
{
	return m_lastTransactionIndex;
}

void ClientModel::onStateReset()
{
	try
	{
		m_contractAddresses.clear();
		m_contractNames.clear();
		m_stdContractAddresses.clear();
		m_stdContractNames.clear();
		m_queueTransactions.clear();
		m_gasCosts.clear();
		m_deployedLibraries.clear();
		m_mining = false;
		m_running = false;
		emit stateCleared();
	}
	catch (...)
	{
		manageException();
	}
}

void ClientModel::onNewTransaction(RecordLogEntry::TxSource _source)
{
	try
	{
		ExecutionResult const& tr = m_client->lastExecution();

		RecordLogEntry::TransactionException exception = RecordLogEntry::TransactionException::None;
		switch (tr.excepted)
		{
		case TransactionException::None:
			break;
		case TransactionException::NotEnoughCash:
		{
			exception = RecordLogEntry::TransactionException::NotEnoughCash;
			emit runFailed("Insufficient balance");
			return;
		}
		case TransactionException::OutOfGasIntrinsic:
		case TransactionException::OutOfGasBase:
		case TransactionException::OutOfGas:
		{
			exception = RecordLogEntry::TransactionException::OutOfGas;
			emit runFailed("Not enough gas");
			return;
		}
		case TransactionException::BlockGasLimitReached:
		{
			exception = RecordLogEntry::TransactionException::BlockGasLimitReached;
			emit runFailed("Block gas limit reached");
			return;
		}
		case TransactionException::BadJumpDestination:
		{
			exception = RecordLogEntry::TransactionException::BadJumpDestination;
			emit runFailed("Solidity exception (bad jump)");
			return;
		}
		case TransactionException::OutOfStack:
		{
			exception = RecordLogEntry::TransactionException::OutOfStack;
			emit runFailed("Out of stack");
			return;
		}

		case TransactionException::StackUnderflow:
		{
			exception = RecordLogEntry::TransactionException::StackUnderflow;
			emit runFailed("Stack underflow");
			return;
		}
			//these should not happen in mix
		case TransactionException::Unknown:
		case TransactionException::BadInstruction:
		case TransactionException::InvalidSignature:
		case TransactionException::InvalidNonce:
		case TransactionException::InvalidFormat:
		case TransactionException::BadRLP:
		{
			exception = RecordLogEntry::TransactionException::Unknown;
			emit runFailed("Internal execution error");
			return;
		}

		}

		unsigned block = m_client->number() + 1;
		unsigned recordIndex = tr.executonIndex;
		QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex);

		QString address = QString::fromStdString(toJS(tr.address));
		QString value = QString::fromStdString(toString(tr.value));
		QString contract = address;
		QString function;
		QString returned;
		QString gasUsed;
		QString gasRequired;
		QString gasRefunded;

		bool creation = (bool)tr.contractAddress;

		if (!tr.isCall())
		{
			gasUsed = QString::fromStdString(toString(tr.gasUsed));
			gasRequired = QString::fromStdString(toString(tr.gasRequired));
			gasRefunded = QString::fromStdString(toString(tr.gasRefunded));
		}

		//TODO: handle value transfer
		FixedHash<4> functionHash;
		bool abi = false;
		if (creation)
		{
			//contract creation
			function = QObject::tr("Constructor");
			address = QObject::tr("(Create contract)");
		}
		else
		{
			//transaction/call
			if (tr.inputParameters.size() >= 4)
			{
				functionHash = FixedHash<4>(tr.inputParameters.data(), FixedHash<4>::ConstructFromPointer);
				function = QString::fromStdString(toJS(functionHash));
				abi = true;
			}
			else
				function = QObject::tr("<none>");
		}

		if (creation)
			returned = QString::fromStdString(toJS(tr.contractAddress));

		Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress;
		auto contractAddressIter = m_contractNames.find(contractAddress);
		QVariantMap inputParameters;
		QVariantMap returnParameters;
		QVariantList logs;
		if (contractAddressIter != m_contractNames.end())
		{
			ContractCallDataEncoder encoder;
			CompiledContract const* compilerRes = m_codeModel->contract(contractAddressIter->second);
			const QContractDefinition* def = compilerRes->contract();
			contract = def->name();
			if (creation)
				function = contract;
			if (abi)
			{
				QFunctionDefinition const* funcDef = def->getFunction(functionHash);
				if (funcDef)
				{
					function = funcDef->name();
					QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.result.output);
					returned += "(";
					returned += returnValues.join(", ");
					returned += ")";

					QStringList returnParams = encoder.decode(funcDef->returnParameters(), tr.result.output);
					for (int k = 0; k < returnParams.length(); ++k)
						returnParameters.insert(funcDef->returnParameters().at(k)->name(), returnParams.at(k));

					bytes data = tr.inputParameters;
					data.erase(data.begin(), data.begin() + 4);
					QStringList parameters = encoder.decode(funcDef->parametersList(), data);
					for (int k = 0; k < parameters.length(); ++k)
					{
						QString name = funcDef->parametersList().at(k)->name();
						if (name.isEmpty())
							name = QString::number(k);
						inputParameters.insert(name, parameters.at(k));
					}
				}
			}

			// Fill generated logs and decode parameters
			for (auto const& log: tr.logs)
			{
				QVariantMap l;
				l.insert("address",  QString::fromStdString(log.address.hex()));
				ostringstream s;
				s << log.data;
				l.insert("data", QString::fromStdString(s.str()));
				ostringstream streamTopic;
				streamTopic << log.topics;
				l.insert("topic", QString::fromStdString(streamTopic.str()));
				auto const& sign = log.topics.front(); // first hash supposed to be the event signature. To check
				int topicDataIndex = 1;
				u256 pos = 0;
				for (auto const& event: def->eventsList())
				{
					if (sign == event->fullHash())
					{
						QVariantList paramsList;
						l.insert("name", event->name());
						for (auto const& e: event->parametersList())
						{
							bytes data;
							QVariant param;
							if (!e->isIndexed())
								param = encoder.decodeType(e->type()->type(), log.data, pos);
							else
							{
								data = log.topics.at(topicDataIndex).asBytes();
								topicDataIndex++;
								u256 indexedPos = 0;
								param = encoder.decodeType(e->type()->type(), data, indexedPos);
							}

							QVariantMap p;
							p.insert("indexed", e->isIndexed());
							p.insert("value", param.toString());
							p.insert("name", e->name());
							paramsList.push_back(p);
						}
						l.insert("param", paramsList);
						break;
					}
				}
				logs.push_back(l);
			}
		}

		QString sender;
		for (auto const& secret: m_accountsSecret)
		{
			if (secret.address() == tr.sender)
			{
				sender = QString::fromStdString(dev::toHex(secret.secret().ref()));
				break;
			}
		}

		if (!creation)
			for (auto const& ctr: m_contractAddresses)
			{
				if (ctr.second == tr.address)
				{
					contract = serializeToken(ctr.first);
					break;
				}
			}

		QString label;
		if (function != QObject::tr("<none>"))
			label = contract + "." + function + "()";
		else
			label = address;

		RecordLogEntry* log = new RecordLogEntry(
			recordIndex,
			transactionIndex,
			contract,
			function,
			value,
			address,
			returned,
			tr.isCall(),
			RecordLogEntry::RecordType::Transaction,
			gasUsed,
			gasRequired,
			gasRefunded,
			sender,
			label,
			inputParameters,
			returnParameters,
			logs,
			_source,
			exception
		);
		if (transactionIndex != QObject::tr("Call"))
			m_lastTransactionIndex = transactionIndex;

		QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership);

		// retrieving all accounts balance
		QVariantMap state;
		QVariantMap contractsStorage;
		QVariantMap accountBalances;
		for (auto const& ctr : m_contractAddresses)
		{
			u256 wei = m_client->balanceAt(ctr.second, PendingBlock);
			auto contractAddressIter = m_contractNames.find(ctr.second);
			CompiledContract const* compilerRes = m_codeModel->contract(contractAddressIter->second);
			QVariantMap sto = contractStorage(m_client->storageAt(ctr.second, PendingBlock), compilerRes);
			contractsStorage.insert(contractAddressIter->second + " - " + QString::fromStdString(ctr.second.hex()) + " - " + QEther(wei, QEther::Wei).format(), sto);
		}
		for (auto const& account : m_accounts)
		{
			u256 wei = m_client->balanceAt(account.first, PendingBlock);
			accountBalances.insert("0x" + QString::fromStdString(account.first.hex()),  QEther(wei, QEther::Wei).format());
		}
		state.insert("accounts", accountBalances);
		state.insert("contractsStorage", contractsStorage);
		emit newState(recordIndex, state);
		emit newRecord(log);
	}
	catch (...)
	{
		manageException();
	}
}

}
}

max_issues_repo_name: ethereum/mix


text:
///////////////////////////////////////////////////////////////////////////////
// umessage_content_handler_base.hpp
//
// smart++ - Multipurpose C++ Library.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// 2010, (c) Dmitry Timoshenko.

#ifdef _MSC_VER
# pragma once
#endif // _MSC_VER

#ifndef SMART_COMPLEX_CONTENT_HANDLER_BASE_HPP_
#define SMART_COMPLEX_CONTENT_HANDLER_BASE_HPP_

#include "xercesc_string.hpp"

#include <xercesc/sax2/DefaultHandler.hpp>

//#include <boost/function.hpp>

#include <string>
#include <map>

/** @namespace smart Library root namespace. */
namespace smart
{

/** @namespace data smart_data library namespace. */
namespace data
{

// forward
namespace detail { struct mchb_impl; }

//struct property_descriptor;

//////////////////////////////////////////////////////////////////////////
// message_content_handler class
class message_content_handler_base : public xercesc::DefaultHandler
{
//////////////////////////////////////////////////////////////////////////
// public interface
public:
  explicit message_content_handler_base(void);
  ~message_content_handler_base(void);

//////////////////////////////////////////////////////////////////////////
// protected interface
protected:
  //typedef xercesc::Attributes tag_attributes_type;
  typedef std::map<std::string, detail::xml_string_type> tag_attributes_collection_type;

protected:
  const std::string& top_element(void) const;

//////////////////////////////////////////////////////////////////////////
// private stuff
private:
  //typedef boost::function<void (void)> handler_type;

private:
  virtual bool is_message_tag(const std::string& /*tag*/) const { return false; }
  virtual bool is_property_tag(const std::string& /*tag*/) const { return false; }
  virtual bool is_array_tag(const std::string& /*tag*/) const { return false; }
  virtual bool is_array_item_tag(const std::string& /*tag*/) const { return false; }

  virtual void on_message_start(const std::string& /*tag*/, const tag_attributes_collection_type& /*attrs*/) { ; }
  virtual void on_property_start(const std::string& /*tag*/, const tag_attributes_collection_type& /*attrs*/) { ; }
  virtual void on_array_start(const std::string& /*tag*/, const tag_attributes_collection_type& /*attrs*/) { ; }
  virtual void on_array_item_start(const std::string& /*tag*/, const tag_attributes_collection_type& /*attrs*/) { ; }

  virtual void on_message_characters(const detail::xml_string_type& /*chars*/, bool /*continuation*/) { ; }
  virtual void on_property_characters(const detail::xml_string_type& /*chars*/, bool /*continuation*/) { ; }
  virtual void on_array_characters(const detail::xml_string_type& /*chars*/, bool /*continuation*/) { ; }
  virtual void on_array_item_characters(const detail::xml_string_type& /*chars*/, bool /*continuation*/) { ; }

  virtual void on_message_end(const std::string& /*tag*/) { ; }
  virtual void on_property_end(const std::string& /*tag*/) { ; }
  virtual void on_array_end(const std::string& /*tag*/) { ; }
  virtual void on_array_item_end(const std::string& /*tag*/) { ; }

private:
  void characters(const XMLCh* const chars, const unsigned int length);
  //void endDocument(void);
  void endElement(const XMLCh* const /*uri*/, const XMLCh* const /*localname*/, const XMLCh* const /*qname*/);
  //void ignorableWhitespace(const XMLCh* const chars, const unsigned int length);
  //void processingInstruction(const XMLCh* const target, const XMLCh* const data);
  //void setDocumentLocator(const xercesc::Locator* const locator);
  //void startDocument(void);
  void startElement(const XMLCh* const /*uri*/, const XMLCh* const /*localname*/, const XMLCh* const qname, const xercesc::Attributes& attrs);

  //void startPrefixMapping(const	XMLCh* const prefix, const XMLCh* const	uri) = 0;
  //void endPrefixMapping(const	XMLCh* const prefix) = 0;
  //void skippedEntity(const XMLCh* const	name) = 0;
  //InputSource* resolveEntity(const XMLCh* const publicId, const XMLCh* const systemId);
  void error(const XERCES_CPP_NAMESPACE::SAXParseException& exc);
  void fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exc);
  void warning(const XERCES_CPP_NAMESPACE::SAXParseException& exc);
  //void resetErrors(void);
  //void notationDecl(const XMLCh* const name, const XMLCh* const publicId, const XMLCh* const systemId);
  //void resetDocType(void);
  //void unparsedEntityDecl(const XMLCh* const name, const XMLCh* const publicId, const XMLCh* const systemId, const XMLCh* const notationName);
  //void comment(const XMLCh* const chars, const unsigned int length);
  //void endCDATA(void);
  //void endDTD(void);
  //void endEntity(const XMLCh* const name);
  //void startCDATA(void);
  //void startDTD(const XMLCh* const name, const XMLCh* const publicId, const XMLCh* const systemId);
  //void startEntity (const XMLCh* const name);
  //void elementDecl(const XMLCh* const name, const XMLCh* const model);
  //void attributeDecl(const XMLCh* const eName, const XMLCh* const aName, const XMLCh* const type, const XMLCh* const mode, const XMLCh* const value);
  //void internalEntityDecl(const XMLCh* const name, const XMLCh* const value);
  //void externalEntityDecl(const XMLCh* const name, const XMLCh* const publicId, const XMLCh* const systemId);

private:
  tag_attributes_collection_type get_attribs(const xercesc::Attributes& attrs) const;

private:
  smart::data::detail::mchb_impl *_impl;
};

} // namespace data

} // namespace smart

#endif // SMART_COMPLEX_CONTENT_HANDLER_BASE_HPP_

ext: hpp

max_stars_repo_name: Chrizzly/libunicomm

max_issues_repo_name: Chrizzly/libunicomm

max_forks_repo_name: Chrizzly/libunicomm


text:
#define BOOST_TEST_DYN_LINK

#define BOOST_TEST_MODULE algorithm/crossover

#include <boost/test/unit_test.hpp>

#include <geneial/core/operations/coupling/LambdaCouplingAdapter.h>
#include <geneial/core/operations/crossover/BaseCrossoverOperation.h>
#include <geneial/core/population/management/BaseManager.h>

BOOST_AUTO_TEST_SUITE( __CRITERIA_TEST_CombinedCriterion )
BOOST_AUTO_TEST_CASE( LambdaAdapterTest )
{
    BOOST_CHECK(1==1);
}
BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: geneial/geneial

max_issues_repo_name: geneial/geneial

max_forks_repo_name: geneial/geneial


text:
// Copyright Antony Polukhin, 2016-2018.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/array.hpp>
BOOST_NOINLINE void foo(int i);
BOOST_NOINLINE void bar(int i);

BOOST_NOINLINE void bar(int i) {
    boost::array<int, 5> a = {{-1, -231, -123, -23, -32}};
    if (i >= 0) {
        foo(a[i]);
    } else {
        std::terminate();
    }
}

BOOST_NOINLINE void foo(int i) {
    bar(--i);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//[getting_started_terminate_handlers

#include <signal.h>     // ::signal, ::raise
#include <boost/stacktrace.hpp>

void my_signal_handler(int signum) {
    ::signal(signum, SIG_DFL);
    boost::stacktrace::safe_dump_to("./backtrace.dump");
    ::raise(SIGABRT);
}
//]

void setup_handlers() {
//[getting_started_setup_handlers
    ::signal(SIGSEGV, &my_signal_handler);
    ::signal(SIGABRT, &my_signal_handler);
//]
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BOOST_CONSTEXPR_OR_CONST std::size_t shared_memory_size = 4096 * 8;

//[getting_started_terminate_handlers_shmem
#include <boost/stacktrace.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

boost::interprocess::shared_memory_object g_shm; // inited at program start
boost::interprocess::mapped_region g_region;     // inited at program start

void my_signal_handler2(int signum) {
    ::signal(signum, SIG_DFL);
    void** f = static_cast<void**>(g_region.get_address());
    *f = reinterpret_cast<void*>(1);                      // Setting flag that shared memory now constains stacktrace.
    boost::stacktrace::safe_dump_to(f + 1, g_region.get_size() - sizeof(void*));

    ::raise(SIGABRT);
}
//]

#include <iostream>     // std::cerr
#include <fstream>     // std::ifstream
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>

inline void copy_and_run(const char* exec_name, char param, bool not_null) {
    std::cout << "Running with param " << param << std::endl;
    boost::filesystem::path command = exec_name;
    command = command.parent_path() / (command.stem().string() + param + command.extension().string());
    boost::filesystem::copy_file(exec_name, command, boost::filesystem::copy_option::overwrite_if_exists);

    boost::filesystem::path command_args = command;
    command_args += ' ';
    command_args += param;
    const int ret = std::system(command_args.string().c_str());

    std::cout << "End Running with param " << param << "; ret code is " << ret << std::endl;
    boost::system::error_code ignore;
    boost::filesystem::remove(command, ignore);
    if (not_null && !ret) {
        std::exit(97);
    } else if (!not_null && ret) {
        std::exit(ret);
    }
}

int run_1(const char* /*argv*/[]) {
    setup_handlers();
    foo(5);
    return 11;
}

int run_2(const char* argv[]) {
    if (!boost::filesystem::exists("./backtrace.dump")) {
        if (std::string(argv[0]).find("noop") == std::string::npos) {
            return 21;
        }

        boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(std::cin);
        if (st) {
            return 22;
        }
        return 0;
    }

//[getting_started_on_program_restart
    if (boost::filesystem::exists("./backtrace.dump")) {
        // there is a backtrace
        std::ifstream ifs("./backtrace.dump");

        boost::stacktrace::stacktrace st = boost::stacktrace::stacktrace::from_dump(ifs);
        std::cout << "Previous run crashed:\n" << st << std::endl; /*<-*/

        if (!st) {
            return 23;
        } /*->*/

        // cleaning up
        ifs.close();
        boost::filesystem::remove("./backtrace.dump");
    }
//]

    return 0;
}

int run_3(const char* /*argv*/[]) {
    using namespace boost::interprocess;
    {
        shared_memory_object shm_obj(open_or_create, "shared_memory", read_write);
        shm_obj.swap(g_shm);
    }
    g_shm.truncate(shared_memory_size);

    {
        mapped_region m(g_shm, read_write, 0, shared_memory_size);
        m.swap(g_region);
    }
    void** f = static_cast<void**>(g_region.get_address());
    *f = 0;

    ::signal(SIGSEGV, &my_signal_handler2);
    ::signal(SIGABRT, &my_signal_handler2);
    foo(5);
    return 31;
}

int run_4(const char* argv[]) {
    using namespace boost::interprocess;
    {
        shared_memory_object shm_obj(open_only, "shared_memory", read_write);
        shm_obj.swap(g_shm);
    }

    {
        mapped_region m(g_shm, read_write, 0, shared_memory_size);
        m.swap(g_region);
    }

//[getting_started_on_program_restart_shmem
    void** f = static_cast<void**>(g_region.get_address());
    if (*f) {                                                 // Checking if memory constains stacktrace.
        boost::stacktrace::stacktrace st
            = boost::stacktrace::stacktrace::from_dump(f + 1, g_region.get_size() - sizeof(bool));

        std::cout << "Previous run crashed and left trace in shared memory:\n" << st << std::endl;
        *f = 0; /*<-*/
        shared_memory_object::remove("shared_memory");
        if (std::string(argv[0]).find("noop") == std::string::npos) {
            if (!st) {
                return 43;
            }
        } else {
           if (st) {
                return 44;
            }
        }
    } else {
        return 42; /*->*/
    }
//]

    return 0;
}

#include <sstream>

int test_inplace() {
    const bool is_noop = !boost::stacktrace::stacktrace();

    {
        // This is very dependent on compiler and link flags. No sane way to make it work, because:
        // * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
        // * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
        const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to("./backtrace2.dump");
        boost::stacktrace::stacktrace ss2;
        std::ifstream ifs("./backtrace2.dump");
        boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
        ifs.close();
        boost::filesystem::remove("./backtrace2.dump");

        if (ss1.size() + 1 != frames_ss1 || ss2.size() != ss1.size()) {
            std::cerr << "51: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
        } else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
            std::cerr << "52: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
        }
    }

    {
        // This is very dependent on compiler and link flags. No sane way to make it work, because:
        // * BOOST_NOINLINE could be ignored by MSVC compiler if link-time optimization is enabled.
        // * BOOST_FORCEINLINE could be ignored by GCC depending on the std::vector default constructor length.
        void* data[1024];
        const std::size_t frames_ss1 = boost::stacktrace::safe_dump_to(data, sizeof(data));
        boost::stacktrace::stacktrace ss2;
        boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(data, sizeof(data));

        if (ss1.size() + 1 != frames_ss1 || ss1.size() != ss2.size()) {
            std::cerr << "53: Stacktraces differ. Dumped size == " << frames_ss1 << ".\n" << ss1 << "\n vs \n" << ss2 << '\n';
        } else if (ss1.size() > 1 && ss1[1].name() != ss2[1].name()) {
            std::cerr << "54: Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
        }
    }

    {
        void* data[1024];
        boost::stacktrace::safe_dump_to(1024, data, sizeof(data));
        if (boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
            std::cerr << "Stacktrace not empty!\n";
            return 55;
        }
    }

    {
        void* data[1024];
        boost::stacktrace::safe_dump_to(1, data, sizeof(data));
        if (!is_noop && !boost::stacktrace::stacktrace::from_dump(data, sizeof(data))) {
            std::cerr << "Stacktrace empty!\n";
            return 56;
        }
        const std::size_t size_1_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();
        boost::stacktrace::safe_dump_to(0, data, sizeof(data));
        const std::size_t size_0_skipped = boost::stacktrace::stacktrace::from_dump(data, sizeof(data)).size();

        if (!is_noop && (size_1_skipped + 1 != size_0_skipped)) {
            std::cerr << "failed to skip 1 frame!\n";
            return 57;
        }
    }

    {
        boost::stacktrace::safe_dump_to(0, 1, "./backtrace3.dump");
        std::ifstream ifs("./backtrace3.dump");
        boost::stacktrace::stacktrace ss1 = boost::stacktrace::stacktrace::from_dump(ifs);
        ifs.close();

        boost::stacktrace::safe_dump_to(1, 1, "./backtrace3.dump");
        ifs.open("./backtrace3.dump");
        boost::stacktrace::stacktrace ss2 = boost::stacktrace::stacktrace::from_dump(ifs);
        ifs.close();

        boost::filesystem::remove("./backtrace3.dump");

#ifdef BOOST_WINDOWS
        // `ss2` could be empty on some combinations of Windows+MSVC.
        if (!ss2) {
            return 0;
        }
#endif

        if (ss1.size() != ss2.size()) {
            std::cerr << "Stacktraces differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
            return 58;
        }

        if (!is_noop && ss1.size() != 1) {
            std::cerr << "Stacktraces does not have size 1:\n" << ss1 << '\n';
            return 59;
        }

        if (ss1 && ss1[0].address() == ss2[0].address()) {
            std::cerr << "Stacktraces must differ:\n" << ss1 << "\n vs \n" << ss2 << '\n';
            return 60;
        }
    }

    return 0;
}

int main(int argc, const char* argv[]) {
    if (argc < 2) {
#ifndef BOOST_WINDOWS
        // We are copying files to make sure that stacktrace printing works independently from executable name
        copy_and_run(argv[0], '1', true);
        copy_and_run(argv[0], '2', false);

        // There are some issues with async-safety of shared memory writes on Windows.
        copy_and_run(argv[0], '3', true);
        copy_and_run(argv[0], '4', false);
#endif

        return test_inplace();
    }

    switch (argv[1][0]) {
    case '1': return run_1(argv);
    case '2': return run_2(argv);
    case '3': return run_3(argv);
    case '4': return run_4(argv);
    }

    return 404;
}

max_stars_repo_name: alexhenrie/poedit

max_issues_repo_name: alexhenrie/poedit

max_forks_repo_name: alexhenrie/poedit


text:
//   -----------------------------------------------------------------------------------------------
//    Copyright 2015 André Bergner. Distributed under the Boost Software License, Version 1.0.
//     (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//      --------------------------------------------------------------------------------------------

#include <iostream>
#include <array>

#include <boost/mpl/int.hpp>
#include <boost/mpl/min_max.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/proto/transform.hpp>
#include <boost/proto/debug.hpp>

#include "callable_decltype.hpp"
#include "tuple_tools.hpp"
#include "demangle.h"

namespace mpl = boost::mpl;
namespace proto = boost::proto;

namespace building_blocks
{
   using namespace proto;

   //  ---------------------------------------------------------------------------------------------
   // definition of the building blocks of the language
   //  ---------------------------------------------------------------------------------------------

   template < typename I >  struct placeholder       { using arity = I; };
   template < typename T >  struct placeholder_arity { using type = typename T::arity; };

   template < typename idx = _ >
   using delayed_placeholder = subscript< terminal<placeholder<idx>> , terminal<placeholder<_>> >;

   //  ---------------------------------------------------------------------------------------------
   // block composition operators -- TODO needs correct grammar as arguments

   using channel_operator  = comma              < _ , _ >;
   using parallel_operator = bitwise_or         < _ , _ >;
   using sequence_operator = bitwise_or_assign  < _ , _ >;
}

using building_blocks :: placeholder;
using building_blocks :: placeholder_arity;
using building_blocks :: delayed_placeholder;

using building_blocks :: channel_operator;
using building_blocks :: sequence_operator;
using building_blocks :: parallel_operator;

BOOST_PROTO_DEFINE_ENV_VAR( current_input_t, current_input );
BOOST_PROTO_DEFINE_ENV_VAR( delayed_input_t, delayed_input );

//  ------------------------------------------------------------------------------------------------
// very simple delay_line operation on std::array --> TODO should be own type static_delay_line !

struct
{
    template< typename T , size_t N , typename Y >
    void operator()( std::array<T,N>& xs , Y y ) const
    {
        for ( size_t n = 1 ; n < xs.size() ; ++n )  xs[n-1] = xs[n];
        xs.back() = y;
    }

    template< typename T , typename Y >
    void operator()( std::array<T,0>& xs , Y y ) const { }

    template< typename T , typename Y >   // if input is not an array, e.g. for not fully
    void operator()( T& , Y ) const { }   // unpacked state while traversing the tree (tuple o'tuples)
}
rotate_push_back;

namespace transforms
{
   using namespace proto;

   //  ---------------------------------------------------------------------------------------------
   // static analysis transforms  --  helpers that inspect structure of expression
   //  ---------------------------------------------------------------------------------------------

   struct output_arity;

   struct input_arity : or_
   <  when
      <  delayed_placeholder<>
      ,  placeholder_arity<_value(_left)>()
      >
   ,  when
      <  terminal< placeholder<_> >
      ,  placeholder_arity<_value>()
      >
   ,  when
      <  terminal<_>
      ,  mpl::int_<0>()
      >
   ,  when
      <  parallel_operator
      ,  mpl::plus< input_arity(_left) , input_arity(_right) >()
      >
   ,  when
      <  sequence_operator
      ,  mpl::plus
         <  input_arity(_left)
         ,  mpl::max
            <  mpl::int_<0>
            ,  mpl::minus< input_arity(_right) , output_arity(_left) >
            >
         >()
      >
   ,  when
      <  nary_expr<_, vararg<_>>
      ,  fold<_, mpl::int_<0>(), mpl::max<input_arity, _state>()>
      >
   >
   {};

   struct output_arity : or_
   <  when
      <  channel_operator
      ,  mpl::plus< output_arity(_left) , output_arity(_right) >()
      >
   ,  when
      <  parallel_operator
      ,  mpl::plus< output_arity(_left) , output_arity(_right) >()
      >
   ,  when
      <  sequence_operator
      ,  mpl::plus
         <  output_arity(_right)
         ,  mpl::max
            <  mpl::int_<0>
            ,  mpl::minus< output_arity(_left) , input_arity(_right) >
            >
         >()
      >
   ,  otherwise< mpl::int_<1>() >
   >
   {};

   template < typename arity , typename delay = mpl::int_<0> >
   struct make_arity_impl
   {
      using type = tuple_cat_t< repeat_t< arity::value-1ul, mpl::int_<0> >
                              , std::tuple<delay>
                              >;
   };

   template < typename delay >
   struct make_arity_impl<mpl::int_<0>, delay>
   {
      using type = std::tuple<>;
   };

   template < typename arity , typename delay = mpl::int_<0> >
   using make_arity = typename make_arity_impl<arity,delay>::type;

   struct delay_per_wire : callable_decltype
   {
      using default_t = placeholder<mpl::int_<0>>;

      template < typename Placeholder = default_t , typename Delay = default_t>
      auto operator()( Placeholder const & = default_t{}, Delay const & = default_t{} ) const
      {
         return make_arity<typename Placeholder::arity, typename Delay::arity>{};
      }
   };

   struct tuple_cat_fn : callable_decltype
   {
      template < typename... Tuples >
      auto operator()( Tuples&&... ts ) const
      {
         return std::tuple_cat( std::forward<Tuples>(ts)... );
      }
   };

   struct make_tuple_fn : callable_decltype
   {
      template < typename... Ts >
      auto operator()( Ts&&... ts ) const
      {
         return std::make_tuple( std::forward<Ts>(ts)... );
      }
   };

   // -------------------------------------------------------------------------------------------
   // max-zip tuple
   // -------------------------------------------------------------------------------------------

   template < typename Tuple1, typename Tuple2, std::size_t... Ns >
   auto zip_with_max( Tuple1&& t1, Tuple2&& t2, std::index_sequence<Ns...> )
   {
      using namespace std;
      return tuple< typename mpl::max< decay_t<decltype(get<Ns>(t1))> , decay_t<decltype(get<Ns>(t2))> >::type... >{};
   }

   template < typename Tuple1, typename Tuple2 >
   auto zip_with_max( Tuple1&&, Tuple2&&, std::index_sequence<> )
   {
      return std::tuple<>{};
   }

   struct max_delay_of_wires : callable_decltype
   {
      template < typename Tuple_l , typename Tuple_r >
      auto operator()( Tuple_l&& tl, Tuple_r&& tr ) const
      {
         using tuple_tl = std::decay_t<Tuple_l>;
         using tuple_tr = std::decay_t<Tuple_r>;
         using min_size = typename mpl::min< mpl::int_<std::tuple_size<tuple_tl>::value>
                                           , mpl::int_<std::tuple_size<tuple_tr>::value>
                                           >::type;
         return  std::tuple_cat(  zip_with_max(tl,tr,std::make_index_sequence<min_size::value>{})
                               ,  tuple_drop<min_size::value>( std::forward<Tuple_l>(tl) )
                               ,  tuple_drop<min_size::value>( std::forward<Tuple_r>(tr) )
                               );
      }
   };

   struct tuple_drop_ : callable_decltype
   {
      template< typename Drop , typename Tuple >
      decltype(auto) operator()( Drop , Tuple const & t ) const
      {
         return tuple_drop<Drop::value>(t);
      }
   };

   struct input_delays : or_
   <  when
      <  delayed_placeholder<>
      ,  delay_per_wire( _value(_left),_value(_right))
      >
   ,  when
      <  terminal< placeholder<_> >
      ,  delay_per_wire( _value() )
      >
   ,  when
      <  terminal<_>
      ,  std::tuple<>()//delay_per_wire()
      >
   ,  when
      <  parallel_operator
      ,  tuple_cat_fn( input_delays(_left) , input_delays(_right) )
      >
   ,  when
      <  sequence_operator
      ,  tuple_cat_fn
         (  input_delays(_left)
         ,  tuple_drop_ // <-- problem here????
            (  output_arity(_left)
            ,  input_delays(_right)
            )
         )
      >
   ,  when
      <  nary_expr<_, vararg<_>>
      ,  fold<_, std::tuple<>(), max_delay_of_wires(input_delays, _state) >
      >
   >
   {};

   template < typename Expr >
   using input_arity_t = typename boost::result_of<input_arity(Expr)>::type;

   struct identity : callable_decltype
   {
      template < typename X >
      auto operator()( X&& x ) { return std::forward<X>(x); }
   };

   template < typename StateCtor >
   struct build_state_impl
   {
      struct apply : or_
      <  when
         <  sequence_operator
         ,  make_tuple_fn
            (  apply( _left  , StateCtor(input_delays( _left  )) )
            ,  apply( _right , StateCtor(input_delays( _right )) )
            )
         >
      ,  otherwise< _state >
      >
      {};
   };

   template < typename StateCtor = identity >
   using build_state = typename build_state_impl<StateCtor>::apply;

   //  ---------------------------------------------------------------------------------------------
   // Evaluators -- transforms that work together for the evaluation of flowz-expressions
   //  ---------------------------------------------------------------------------------------------

   struct place_the_holder;
   struct place_delay;
   struct sequence;
   struct parallel;

   struct eval_it : or_
   <  when
      <  delayed_placeholder<>
      ,  place_delay( _value(_left) , _value(_right) , _env_var<delayed_input_t> )
      >
   ,  when
      <  terminal< placeholder<_> >
      ,  place_the_holder( _value , _env_var<current_input_t> )
      >
   ,  when
      <  sequence_operator
      ,  sequence( _left , _right , _env_var<current_input_t> , _env_var<delayed_input_t> )
      >
   ,  when
      <  parallel_operator
      ,  parallel( _left , _right , _env_var<current_input_t> , _env_var<delayed_input_t> )
      >
   ,  when
      <  channel_operator    //  grammar rule: only allowed after sequence or recursion at top of sub-tree
      ,  make_tuple_fn( eval_it(_left), eval_it(_right) )
      >
   ,  when
      <  _
      ,  _default< eval_it >
      >
   >
   {};

   //-----------------------------------------------------------------------------------------------

   template < typename T >
   using in_t = T const &;
   //using in_t = T;

   struct place_the_holder : callable_decltype
   {
      template < typename I , typename Tuple >
      auto operator()( placeholder<I> const & , Tuple const & args ) const
      {
         return std::get<I::value-1>( args );
      }
   };

   struct place_delay : callable_decltype
   {
      template < typename I , typename J , typename Delayed_input >
      auto operator()( placeholder<I> , placeholder<J> , in_t<Delayed_input> del_in ) const
      {
         auto const & s = std::get<I::value-1>(del_in);
         return s[s.size()-J::value];
      }
   };

   struct sequence : callable_decltype
   {
      template < typename LeftExpr , typename RightExpr , typename Input , typename Delay >
      auto operator()( in_t<LeftExpr> l , in_t<RightExpr> r , in_t<Input> input , Delay& delay ) const
      {
         auto e = eval_it{};

         auto& ls = std::get<0>(delay);
         auto& rs = std::get<1>(delay);

         auto left_result =
            flatten_tuple( std::make_tuple(
               e( l, 0, ( current_input = input , delayed_input = boost::ref(ls) ))
            ));

         tuple_for_each( rotate_push_back, ls, input );
         using left_size = std::tuple_size<decltype(left_result)>;
         auto right_input = tuple_cat( left_result, tuple_drop<left_size::value>(input) );

         auto right_result =
            flatten_tuple( std::make_tuple(
               e( r, 0, ( current_input = right_input , delayed_input = boost::ref(rs)) )
            ));

         tuple_for_each( rotate_push_back, rs, left_result );
         using right_size = std::tuple_size<decltype(right_result)>;
         return tuple_cat( right_result, tuple_drop<right_size::value>(std::move(left_result)) );
      }
   };

   struct parallel : callable_decltype
   {
      template < typename LeftExpr , typename RightExpr , typename Input , typename Delay >
      auto operator()( in_t<LeftExpr> l , in_t<RightExpr> r , in_t<Input> input , Delay& del ) const
      {
         auto e = eval_it{};
         auto left_state  = ( current_input = input , delayed_input = del );
         auto right_state = ( current_input = tuple_drop<input_arity_t<LeftExpr>::value>(input)
                            , delayed_input = tuple_drop<input_arity_t<LeftExpr>::value>(del)
                            );
         return std::make_tuple
                (  e( l, 0, left_state )
                ,  e( r, 0, right_state )
                );
      }
   };

}

using  transforms :: input_arity;
using  transforms :: input_delays;
using  transforms :: build_state;
using  transforms :: input_arity_t;
using  transforms :: output_arity;
using  transforms :: eval_it;

//  ------------------------------------------------------------------------------------------------
// supporting state tools
//  ------------------------------------------------------------------------------------------------

//  ------------------------------------------------------------------------------------------------
// lift_into_tuple  --  lifts a meta-function into a tuple,
//                      i.e. applies it on each type in tuple, returns tuple of new types

template< typename F , typename Tuple >
struct lift_into_tuple;

template< typename F , typename... Ts >
struct lift_into_tuple< F , std::tuple<Ts...> >
{
    using type = std::tuple< typename F::template apply_t<Ts>... >;
};

template< typename F , typename Tuple >
using lift_into_tuple_t = typename lift_into_tuple<F,Tuple>::type;

//  ------------------------------------------------------------------------------------------------
// to_array  --  meta-function that maps mpl::int_<N> to array<T,N>

template< typename T >
struct to_array
{
   template< typename Int >
   struct apply
   {
      using type = std::array< T , std::decay_t<Int>::value >;
   };

   template< typename Int >
   using apply_t = typename apply<Int>::type;

};

template < typename T >
struct to_array_tuple
{
   struct apply : proto::callable_decltype
   {
       template< typename Tuple >
       auto operator()( Tuple ) { return lift_into_tuple_t< to_array<T>, Tuple > {}; }
   };
};

//  ------------------------------------------------------------------------------------------------
// compile  --  main function of framework
//              • takes an expression
//              • returns clojure
//  ------------------------------------------------------------------------------------------------

template
<  typename Expression
,  typename State
,  size_t   arity
>
struct stateful_lambda
{
private:

   Expression  expr_;
   State       state_;

   template < typename... Args >
   auto call_impl( mpl::int_<0> , Args const &... args ) -> decltype(auto)
   {
      auto result = eval_it{}( expr_, 0, ( current_input = std::make_tuple(args...) , delayed_input = boost::ref(state_) ) );
      return flatten_tuple( std::make_tuple( result ));
   }

   template < int arg_diff , typename... Args >
   auto call_impl( mpl::int_<arg_diff> , Args const &... args )
   {
      return [ args...
             , expr = *this ]           // TODO should not be a lambda, but a type that is
      ( auto const &... missing_args ) mutable  //      aware of the # of args (enable_if them)
      {
         return expr( args..., missing_args... );
      };
   }

public:

   stateful_lambda( Expression expr ) : expr_( std::move(expr)) {}

   template < typename... Args , typename = std::enable_if_t< sizeof...(Args) <= arity > >
   auto operator()( Args const &... args ) -> decltype(auto)
   {
      return call_impl( mpl::int_< arity - sizeof...(Args) >{} , args... );
   }
};

// TODO template input type determinse state type (float)
auto compile = []( auto expr )        // TODO need to define value_type for state
{
   using expr_t = decltype(expr);
   using arity_t = input_arity_t<expr_t>;

   auto builder = build_state< to_array_tuple<float>::apply >{};
   using state_t = decltype( builder(expr) );

   return stateful_lambda< expr_t, state_t, arity_t::value>{ expr };
};

const proto::terminal< placeholder< mpl::int_<1> >>::type   _1  = {{}};
const proto::terminal< placeholder< mpl::int_<2> >>::type   _2  = {{}};
const proto::terminal< placeholder< mpl::int_<3> >>::type   _3  = {{}};
const proto::terminal< placeholder< mpl::int_<4> >>::type   _4  = {{}};
const proto::terminal< placeholder< mpl::int_<5> >>::type   _5  = {{}};
const proto::terminal< placeholder< mpl::int_<6> >>::type   _6  = {{}};

int main()
{
   auto print_ins_and_outs = []( auto const & expr )
   {
       std::cout << "-------------------------" << std::endl;
       //proto::display_expr( expr );
       std::cout << "#ins:  " << input_arity{} (expr) << std::endl;
       std::cout << "#outs: " << output_arity{}(expr) << std::endl;
       std::cout << std::endl;
   };

   auto e1 = ( _2 + _1 , _2 );
   auto e2 = ( _1*_2 - 100 );
   auto seq_expr =(      e1 | (_1+_2)
                      |= e2 | (_1*_1)
                  );

   print( input_delays{}(seq_expr));

   print_ins_and_outs( seq_expr );
   auto seq = compile( seq_expr );

   std::cout << std::get<1>(seq(1337,3,4)(3)) << std::endl;

   std::cout << "-------------------------" << std::endl;
   build_state<> b;
   build_state< to_array_tuple<float>::apply > d;
   std::cout << b( (_2[_1] |= _1[_2]) |= (_1[_3] |= _3[_4]) ) << std::endl;
   std::cout << b(  _2[_1] |= (_1[_2] |=  _1[_3] |= _3[_4]) ) << std::endl;
   std::cout << b( (_2[_1] |=  _1[_2] |=  _1[_3]) |= _3[_4] ) << std::endl;
   std::cout << b( _1, std::tuple<>{} ) << std::endl;
   std::cout << type_name( d( (_2[_1] |= _1[_2]) |= (_1[_3] |= _3[_4]) )) << std::endl;
   std::cout << "-------------------------" << std::endl;

   auto z = compile( ((_1|_1) |= (_1[_2] - _2[_3])) |= _1[_1] );

   std::cout << std::get<0>(z(1,1)) << std::endl;
   std::cout << std::get<0>(z(1,2)) << std::endl;
   std::cout << std::get<0>(z(1,3)) << std::endl;
   std::cout << std::get<0>(z(1,4)) << std::endl;
   std::cout << std::get<0>(z(1,5)) << std::endl;
   std::cout << std::get<0>(z(1,6)) << std::endl;
   std::cout << std::get<0>(z(3,10)) << std::endl;

   auto wire_around_prev_box = (_1 |= _2);
   print_ins_and_outs( wire_around_prev_box );
   auto wp = compile( wire_around_prev_box );
   std::cout << wp(2,1337) << std::endl;

   auto wire_around_succ_box = ( (_1,_1) |= _1);
   print_ins_and_outs( wire_around_succ_box );
   auto ws = compile( wire_around_succ_box );
   std::cout << ws(1337) << std::endl;
}

max_stars_repo_name: andre-bergner/zignal

max_issues_repo_name: andre-bergner/zignal

max_forks_repo_name: andre-bergner/zignal


text:
#include "base_driver.h"
#include "data_holder.h"

#include <std_msgs/Float32MultiArray.h>

#ifdef USE_BOOST_SERIAL_TRANSPORT
#include "serial_transport.h"
#else
#include "serial_transport2.h"
#endif

#include "simple_dataframe_master.h"
#include <boost/assign/list_of.hpp>

BaseDriver* BaseDriver::instance = NULL;

BaseDriver::BaseDriver() : pn("~"), bdg(pn)
{
    //init config
    bdg.init(&Data_holder::get()->parameter);

#ifdef USE_BOOST_SERIAL_TRANSPORT
    trans = boost::make_shared<Serial_transport>(bdg.port, bdg.baudrate);
#else
    trans = boost::make_shared<Serial_transport2>(bdg.port, bdg.baudrate);
#endif

    frame = boost::make_shared<Simple_dataframe>(trans.get());

    ROS_INFO("[KUBOT]BaseDriver startup...");
    if (trans->init())
    {
        ROS_INFO("[KUBOT]connected to main board");
    }
    else
    {
        ROS_ERROR("[KUBOT]oops!!! can't connect to main board, please check the usb connection or baudrate!");
        return;
    }

    ros::Duration(2).sleep(); //wait for device
    ROS_INFO("[KUBOT]end sleep");

    frame->init();

    for (int i=0;i<3;i++) {
        if (frame->interact(ID_GET_VERSION))
            break;
        ros::Duration(1).sleep(); //wait for device
    }

    ROS_INFO("[KUBOT]robot version:%s build time:%s", Data_holder::get()->firmware_info.version,
                                        Data_holder::get()->firmware_info.time);

    init_cmd_odom();

    init_pid_debug();

    read_param();

    init_imu();

    init_battery_meter();
}

BaseDriver::~BaseDriver()
{
if (instance != NULL)
    delete instance;
}

void BaseDriver::init_cmd_odom()
{
    frame->interact(ID_INIT_ODOM);

    ROS_INFO_STREAM("[KUBOT]subscribe cmd topic on [" << bdg.cmd_vel_topic << "]");
    cmd_vel_sub = nh.subscribe(bdg.cmd_vel_topic, 1000, &BaseDriver::cmd_vel_callback, this);

    ROS_INFO_STREAM("[KUBOT]advertise odom topic on [" << bdg.odom_topic << "]");
    odom_pub = nh.advertise<nav_msgs::Odometry>(bdg.odom_topic, 50);

    //init odom_trans
    odom_trans.header.frame_id = bdg.odom_frame;
    odom_trans.child_frame_id = bdg.base_frame;

    odom_trans.transform.translation.z = 0;

    //init odom
    odom.header.frame_id = bdg.odom_frame;
    odom.pose.pose.position.z = 0.0;
    odom.child_frame_id = bdg.base_frame;
    odom.twist.twist.linear.y = 0;

    if (!bdg.publish_tf)
    {
        odom.pose.covariance =  boost::assign::list_of(1e-3) (0) (0)  (0)  (0)  (0)
                                                    (0) (1e-3)  (0)  (0)  (0)  (0)
                                                    (0)   (0)  (1e6) (0)  (0)  (0)
                                                    (0)   (0)   (0) (1e6) (0)  (0)
                                                    (0)   (0)   (0)  (0) (1e6) (0)
                                                    (0)   (0)   (0)  (0)  (0)  (1e3) ;

        odom.twist.covariance =  boost::assign::list_of(1e-3) (0)   (0)  (0)  (0)  (0)
                                                    (0) (1e-3)  (0)  (0)  (0)  (0)
                                                    (0)   (0)  (1e6) (0)  (0)  (0)
                                                    (0)   (0)   (0) (1e6) (0)  (0)
                                                    (0)   (0)   (0)  (0) (1e6) (0)
                                                    (0)   (0)   (0)  (0)  (0)  (1e3) ;
    }

    need_update_speed = false;

    //ROS_INFO_STREAM("subscribe cmd topic on [correct_pos]");
    //correct_pos_sub = nh.subscribe("correct_pos", 1000, &BaseDriver::correct_pos_callback, this);
}

void BaseDriver::init_pid_debug()
{
    if (bdg.out_pid_debug_enable)
    {
        const char* input_topic_name[MAX_MOTOR_COUNT]={"motor1_input", "motor2_input", "motor3_input", "motor4_input"};
        const char* output_topic_name[MAX_MOTOR_COUNT]={"motor1_output", "motor2_output", "motor3_output", "motor4_output"};
        for (size_t i = 0; i < MAX_MOTOR_COUNT; i++)
        {
            pid_debug_pub_input[i] = nh.advertise<std_msgs::Int32>(input_topic_name[i], 1000);
            pid_debug_pub_output[i] = nh.advertise<std_msgs::Int32>(output_topic_name[i], 1000);
        }
    }
}

void BaseDriver::init_imu()
{
    raw_imu_pub = nh.advertise<kubot_msgs::RawImu>("raw_imu", 50);
    raw_imu_msgs.header.frame_id = "imu_link";
    raw_imu_msgs.accelerometer = true;
    raw_imu_msgs.gyroscope = true;
    raw_imu_msgs.magnetometer = true;
}

void BaseDriver::init_battery_meter()
{
    battery_voltage_pub = nh.advertise<kubot_msgs::BatteryVoltage>("battery_voltage", 1000);
    battery_voltage_msgs.batterymeter = true;
}

void BaseDriver::read_param()
{
    Robot_parameter* param = &Data_holder::get()->parameter;
    memset(param,0, sizeof(Robot_parameter));

    frame->interact(ID_GET_ROBOT_PARAMTER);

    ROS_INFO("RobotParameters: %d %d %d %d %d %d %d %d %d %d %d %d %d",
        param->wheel_diameter, param->wheel_track,  param->encoder_resolution,
        param->do_pid_interval, param->kp, param->ki, param->kd, param->ko,
        param->cmd_last_time, param->max_v_liner_x, param->max_v_liner_y, param->max_v_angular_z,
        param->imu_type);

    bdg.SetRobotParameters();
}

void BaseDriver::cmd_vel_callback(const geometry_msgs::Twist& vel_cmd)
{
    ROS_INFO_STREAM("cmd_vel:[" << vel_cmd.linear.x << " " << vel_cmd.linear.y << " " << vel_cmd.angular.z << "]");

    Data_holder::get()->velocity.v_liner_x = vel_cmd.linear.x*100;
    Data_holder::get()->velocity.v_liner_y = vel_cmd.linear.y*100;
    Data_holder::get()->velocity.v_angular_z = vel_cmd.angular.z*100;

    need_update_speed = true;
}

void BaseDriver::work_loop()
{
    ros::Rate loop(bdg.freq);
    while (ros::ok())
    {
        //boost::posix_time::ptime my_posix_time = ros::Time::now().toBoost();
        update_param();

        update_odom();

        update_pid_debug();

        update_speed();

        if (Data_holder::get()->parameter.imu_type == 'E')
            update_imu();

        loop.sleep();

        update_battery_meter();

	    ros::spinOnce();
    }
}

void BaseDriver::update_param()
{
#ifdef USE_DYNAMIC_RECONFIG
    if (bdg.get_param_update_flag())
    {
        frame->interact(ID_SET_ROBOT_PARAMTER);
        ros::Rate loop(5);
        loop.sleep();
    }
#endif
}

void BaseDriver::update_odom()
{
    frame->interact(ID_GET_ODOM);

    ros::Time current_time = ros::Time::now();

    float x = Data_holder::get()->odom.x*0.01;
    float y = Data_holder::get()->odom.y*0.01;
    float th = Data_holder::get()->odom.yaw*0.01;

    float vxy = Data_holder::get()->odom.v_liner_x*0.01;
    float vth = Data_holder::get()->odom.v_angular_z*0.01;

    //ROS_INFO("odom: x=%.2f y=%.2f th=%.2f vxy=%.2f vth=%.2f", x, y ,th, vxy,vth);

    geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);

    //publish_tf
    if (bdg.publish_tf)
    {
        odom_trans.header.stamp = current_time;
        odom_trans.transform.translation.x = x;
        odom_trans.transform.translation.y = y;
        odom_trans.transform.rotation = odom_quat;
        odom_broadcaster.sendTransform(odom_trans);
    }

    //publish the message
    odom.header.stamp = current_time;
    odom.pose.pose.position.x = x;
    odom.pose.pose.position.y = y;
    odom.pose.pose.orientation = odom_quat;
    odom.twist.twist.linear.x = vxy;
    odom.twist.twist.angular.z = vth;

    odom_pub.publish(odom);
}

void BaseDriver::update_speed()
{
    if (need_update_speed)
    {
        ROS_INFO_STREAM("update_speed");
        need_update_speed = !(frame->interact(ID_SET_VELOCITY));
    }
}

void BaseDriver::update_pid_debug()
{
    if (bdg.out_pid_debug_enable)
    {
        frame->interact(ID_GET_PID_DATA);

        for (size_t i = 0; i < MAX_MOTOR_COUNT; i++)
        {
            pid_debug_msg_input[i].data = Data_holder::get()->pid_data.input[i];
            pid_debug_msg_output[i].data = Data_holder::get()->pid_data.output[i];

            pid_debug_pub_input[i].publish(pid_debug_msg_input[i]);
            pid_debug_pub_output[i].publish(pid_debug_msg_output[i]);
        }
    }
}

void BaseDriver::update_imu()
{
    frame->interact(ID_GET_IMU_DATA);
    raw_imu_msgs.header.stamp = ros::Time::now();
    raw_imu_msgs.raw_linear_acceleration.x = Data_holder::get()->imu_data[0];
    raw_imu_msgs.raw_linear_acceleration.y = Data_holder::get()->imu_data[1];
    raw_imu_msgs.raw_linear_acceleration.z= Data_holder::get()->imu_data[2];
    raw_imu_msgs.raw_angular_velocity.x = Data_holder::get()->imu_data[3];
    raw_imu_msgs.raw_angular_velocity.y = Data_holder::get()->imu_data[4];
    raw_imu_msgs.raw_angular_velocity.z = Data_holder::get()->imu_data[5];
    raw_imu_msgs.raw_magnetic_field.x = Data_holder::get()->imu_data[6];
    raw_imu_msgs.raw_magnetic_field.y = Data_holder::get()->imu_data[7];
    raw_imu_msgs.raw_magnetic_field.z = Data_holder::get()->imu_data[8];
    raw_imu_pub.publish(raw_imu_msgs);
}

void BaseDriver::update_battery_meter()
{
    frame->interact(ID_GET_VOLTAGE_DATA);
    battery_voltage_msgs.header.stamp = ros::Time::now();
    battery_voltage_msgs.battery_voltage = Data_holder::get()->battery_voltage[0];
 //   ROS_INFO_STREAM("battery_voltage:[" <<battery_voltage_msgs.battery_voltage<< " ] V");
    battery_voltage_pub.publish(battery_voltage_msgs);
}


text:
// Copyright (C) 2004 Jeremy Siek <jsiek@cs.indiana.edu>
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/transitive_closure.hpp>
#include <iostream>
using namespace std;

using namespace boost;
typedef adjacency_list<> graph_t;

int main(int argc, char *argv[]) {
  graph_t g(5),g_TC;

  add_edge(0,2,g);
  add_edge(1,0,g);
  add_edge(1,2,g);
  add_edge(1,4,g);
  add_edge(3,0,g);
  add_edge(3,2,g);
  add_edge(4,2,g);
  add_edge(4,3,g);

  transitive_closure(g,g_TC);

  cout << "original graph: 0->2, 1->0, 1->2, 1->4, 3->0, 3->2, 4->2, 4->3"
       << endl;
  cout << "transitive closure: ";
  graph_t::edge_iterator i,iend;
  for(boost::tie(i,iend) = edges(g_TC);i!=iend;++i) {
    cout << source(*i,g_TC) << "->" << target(*i,g_TC) << " ";
  }
  cout << endl;
}


text:
/*
 * parallel_ts_compressor.cpp
 *
 *  Created on: Dec 29, 2015
 *      Author: Karol Dzitkowski
 */

#include "parallel_ts_compressor.hpp"
#include "optimizer/compression_task.hpp"
#include "optimizer/decompression_task.hpp"
#include <queue>
#include <boost/make_shared.hpp>

namespace ddj
{

ParallelTSCompressor::ParallelTSCompressor(SharedTimeSeriesReader reader)
	: _reader(reader),
	  _batchSize(1e6),
	  _columnNumber(2),
	  _initialized(false),
	  _logger(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("ParallelTSCompressor")))
{}

void ParallelTSCompressor::SetBatchSize(size_t size)
{
	_batchSize = size;
}

void ParallelTSCompressor::init(SharedTimeSeriesPtr ts)
{
	_columnNumber = ts->getColumnsNumber();
	for(int i = 0; i < _columnNumber; i++)
		_optimizers.push_back(CompressionOptimizer::make_shared());
	_taskScheduler = TaskScheduler::make_unique(1);
	_initialized = true;
}

void ParallelTSCompressor::Compress(File& inputFile, File& outputFile)
{
	LOG4CPLUS_DEBUG(_logger, "Starting compression");
	CUDA_CALL( cudaGetLastError() );

	SharedTimeSeriesPtr ts;
	do
	{
		// read batch data from source
		ts = _reader->Read(inputFile, _batchSize);
//		ts->print(5);
		if(ts->getRecordsCnt() <= 0) break;

		if(!_initialized) init(ts);

		// schedule tasks for compression of new column parts
		for(int i = 0; i < _columnNumber; i++)
			_taskScheduler->Schedule(CompressionTask::make_shared(ts, i, _optimizers[i], outputFile));

		// wait for all tasks to complete
		_taskScheduler->WaitAll();
		_taskScheduler->Clear();
	} while(ts->getRecordsCnt() == _batchSize);
	LOG4CPLUS_DEBUG(_logger, "Compression done");
}

void ParallelTSCompressor::Decompress(File& inputFile, File& outputFile, FileDefinition& def)
{
	LOG4CPLUS_DEBUG(_logger, "Starting decompression");
	CUDA_CALL( cudaGetLastError() );

	// Create part of time series
	SharedTimeSeriesPtr ts = TimeSeries::make_shared(def);

	// read size of data chunk
	size_t size = 0;
	int i = 0;
	while(!inputFile.ReadRaw((char*)&size, sizeof(size_t)))
	{
		if(!_initialized) init(ts);

		// read data from file and save as ts column
		ts->getColumn(i).reserveSize(size);
		inputFile.ReadRaw(ts->getColumn(i).getData(), size);

		// schedule decompression task
		_taskScheduler->Schedule(DecompressionTask::make_shared(ts, i++));
		if(i == _columnNumber)
		{
			LOG4CPLUS_DEBUG(_logger, "SYNC!");
			i = 0;

			// wait for all tasks to complete
			_taskScheduler->WaitAll();
			_taskScheduler->Clear();

			// write part of time series to file
			ts->updateRecordsCnt();
			_reader->Write(outputFile, *ts);
			LOG4CPLUS_DEBUG_FMT(_logger, "%d records written to a file", ts->getRecordsCnt());
		}
	}
	LOG4CPLUS_DEBUG(_logger, "Decompression done");
}

} /* namespace ddj */

max_stars_repo_licenses: MIT Unlicense

max_issues_repo_licenses: MIT Unlicense

max_forks_repo_licenses: MIT Unlicense