<commit_before>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript 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.
 *
 * Cycript 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 Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#include <sstream>

#include "Decode.hpp"
#include "Replace.hpp"

CYTypedIdentifier *Decode_(CYPool &pool, struct sig::Type *type) {
    switch (type->primitive) {
        case sig::unknown_P: return $ CYTypedIdentifier($ CYTypeError());

        case sig::function_P: {
            _assert(type->data.signature.count != 0);
            CYTypedParameter *parameter(NULL);
            for (size_t i(type->data.signature.count - 1); i != 0; --i)
                parameter = $ CYTypedParameter(Decode(pool, type->data.signature.elements[i].type), parameter);
            return Decode(pool, type->data.signature.elements[0].type)->Modify($ CYTypeFunctionWith(parameter));
        } break;

        case sig::typename_P: return $ CYTypedIdentifier($ CYTypeVariable("Class"));
        case sig::union_P: _assert(false); break;
        case sig::string_P: return $ CYTypedIdentifier($ CYTypeVariable("char"), $ CYTypePointerTo());
        case sig::selector_P: return $ CYTypedIdentifier($ CYTypeVariable("SEL"));

        case sig::block_P: {
            _assert(type->data.signature.count != 0);
            CYTypedParameter *parameter(NULL);
            for (size_t i(type->data.signature.count - 1); i != 0; --i)
                parameter = $ CYTypedParameter(Decode(pool, type->data.signature.elements[i].type), parameter);
            return Decode(pool, type->data.signature.elements[0].type)->Modify($ CYTypeBlockWith(parameter));
        } break;

        case sig::object_P: {
            if (type->name == NULL)
                return $ CYTypedIdentifier($ CYTypeVariable("id"));
            else
                return $ CYTypedIdentifier($ CYTypeVariable(type->name), $ CYTypePointerTo());
        } break;

        case sig::boolean_P: return $ CYTypedIdentifier($ CYTypeVariable("bool"));
        case sig::uchar_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeVariable("char")));
        case sig::uint_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeVariable("int")));
        case sig::ulong_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeLong($ CYTypeVariable("int"))));
        case sig::ulonglong_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeLong($ CYTypeLong($ CYTypeVariable("int")))));
        case sig::ushort_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeShort($ CYTypeVariable("int"))));
        case sig::array_P: return Decode(pool, type->data.data.type)->Modify($ CYTypeArrayOf($D(type->data.data.size)));

        case sig::pointer_P: {
            CYTypedIdentifier *typed;
            if (type->data.data.type == NULL)
                typed = $ CYTypedIdentifier($ CYTypeVoid());
            else
                typed = Decode(pool, type->data.data.type);
            return typed->Modify($ CYTypePointerTo());
        } break;

        case sig::bit_P: _assert(false); break;
        case sig::char_P: return $ CYTypedIdentifier($ CYTypeVariable("char"));
        case sig::double_P: return $ CYTypedIdentifier($ CYTypeVariable("double"));
        case sig::float_P: return $ CYTypedIdentifier($ CYTypeVariable("float"));
        case sig::int_P: return $ CYTypedIdentifier($ CYTypeVariable("int"));
        case sig::long_P: return $ CYTypedIdentifier($ CYTypeLong($ CYTypeVariable("int")));
        case sig::longlong_P: return $ CYTypedIdentifier($ CYTypeLong($ CYTypeLong($ CYTypeVariable("int"))));
        case sig::short_P: return $ CYTypedIdentifier($ CYTypeShort($ CYTypeVariable("int")));

        case sig::void_P: return $ CYTypedIdentifier($ CYTypeVoid());

        case sig::struct_P: {
            _assert(type->name != NULL);
            return $ CYTypedIdentifier($ CYTypeVariable(type->name));
        } break;
    }

    _assert(false);
    return NULL;
}

CYTypedIdentifier *Decode(CYPool &pool, struct sig::Type *type) {
    CYTypedIdentifier *typed(Decode_(pool, type));
    if ((type->flags & JOC_TYPE_CONST) != 0) {
        if (type->primitive == sig::string_P)
            typed->modifier_ = $ CYTypeConstant(typed->modifier_);
        else
            typed = typed->Modify($ CYTypeConstant());
    }
    return typed;
}
<commit_msg>Unknown block arguments can decode to NSBlock *.<commit_after>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript 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.
 *
 * Cycript 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 Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#include <sstream>

#include "Decode.hpp"
#include "Replace.hpp"

CYTypedIdentifier *Decode_(CYPool &pool, struct sig::Type *type) {
    switch (type->primitive) {
        case sig::unknown_P: return $ CYTypedIdentifier($ CYTypeError());

        case sig::function_P: {
            _assert(type->data.signature.count != 0);
            CYTypedParameter *parameter(NULL);
            for (size_t i(type->data.signature.count - 1); i != 0; --i)
                parameter = $ CYTypedParameter(Decode(pool, type->data.signature.elements[i].type), parameter);
            return Decode(pool, type->data.signature.elements[0].type)->Modify($ CYTypeFunctionWith(parameter));
        } break;

        case sig::typename_P: return $ CYTypedIdentifier($ CYTypeVariable("Class"));
        case sig::union_P: _assert(false); break;
        case sig::string_P: return $ CYTypedIdentifier($ CYTypeVariable("char"), $ CYTypePointerTo());
        case sig::selector_P: return $ CYTypedIdentifier($ CYTypeVariable("SEL"));

        case sig::block_P: {
            if (type->data.signature.count == 0)
                return $ CYTypedIdentifier($ CYTypeVariable("NSBlock"), $ CYTypePointerTo());
            else {
                CYTypedParameter *parameter(NULL);
                for (size_t i(type->data.signature.count - 1); i != 0; --i)
                    parameter = $ CYTypedParameter(Decode(pool, type->data.signature.elements[i].type), parameter);
                return Decode(pool, type->data.signature.elements[0].type)->Modify($ CYTypeBlockWith(parameter));
            }
        } break;

        case sig::object_P: {
            if (type->name == NULL)
                return $ CYTypedIdentifier($ CYTypeVariable("id"));
            else
                return $ CYTypedIdentifier($ CYTypeVariable(type->name), $ CYTypePointerTo());
        } break;

        case sig::boolean_P: return $ CYTypedIdentifier($ CYTypeVariable("bool"));
        case sig::uchar_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeVariable("char")));
        case sig::uint_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeVariable("int")));
        case sig::ulong_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeLong($ CYTypeVariable("int"))));
        case sig::ulonglong_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeLong($ CYTypeLong($ CYTypeVariable("int")))));
        case sig::ushort_P: return $ CYTypedIdentifier($ CYTypeUnsigned($ CYTypeShort($ CYTypeVariable("int"))));
        case sig::array_P: return Decode(pool, type->data.data.type)->Modify($ CYTypeArrayOf($D(type->data.data.size)));

        case sig::pointer_P: {
            CYTypedIdentifier *typed;
            if (type->data.data.type == NULL)
                typed = $ CYTypedIdentifier($ CYTypeVoid());
            else
                typed = Decode(pool, type->data.data.type);
            return typed->Modify($ CYTypePointerTo());
        } break;

        case sig::bit_P: _assert(false); break;
        case sig::char_P: return $ CYTypedIdentifier($ CYTypeVariable("char"));
        case sig::double_P: return $ CYTypedIdentifier($ CYTypeVariable("double"));
        case sig::float_P: return $ CYTypedIdentifier($ CYTypeVariable("float"));
        case sig::int_P: return $ CYTypedIdentifier($ CYTypeVariable("int"));
        case sig::long_P: return $ CYTypedIdentifier($ CYTypeLong($ CYTypeVariable("int")));
        case sig::longlong_P: return $ CYTypedIdentifier($ CYTypeLong($ CYTypeLong($ CYTypeVariable("int"))));
        case sig::short_P: return $ CYTypedIdentifier($ CYTypeShort($ CYTypeVariable("int")));

        case sig::void_P: return $ CYTypedIdentifier($ CYTypeVoid());

        case sig::struct_P: {
            _assert(type->name != NULL);
            return $ CYTypedIdentifier($ CYTypeVariable(type->name));
        } break;
    }

    _assert(false);
    return NULL;
}

CYTypedIdentifier *Decode(CYPool &pool, struct sig::Type *type) {
    CYTypedIdentifier *typed(Decode_(pool, type));
    if ((type->flags & JOC_TYPE_CONST) != 0) {
        if (type->primitive == sig::string_P)
            typed->modifier_ = $ CYTypeConstant(typed->modifier_);
        else
            typed = typed->Modify($ CYTypeConstant());
    }
    return typed;
}
<|endoftext|>


<commit_before>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008, 2009 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

Redistribution and use of HOOMD-blue, 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 the copyright holder nor the names of HOOMD-blue's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR
ANY WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/

// $Id$
// $URL$
// Maintainer: joaander

// temporarily work around issues with the new boost fileystem libraries
// http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/index.htm

//! Enable old boost::filesystem API (temporary fix)
#define BOOST_FILESYSTEM_VERSION 2

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4103 4244 )
#endif

#include <boost/python.hpp>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

using namespace boost::filesystem;

#include "PathUtils.h"
#include "HOOMDVersion.h"

#include <string>
#include <sstream>
#include <list>
#include <iostream>
using namespace std;

/*! \file hoomd.cc
    \brief Executable for running python scripts with the hoomd module builtin
*/

//! forward declaration of the inithoomd function that inits the python module from hoomd_module.cc
extern "C" void inithoomd();

//! A simple method for finding the hoomd_script python module
string find_hoomd_script()
    {
    // this works on the requirement in the hoomd build scripts that the python module is always
    // installed in lib/hoomd/python-module on linux and mac. On windows, it actually ends up in bin/python-module
    path exepath = path(getExePath());
    list<path> search_paths;
    search_paths.push_back(exepath / "python-module");                            // windows
    search_paths.push_back(exepath / ".." / "lib" / "hoomd" / "python-module");   // linux/mac
    search_paths.push_back(path(HOOMD_SOURCE_DIR) / "python-module");             // from source builds

    list<path>::iterator cur_path;
    for (cur_path = search_paths.begin(); cur_path != search_paths.end(); ++cur_path)
        {
        if (exists(*cur_path / "hoomd_script" / "__init__.py"))
            return cur_path->native_file_string();
        }

    cerr << endl
         << "***Error! HOOMD python-module directory not found. Check your HOOMD directory structure." << endl;
    cerr << "Searched for hoomd_script in:" << endl;
    for (cur_path = search_paths.begin(); cur_path != search_paths.end(); ++cur_path)
        {
        cerr << cur_path->native_file_string() << endl;
        }

    return "";
    }

//! Main function for the executable
/*! \param argc argument count
    \param argv arguments
    Loads up the hoomd python module and then passes control onto Py_Main
*/
int main(int argc, char **argv)
    {
    if (argc == 1)
        {
        // This shell is an interactive launch with no arguments
        cout << "Launching intractive python shell now.... run \"from hoomd_script import *\" to load the HOOMD-blue python module" << endl << endl;
        }

    char module_name[] = "hoomd";
    PyImport_AppendInittab(module_name, &inithoomd);
    Py_Initialize();

    // Need to inject the hoomd module path and the plugins dir into sys.path
    string python_cmds("import sys\n");
    if (getenv("HOOMD_PLUGINS_DIR"))
        {
        string hoomd_plugins_dir = string(getenv("HOOMD_PLUGINS_DIR"));
        python_cmds += string("sys.path.insert(0, r\"") + hoomd_plugins_dir + string("\")\n");
        cout << "Notice: Using hoomd plugins in " << hoomd_plugins_dir << endl;
        }

    string hoomd_script_dir = find_hoomd_script();
    if (hoomd_script_dir != "")
        {
        python_cmds += string("sys.path.insert(0, r\"") + hoomd_script_dir + string("\")\n");
        }
    PyRun_SimpleString(python_cmds.c_str());

    int retval = Py_Main(argc, argv);

    // trying to clean up python's messy memory leaks
    Py_Finalize();
    return retval;
    }
#ifdef WIN32
#pragma warning( pop )
#endif

<commit_msg>Insert plugins and script dir in opposite order so that an installed hoomd_script doesn't shadow one set in the environment<commit_after>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008, 2009 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

Redistribution and use of HOOMD-blue, 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 the copyright holder nor the names of HOOMD-blue's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR
ANY WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/

// $Id$
// $URL$
// Maintainer: joaander

// temporarily work around issues with the new boost fileystem libraries
// http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/index.htm

//! Enable old boost::filesystem API (temporary fix)
#define BOOST_FILESYSTEM_VERSION 2

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4103 4244 )
#endif

#include <boost/python.hpp>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

using namespace boost::filesystem;

#include "PathUtils.h"
#include "HOOMDVersion.h"

#include <string>
#include <sstream>
#include <list>
#include <iostream>
using namespace std;

/*! \file hoomd.cc
    \brief Executable for running python scripts with the hoomd module builtin
*/

//! forward declaration of the inithoomd function that inits the python module from hoomd_module.cc
extern "C" void inithoomd();

//! A simple method for finding the hoomd_script python module
string find_hoomd_script()
    {
    // this works on the requirement in the hoomd build scripts that the python module is always
    // installed in lib/hoomd/python-module on linux and mac. On windows, it actually ends up in bin/python-module
    path exepath = path(getExePath());
    list<path> search_paths;
    search_paths.push_back(exepath / "python-module");                            // windows
    search_paths.push_back(exepath / ".." / "lib" / "hoomd" / "python-module");   // linux/mac
    search_paths.push_back(path(HOOMD_SOURCE_DIR) / "python-module");             // from source builds

    list<path>::iterator cur_path;
    for (cur_path = search_paths.begin(); cur_path != search_paths.end(); ++cur_path)
        {
        if (exists(*cur_path / "hoomd_script" / "__init__.py"))
            return cur_path->native_file_string();
        }

    cerr << endl
         << "***Error! HOOMD python-module directory not found. Check your HOOMD directory structure." << endl;
    cerr << "Searched for hoomd_script in:" << endl;
    for (cur_path = search_paths.begin(); cur_path != search_paths.end(); ++cur_path)
        {
        cerr << cur_path->native_file_string() << endl;
        }

    return "";
    }

//! Main function for the executable
/*! \param argc argument count
    \param argv arguments
    Loads up the hoomd python module and then passes control onto Py_Main
*/
int main(int argc, char **argv)
    {
    if (argc == 1)
        {
        // This shell is an interactive launch with no arguments
        cout << "Launching intractive python shell now.... run \"from hoomd_script import *\" to load the HOOMD-blue python module" << endl << endl;
        }

    char module_name[] = "hoomd";
    PyImport_AppendInittab(module_name, &inithoomd);
    Py_Initialize();

    // Need to inject the hoomd module path and the plugins dir into sys.path
    string python_cmds("import sys\n");
    string hoomd_script_dir = find_hoomd_script();
    if (hoomd_script_dir != "")
        {
        python_cmds += string("sys.path.insert(0, r\"") + hoomd_script_dir + string("\")\n");
        }

    if (getenv("HOOMD_PLUGINS_DIR"))
        {
        string hoomd_plugins_dir = string(getenv("HOOMD_PLUGINS_DIR"));
        python_cmds += string("sys.path.insert(0, r\"") + hoomd_plugins_dir + string("\")\n");
        cout << "Notice: Using hoomd plugins in " << hoomd_plugins_dir << endl;
        }

    PyRun_SimpleString(python_cmds.c_str());

    int retval = Py_Main(argc, argv);

    // trying to clean up python's messy memory leaks
    Py_Finalize();
    return retval;
    }
#ifdef WIN32
#pragma warning( pop )
#endif

<|endoftext|>


<commit_before>#include "mtpobjectsmodel.h"
#include <QDebug>
#include <QBrush>
#include <QColor>
#include <QFile>
#include <QFileInfo>

MtpObjectsModel::MtpObjectsModel(QObject *parent): QAbstractListModel(parent)
{ }

MtpObjectsModel::~MtpObjectsModel()
{ }

void MtpObjectsModel::setParent(mtp::u32 parentObjectId)
{
	beginResetModel();

	_parentObjectId = parentObjectId;
	mtp::msg::ObjectHandles handles = _session->GetObjectHandles(mtp::Session::AllStorages, mtp::Session::AllFormats, parentObjectId);
	_rows.clear();
	_rows.reserve(handles.ObjectHandles.size());
	for(size_t i = 0; i < handles.ObjectHandles.size(); ++i)
	{
		mtp::u32 oid = handles.ObjectHandles[i];
		_rows.append(Row(oid));
	}

	endResetModel();
}

bool MtpObjectsModel::enter(int idx)
{
	if (idx < 0 || idx >= _rows.size())
		return false;

	Row &row = _rows[idx];
	if (row.GetInfo(_session)->ObjectFormat == (mtp::u16)mtp::ObjectFormat::Association)
	{
		setParent(row.ObjectId);
		return true;
	}
	else
		return false;
}

void MtpObjectsModel::setSession(mtp::SessionPtr session)
{
	beginResetModel();
	_session = session;
	setParent(mtp::Session::Root);
	endResetModel();
}

int MtpObjectsModel::rowCount(const QModelIndex &) const
{ return _rows.size(); }

std::shared_ptr<mtp::msg::ObjectInfo> MtpObjectsModel::Row::GetInfo(mtp::SessionPtr session)
{
	if (!_info)
	{
		_info = std::make_shared<mtp::msg::ObjectInfo>();
		try
		{
			*_info = session->GetObjectInfo(ObjectId);
			//qDebug() << QString::fromUtf8(row.Info->Filename.c_str());
		}
		catch(const std::exception &ex)
		{ qDebug() << "failed to get object info " << ex.what(); }
	}
	return _info;
}

bool MtpObjectsModel::removeRows (int row, int count, const QModelIndex & parent )
{
	qDebug() << "remove rows " << row << " " << count;
	beginRemoveRows(parent, row, row + count - 1);
	for(int i = 0; i < count; ++i)
	{
		mtp::u32 oid = objectIdAt(row + i);
		if (oid == 0)
			continue;
		_session->DeleteObject(oid);
	}
	_rows.remove(row, count);

	endRemoveRows();
	return false;
}

mtp::u32 MtpObjectsModel::objectIdAt(int idx)
{
	return (idx >= 0 && idx < _rows.size())? _rows[idx].ObjectId: 0;
}

QVariant MtpObjectsModel::data(const QModelIndex &index, int role) const
{
	int row_idx = index.row();
	if (row_idx < 0 || row_idx > _rows.size())
		return QVariant();

	Row &row = _rows[row_idx];

	switch(role)
	{
	case Qt::DisplayRole:
		return QString::fromUtf8(row.GetInfo(_session)->Filename.c_str());

	case Qt::ForegroundRole:
		return row.GetInfo(_session)->ObjectFormat == (mtp::u16)mtp::ObjectFormat::Association? QBrush(QColor(0, 0, 128)): QBrush(Qt::black);

	default:
		return QVariant();
	}
}

mtp::u32 MtpObjectsModel::createDirectory(const QString &name)
{
	mtp::msg::ObjectInfo oi;
	QByteArray filename = name.toUtf8();
	oi.Filename = filename.data();
	oi.ObjectFormat = (mtp::u16)mtp::ObjectFormat::Association;
	mtp::Session::NewObjectInfo noi = _session->SendObjectInfo(oi, 0, _parentObjectId);
	beginInsertRows(QModelIndex(), _rows.size(), _rows.size());
	_rows.push_back(Row(noi.ObjectId));
	endInsertRows();
	return noi.ObjectId;
}

bool MtpObjectsModel::uploadFile(const QString &filename)
{
	QFileInfo fileInfo(filename);
	qDebug() << "uploadFile " << fileInfo.fileName();
	QString ext = fileInfo.suffix();
	mtp::ObjectFormat objectFormat;
	if (ext == "mp3")
		objectFormat = mtp::ObjectFormat::Mp3;
	else if (ext == "txt")
		objectFormat = mtp::ObjectFormat::Text;
	else if (ext == "jpeg" || ext == "jpg")
		objectFormat = mtp::ObjectFormat::Jfif;
	else if (ext == "gif")
		objectFormat = mtp::ObjectFormat::Gif;
	else if (ext == "bmp")
		objectFormat = mtp::ObjectFormat::Bmp;
	else if (ext == "png")
		objectFormat = mtp::ObjectFormat::Png;
	else
	{
		qDebug() << "unknown file type " << ext;
		return false;
	}

	mtp::ByteArray data;
	{
		QFile file(filename);
		file.open(QFile::ReadOnly);
		if (!file.isOpen())
		{
			qWarning() << "file " << filename << " could not be opened";
			return false;
		}
		QByteArray qdata = file.readAll();
		file.close();
		data.assign(qdata.begin(), qdata.end());
	}
	qDebug() << "sending " << data.size() << " bytes";

	mtp::msg::ObjectInfo oi;
	QByteArray filename_utf = fileInfo.fileName().toUtf8();
	oi.Filename = filename_utf.data();
	oi.ObjectFormat = (mtp::u16)objectFormat;
	oi.ObjectCompressedSize = data.size();
	mtp::Session::NewObjectInfo noi = _session->SendObjectInfo(oi, 0, _parentObjectId);
	qDebug() << "new object id: " << noi.ObjectId << ", sending...";
	_session->SendObject(data);
	qDebug() << "ok";
	beginInsertRows(QModelIndex(), _rows.size(), _rows.size());
	_rows.push_back(Row(noi.ObjectId));
	endInsertRows();
	return true;
}
<commit_msg>do not reset on same parent id<commit_after>#include "mtpobjectsmodel.h"
#include <QDebug>
#include <QBrush>
#include <QColor>
#include <QFile>
#include <QFileInfo>

MtpObjectsModel::MtpObjectsModel(QObject *parent): QAbstractListModel(parent)
{ }

MtpObjectsModel::~MtpObjectsModel()
{ }

void MtpObjectsModel::setParent(mtp::u32 parentObjectId)
{
	if (_parentObjectId == parentObjectId)
		return;

	beginResetModel();

	_parentObjectId = parentObjectId;
	mtp::msg::ObjectHandles handles = _session->GetObjectHandles(mtp::Session::AllStorages, mtp::Session::AllFormats, parentObjectId);
	_rows.clear();
	_rows.reserve(handles.ObjectHandles.size());
	for(size_t i = 0; i < handles.ObjectHandles.size(); ++i)
	{
		mtp::u32 oid = handles.ObjectHandles[i];
		_rows.append(Row(oid));
	}

	endResetModel();
}

bool MtpObjectsModel::enter(int idx)
{
	if (idx < 0 || idx >= _rows.size())
		return false;

	Row &row = _rows[idx];
	if (row.GetInfo(_session)->ObjectFormat == (mtp::u16)mtp::ObjectFormat::Association)
	{
		setParent(row.ObjectId);
		return true;
	}
	else
		return false;
}

void MtpObjectsModel::setSession(mtp::SessionPtr session)
{
	beginResetModel();
	_session = session;
	setParent(mtp::Session::Root);
	endResetModel();
}

int MtpObjectsModel::rowCount(const QModelIndex &) const
{ return _rows.size(); }

std::shared_ptr<mtp::msg::ObjectInfo> MtpObjectsModel::Row::GetInfo(mtp::SessionPtr session)
{
	if (!_info)
	{
		_info = std::make_shared<mtp::msg::ObjectInfo>();
		try
		{
			*_info = session->GetObjectInfo(ObjectId);
			//qDebug() << QString::fromUtf8(row.Info->Filename.c_str());
		}
		catch(const std::exception &ex)
		{ qDebug() << "failed to get object info " << ex.what(); }
	}
	return _info;
}

bool MtpObjectsModel::removeRows (int row, int count, const QModelIndex & parent )
{
	qDebug() << "remove rows " << row << " " << count;
	beginRemoveRows(parent, row, row + count - 1);
	for(int i = 0; i < count; ++i)
	{
		mtp::u32 oid = objectIdAt(row + i);
		if (oid == 0)
			continue;
		_session->DeleteObject(oid);
	}
	_rows.remove(row, count);

	endRemoveRows();
	return false;
}

mtp::u32 MtpObjectsModel::objectIdAt(int idx)
{
	return (idx >= 0 && idx < _rows.size())? _rows[idx].ObjectId: 0;
}

QVariant MtpObjectsModel::data(const QModelIndex &index, int role) const
{
	int row_idx = index.row();
	if (row_idx < 0 || row_idx > _rows.size())
		return QVariant();

	Row &row = _rows[row_idx];

	switch(role)
	{
	case Qt::DisplayRole:
		return QString::fromUtf8(row.GetInfo(_session)->Filename.c_str());

	case Qt::ForegroundRole:
		return row.GetInfo(_session)->ObjectFormat == (mtp::u16)mtp::ObjectFormat::Association? QBrush(QColor(0, 0, 128)): QBrush(Qt::black);

	default:
		return QVariant();
	}
}

mtp::u32 MtpObjectsModel::createDirectory(const QString &name)
{
	mtp::msg::ObjectInfo oi;
	QByteArray filename = name.toUtf8();
	oi.Filename = filename.data();
	oi.ObjectFormat = (mtp::u16)mtp::ObjectFormat::Association;
	mtp::Session::NewObjectInfo noi = _session->SendObjectInfo(oi, 0, _parentObjectId);
	beginInsertRows(QModelIndex(), _rows.size(), _rows.size());
	_rows.push_back(Row(noi.ObjectId));
	endInsertRows();
	return noi.ObjectId;
}

bool MtpObjectsModel::uploadFile(const QString &filename)
{
	QFileInfo fileInfo(filename);
	qDebug() << "uploadFile " << fileInfo.fileName();
	QString ext = fileInfo.suffix();
	mtp::ObjectFormat objectFormat;
	if (ext == "mp3")
		objectFormat = mtp::ObjectFormat::Mp3;
	else if (ext == "txt")
		objectFormat = mtp::ObjectFormat::Text;
	else if (ext == "jpeg" || ext == "jpg")
		objectFormat = mtp::ObjectFormat::Jfif;
	else if (ext == "gif")
		objectFormat = mtp::ObjectFormat::Gif;
	else if (ext == "bmp")
		objectFormat = mtp::ObjectFormat::Bmp;
	else if (ext == "png")
		objectFormat = mtp::ObjectFormat::Png;
	else
	{
		qDebug() << "unknown file type " << ext;
		return false;
	}

	mtp::ByteArray data;
	{
		QFile file(filename);
		file.open(QFile::ReadOnly);
		if (!file.isOpen())
		{
			qWarning() << "file " << filename << " could not be opened";
			return false;
		}
		QByteArray qdata = file.readAll();
		file.close();
		data.assign(qdata.begin(), qdata.end());
	}
	qDebug() << "sending " << data.size() << " bytes";

	mtp::msg::ObjectInfo oi;
	QByteArray filename_utf = fileInfo.fileName().toUtf8();
	oi.Filename = filename_utf.data();
	oi.ObjectFormat = (mtp::u16)objectFormat;
	oi.ObjectCompressedSize = data.size();
	mtp::Session::NewObjectInfo noi = _session->SendObjectInfo(oi, 0, _parentObjectId);
	qDebug() << "new object id: " << noi.ObjectId << ", sending...";
	_session->SendObject(data);
	qDebug() << "ok";
	beginInsertRows(QModelIndex(), _rows.size(), _rows.size());
	_rows.push_back(Row(noi.ObjectId));
	endInsertRows();
	return true;
}
<|endoftext|>


<commit_before>#include "sshtunnelout.h"
#include "sshclient.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QEventLoop>
#include <cerrno>

Q_LOGGING_CATEGORY(logsshtunnelout, "ssh.tunnelout", QtWarningMsg)

SshTunnelOut::SshTunnelOut(SshClient *client, QTcpSocket *tcpSocket, const QString &port_identifier, quint16 port, QObject *parent):
    QObject(parent),
    m_port(port),
    m_name(port_identifier),
    m_tcpsocket(tcpSocket),
    m_client(client),
    m_dataSsh(16384, 0),
    m_dataSocket(16384, 0)
{
    m_sshChannel = qssh2_channel_direct_tcpip(m_client->session(), "127.0.0.1", m_port);
    if(m_sshChannel == nullptr)
    {
        int ret = qssh2_session_last_error(m_client->session(), nullptr, nullptr, 0);
        if(ret != LIBSSH2_ERROR_CHANNEL_FAILURE)
        {
            qDebug() << "ERROR: Can't connect direct tcpip " << ret << " for port " << m_port;
        }
        else
        {
            qCDebug(logsshtunnelout) << "Can't connect direct tcpip " << ret << " for port " << m_port;
        }
        return;
    }

    QObject::connect(m_client,    &SshClient::sshDataReceived, this, &SshTunnelOut::sshDataReceived);
    QObject::connect(m_tcpsocket, &QTcpSocket::readyRead,      this, &SshTunnelOut::tcpDataReceived);
    QObject::connect(m_tcpsocket, &QTcpSocket::disconnected,   this, &SshTunnelOut::tcpDisconnected);
    QObject::connect(m_tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)),   this, SLOT(displayError(QAbstractSocket::SocketError)));

    qCDebug(logsshtunnelout) << "SshTunnelOut::SshTunnelOut() OK " << m_name;
    tcpDataReceived();
}

SshTunnelOut::~SshTunnelOut()
{
    qCDebug(logsshtunnelout) << "~SshTunnelOut() " << m_name << " " << this;
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }

    if (m_sshChannel == nullptr)
        return;

    int ret = qssh2_channel_close(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_close: LIBSSH2_ERROR_SOCKET_SEND";
        return;
    }

    ret = qssh2_channel_wait_closed(m_sshChannel);
    if(ret)
    {
        qDebug(logsshtunnelout) << "Failed to channel_wait_closed";
        return;
    }

    ret = qssh2_channel_free(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_free";
        return;
    }
}

void SshTunnelOut::disconectFromHost()
{
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }
}

QString SshTunnelOut::name() const
{
    return m_name;
}

void SshTunnelOut::sshDataReceived()
{
    if(!m_mutex.tryLock())
        return;

    ssize_t len = 0,wr = 0;
    qint64 i;

    do
    {
        /* Read data from SSH */
        /*
         * In this case, we must not used qssh2_channel_read
         * beacause we don't need to ProcessEvent to be locked
         * We can return, we will be recall at the next sshDataReceived
         */
        len = static_cast<ssize_t>(libssh2_channel_read(m_sshChannel, m_dataSsh.data(), static_cast<unsigned int>(m_dataSsh.size())));
        if(len == LIBSSH2_ERROR_EAGAIN)
        {
            m_mutex.unlock();
            return;
        }
        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " remote failed to read (" << len << " / " << m_dataSsh.size() << ")";
            m_mutex.unlock();
            return;
        }

        /* Write data into output local socket */
        wr = 0;
        if(m_tcpsocket != nullptr)
        {
            while (wr < len)
            {
                i = m_tcpsocket->write( m_dataSsh.mid(static_cast<int>(wr), static_cast<int>(len)));
                if (i <= 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " local failed to write (" << i << ")";
                    m_mutex.unlock();
                    return;
                }
                wr += i;
            }
        }
    }
    while(len == m_dataSsh.size());

    if (libssh2_channel_eof(m_sshChannel))
    {
        if(m_tcpsocket)
            m_tcpsocket->disconnectFromHost();
        qCDebug(logsshtunnelout) << "Disconnected from ssh";
        emit disconnectedFromSsh();
    }
    m_mutex.unlock();
}

void SshTunnelOut::tcpDataReceived()
{
    if(!m_mutex.tryLock())
        return;
    qint64 len = 0;
    ssize_t wr = 0;
    ssize_t i = 0;

    if (m_tcpsocket == nullptr || m_sshChannel == nullptr)
    {
        qCWarning(logsshtunnelout) <<  "ERROR : SshTunnelOut(" << m_name << ") : received TCP data but not seems to be a valid Tcp socket or channel not ready";
        m_mutex.unlock();
        return;
    }

    do
    {
        /* Read data from local socket */
        len = m_tcpsocket->read(m_dataSocket.data(), m_dataSocket.size());
        if (-EAGAIN == len)
        {
            qCDebug(logsshtunnelout) << m_name << "tcpDataReceived() EAGAIN";
            break;
        }

        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " local failed to read (" << len << ")";
            m_mutex.unlock();
            return;
        }

        if(len > 0)
        {
            do
            {
                i = qssh2_channel_write(m_sshChannel, m_dataSocket.data(), static_cast<size_t>(len));
                if (i < 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " remote failed to write (" << i << ")";
                    m_mutex.unlock();
                    return;
                }
                if (i == 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " qssh2_channel_write return 0";
                }
                wr += i;
            } while(i > 0 && wr < len);
        }
    }
    while(len > 0);
    m_mutex.unlock();
}

void SshTunnelOut::tcpDisconnected()
{
    qCDebug(logsshtunnelout) << "Disconnected from socket";
    m_tcpsocket->deleteLater();
    m_tcpsocket = nullptr;
    qssh2_channel_send_eof(m_sshChannel);
    emit disconnectedFromTcp();
}

void SshTunnelOut::displayError(QAbstractSocket::SocketError error)
{
    qCWarning(logsshtunnelout) << "ERROR : SshTunnelOut(" << m_name << ") : redirection socket error=" << error;
}

<commit_msg>SshTunnelOut: Delayed qssh2_channel_direct_tcpip creation outside constructor<commit_after>#include "sshtunnelout.h"
#include "sshclient.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QEventLoop>
#include <cerrno>

Q_LOGGING_CATEGORY(logsshtunnelout, "ssh.tunnelout", QtWarningMsg)

SshTunnelOut::SshTunnelOut(SshClient *client, QTcpSocket *tcpSocket, const QString &port_identifier, quint16 port, QObject *parent):
    QObject(parent),
    m_port(port),
    m_name(port_identifier),
    m_tcpsocket(tcpSocket),
    m_client(client),
    m_dataSsh(16384, 0),
    m_dataSocket(16384, 0)
{
    QObject::connect(m_client,    &SshClient::sshDataReceived, this, &SshTunnelOut::sshDataReceived);
    QObject::connect(m_tcpsocket, &QTcpSocket::readyRead,      this, &SshTunnelOut::tcpDataReceived);
    QObject::connect(m_tcpsocket, &QTcpSocket::disconnected,   this, &SshTunnelOut::tcpDisconnected);
    QObject::connect(m_tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)),   this, SLOT(displayError(QAbstractSocket::SocketError)));

    qCDebug(logsshtunnelout) << "SshTunnelOut::SshTunnelOut() OK " << m_name;
}

SshTunnelOut::~SshTunnelOut()
{
    qCDebug(logsshtunnelout) << "~SshTunnelOut() " << m_name << " " << this;
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }

    if (m_sshChannel == nullptr)
        return;

    int ret = qssh2_channel_close(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_close: LIBSSH2_ERROR_SOCKET_SEND";
        return;
    }

    ret = qssh2_channel_wait_closed(m_sshChannel);
    if(ret)
    {
        qDebug(logsshtunnelout) << "Failed to channel_wait_closed";
        return;
    }

    ret = qssh2_channel_free(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_free";
        return;
    }
}

void SshTunnelOut::disconectFromHost()
{
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }
}

QString SshTunnelOut::name() const
{
    return m_name;
}

void SshTunnelOut::sshDataReceived()
{
    if(!m_mutex.tryLock())
        return;

    ssize_t len = 0,wr = 0;
    qint64 i;

    do
    {
        /* Read data from SSH */
        /*
         * In this case, we must not used qssh2_channel_read
         * beacause we don't need to ProcessEvent to be locked
         * We can return, we will be recall at the next sshDataReceived
         */
        len = static_cast<ssize_t>(libssh2_channel_read(m_sshChannel, m_dataSsh.data(), static_cast<unsigned int>(m_dataSsh.size())));
        if(len == LIBSSH2_ERROR_EAGAIN)
        {
            m_mutex.unlock();
            return;
        }
        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " remote failed to read (" << len << " / " << m_dataSsh.size() << ")";
            m_mutex.unlock();
            return;
        }

        /* Write data into output local socket */
        wr = 0;
        if(m_tcpsocket != nullptr)
        {
            while (wr < len)
            {
                i = m_tcpsocket->write( m_dataSsh.mid(static_cast<int>(wr), static_cast<int>(len)));
                if (i <= 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " local failed to write (" << i << ")";
                    m_mutex.unlock();
                    return;
                }
                wr += i;
            }
        }
    }
    while(len == m_dataSsh.size());

    if (libssh2_channel_eof(m_sshChannel))
    {
        if(m_tcpsocket)
            m_tcpsocket->disconnectFromHost();
        qCDebug(logsshtunnelout) << "Disconnected from ssh";
        emit disconnectedFromSsh();
    }
    m_mutex.unlock();
}

void SshTunnelOut::tcpDataReceived()
{
    if(!m_mutex.tryLock())
    {
        return;
    }
    qint64 len = 0;
    ssize_t wr = 0;
    ssize_t i = 0;

    if(m_sshChannel == nullptr)
    {
        m_sshChannel = qssh2_channel_direct_tcpip(m_client->session(), "127.0.0.1", m_port);
        qCDebug(logsshtunnelout) << "SshTunnelOut::SshTunnelOut() " << m_name << " try to connect to " << m_port << " return " << m_sshChannel;

        if(m_sshChannel == nullptr)
        {
            int ret = qssh2_session_last_error(m_client->session(), nullptr, nullptr, 0);
            if(ret != LIBSSH2_ERROR_CHANNEL_FAILURE)
            {
                qDebug() << "ERROR: Can't connect direct tcpip " << ret << " for port " << m_port;
            }
            else
            {
                qCDebug(logsshtunnelout) << "Can't connect direct tcpip " << ret << " for port " << m_port;
            }
            return;
        }
    }

    if (m_tcpsocket == nullptr || m_sshChannel == nullptr)
    {
        qCWarning(logsshtunnelout) <<  "ERROR : SshTunnelOut(" << m_name << ") : received TCP data but not seems to be a valid Tcp socket or channel not ready";
        m_mutex.unlock();
        return;
    }

    do
    {
        /* Read data from local socket */
        len = m_tcpsocket->read(m_dataSocket.data(), m_dataSocket.size());
        if (-EAGAIN == len)
        {
            qCDebug(logsshtunnelout) << m_name << "tcpDataReceived() EAGAIN";
            break;
        }

        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " local failed to read (" << len << ")";
            m_mutex.unlock();
            return;
        }

        if(len > 0)
        {
            do
            {
                i = qssh2_channel_write(m_sshChannel, m_dataSocket.data(), static_cast<size_t>(len));
                if (i < 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " remote failed to write (" << i << ")";
                    m_mutex.unlock();
                    return;
                }
                if (i == 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " qssh2_channel_write return 0";
                }
                wr += i;
            } while(i > 0 && wr < len);
        }
    }
    while(len > 0);
    m_mutex.unlock();
}

void SshTunnelOut::tcpDisconnected()
{
    qCDebug(logsshtunnelout) << "Disconnected from socket";
    m_tcpsocket->deleteLater();
    m_tcpsocket = nullptr;
    qssh2_channel_send_eof(m_sshChannel);
    emit disconnectedFromTcp();
}

void SshTunnelOut::displayError(QAbstractSocket::SocketError error)
{
    qCWarning(logsshtunnelout) << "ERROR : SshTunnelOut(" << m_name << ") : redirection socket error=" << error;
}

<|endoftext|>


<commit_before>
#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include "Car.h"
#include "Engine.h"
#include "Global.h"

Engine::Engine(){
  setMinSpeed(900);
  setMaxSpeed(4096);
  setStopSpeed(0);
  setPace(getMinSpeed());
  setTransmission('a');
}

Engine::Engine(int pinL,int pinR){
  _pinL = pinL;
  _pinR = pinR;
  setMinSpeed(704);
  setMaxSpeed(4096);
  setStopSpeed(0);
  setPace(getMinSpeed());
  setTransmission('a');
  //changeGear();
}
void Engine::setPinL(int pinL){
  _pinL = pinL;
}
void Engine::setPinR(int pinR){
  _pinR = pinR;
}
int Engine::getPinL(){
  return _pinL;
}
int Engine::getPinR(){
  return _pinR;
}

void Engine::setStopSpeed(int sp){
  stopSpeed = sp;
}
int Engine::getStopSpeed(){
  return stopSpeed;
}
void Engine::setMaxSpeed(int sp){
  maxSpeed = sp;
}
int Engine::getMaxSpeed(){
  return maxSpeed;
}
void Engine::setMinSpeed(int sp){
  minSpeed = sp;
}
int Engine::getMinSpeed(){
  return minSpeed;
}

int Engine::getPace(){
  return pace;
}

void Engine::setPace(int val){
   //Wouldn't wanna accelerate over the max speed
  if(val <= getMaxSpeed() && val >= getMinSpeed()){
    pace = val;
  }
}

void Engine::setGear(char g){
  gear = g;
}

char Engine::getGear(){
  return gear;
}
void Engine::halt(Adafruit_PWMServoDriver pwm){
  pwm.setPin(getPinL(),getStopSpeed());
  pwm.setPin(getPinR(),getStopSpeed());
  setPace(getMinSpeed());
  Serial.print("Stopped ");
  Serial.println(getPace());
}

void Engine::setTransmission(char s){
  transmission = s;
}

char Engine::getTransmission(){
  return transmission;
}

void Engine::throttle(Adafruit_PWMServoDriver pwm){

  switch(getGear()){
    case '1':
        setMaxSpeed(gear1);
        setGear('1');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
            changeGear();
        }while(pace<getMaxSpeed());

        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '2':
        setMaxSpeed(gear2);
        setGear('2');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();
        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '3':
        setMaxSpeed(gear3);
        setGear('3');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();
        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '4':
        setMaxSpeed(gear4);
        setGear('4');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();
        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '5':
        setMaxSpeed(gear5);
        setGear('5');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();

    ////////////////////////////////////////////////////////////////////////////////
        break;
    ////////////////////////////////////////////////////////////////////////////////

      case 'p':
        setMaxSpeed(parking);
        setPace(parking);
        pwm.setPin(getPinL(),parking);
        pwm.setPin(getPinR(),parking);
        Serial.print("Parking...");
        Serial.println(getPace());
        break;
    }
}

char Engine::checkGear(){
  switch(pace){
    case parking:
        return 'p';
        break;
    case parking+1 ... gear1:
        return '1';
        break;
    case gear1+1 ... gear2:
        return '2';
        break;
    case gear2+1 ... gear3:
        return '3';
        break;
    case gear3+1 ... gear4:
        return '4';
        break;
    case gear4+1 ... gear5:
        return '5';
        break;
    default:
        return 'n';
        Serial.print("Neutral");
        break;
   }
}

void Engine::changeGear(){
  //checkGear();
  switch(getTransmission()){
    case 'a':
        if(getMaxSpeed() == gear1){
          setPace(gear1+1); // add more pace so that gear changes and a new maxspeed is set
        }else if(getMaxSpeed() == gear2){
          setPace(gear2+1);
        }
        else if(getMaxSpeed() == gear3){
          setPace(gear3+1);
        }
        else if(getMaxSpeed() == gear4){
          setPace(gear4+1); // head over to gear five, the last gear
        }
    break;
    case 's':
    break;

    ///////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////     MANUAL TRANSMISSION     /////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////

    case 'm':
      //setGear('n');
      switch(getGear()){
        // For any of these gears...
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
          if (getGear() != checkGear()){ // meaning possibly the user switched gears but...
            // its is not the gear the transmission is in right now
            // Now all the logic for automatic gear shifting with a tiny twist

            //////////////////////////////////////////////////////////
            /////////////////       UP SHIFTING     //////////////////
            //////////////////////////////////////////////////////////

            if(getPace() <= gear1 && getPace() > getStopSpeed()){
              setGear('1'); // set gear to next level;
              // then throttle at this gear
              throttle(pwm);
            }else if(getPace() <= gear2 && getPace() > gear1){
              setGear('2');
              // then throttle at this gear
              throttle(pwm);
            }
            else if(getPace() <= gear3 && getPace() > gear2){
              setGear('3');
              // then throttle at this gear
              throttle(pwm);
            }
            else if(getPace() <= gear4 && getPace() > gear3){
              setGear('4');
              // then throttle at this gear
              throttle(pwm);
            }else{
              setGear('5');
              // then throttle at this gear
              throttle(pwm);
            }

            //////////////////////////////////////////////////////////
            ////////////////       DOWN SHIFTING     /////////////////
            //////////////////////////////////////////////////////////

          }
        break;
      }// End MANUAL TRANSMISSION
    break;
  }
}

void Engine::channelize(Adafruit_PWMServoDriver pwm){
  setPace(pace-819);
  pwm.setPin(getPinL(),pace);
  pwm.setPin(getPinR(),pace);
  Serial.println(getPace());
}

<commit_msg>Manual transmission working<commit_after>
#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include "Car.h"
#include "Engine.h"
#include "Global.h"

Engine::Engine(){
  setMinSpeed(900);
  setMaxSpeed(4096);
  setStopSpeed(0);
  setPace(getMinSpeed());
  setTransmission('a');
}

Engine::Engine(int pinL,int pinR){
  _pinL = pinL;
  _pinR = pinR;
  setMinSpeed(704);
  setMaxSpeed(4096);
  setStopSpeed(0);
  setPace(getMinSpeed());
  setTransmission('a');
  //changeGear();
}
void Engine::setPinL(int pinL){
  _pinL = pinL;
}
void Engine::setPinR(int pinR){
  _pinR = pinR;
}
int Engine::getPinL(){
  return _pinL;
}
int Engine::getPinR(){
  return _pinR;
}

void Engine::setStopSpeed(int sp){
  stopSpeed = sp;
}
int Engine::getStopSpeed(){
  return stopSpeed;
}
void Engine::setMaxSpeed(int sp){
  maxSpeed = sp;
}
int Engine::getMaxSpeed(){
  return maxSpeed;
}
void Engine::setMinSpeed(int sp){
  minSpeed = sp;
}
int Engine::getMinSpeed(){
  return minSpeed;
}

int Engine::getPace(){
  return pace;
}

void Engine::setPace(int val){
   //Wouldn't wanna accelerate over the max speed
  if(val <= getMaxSpeed() && val >= getMinSpeed()){
    pace = val;
  }
}

void Engine::setGear(char g){
  gear = g;
}

char Engine::getGear(){
  return gear;
}
void Engine::halt(Adafruit_PWMServoDriver pwm){
  pwm.setPin(getPinL(),getStopSpeed());
  pwm.setPin(getPinR(),getStopSpeed());
  setPace(getMinSpeed());
  Serial.print("Stopped ");
  Serial.println(getPace());
}

void Engine::setTransmission(char s){
  transmission = s;
}

char Engine::getTransmission(){
  return transmission;
}

void Engine::throttle(Adafruit_PWMServoDriver pwm){

  switch(getGear()){
    case '1':
        setMaxSpeed(gear1);
        setGear('1');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
            changeGear();
        }while(pace<getMaxSpeed());

        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '2':
        setMaxSpeed(gear2);
        setGear('2');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();
        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '3':
        setMaxSpeed(gear3);
        setGear('3');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();
        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '4':
        setMaxSpeed(gear4);
        setGear('4');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();
        if(getTransmission() != 'a'){
          break; // else woun't break out of the loop so that gears can change in auto
        }
    case '5':
        setMaxSpeed(gear5);
        setGear('5');
        do{
            pwm.setPin(getPinL(),pace);
            pwm.setPin(getPinR(),pace);
            setPace(pace+1);
            Serial.println(getPace());
        }while(pace<getMaxSpeed());
        changeGear();

    ////////////////////////////////////////////////////////////////////////////////
      break;
    ////////////////////////////////////////////////////////////////////////////////

      case 'p':
        setMaxSpeed(parking);
        setPace(parking);
        pwm.setPin(getPinL(),parking);
        pwm.setPin(getPinR(),parking);
        Serial.print("Parking...");
        Serial.println(getPace());
        break;
    }
}

char Engine::checkGear(){
  switch(pace){
    case parking:
        return 'p';
        break;
    case parking+1 ... gear1:
        return '1';
        break;
    case gear1+1 ... gear2:
        return '2';
        break;
    case gear2+1 ... gear3:
        return '3';
        break;
    case gear3+1 ... gear4:
        return '4';
        break;
    case gear4+1 ... gear5:
        return '5';
        break;
    default:
        return 'n';
        Serial.print("Neutral");
        break;
   }
}

void Engine::changeGear(){
  //checkGear();
  switch(getTransmission()){
    case 'a':
        if(getMaxSpeed() == gear1){
          setPace(gear1+1); // add more pace so that gear changes and a new maxspeed is set
        }else if(getMaxSpeed() == gear2){
          setPace(gear2+1);
        }
        else if(getMaxSpeed() == gear3){
          setPace(gear3+1);
        }
        else if(getMaxSpeed() == gear4){
          setPace(gear4+1); // head over to gear five, the last gear
        }
    break;
    case 's':
    break;

    ///////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////     MANUAL TRANSMISSION     /////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////

    case 'm':
      setGear('n');
      switch(getGear()){
        // For any of these gears...
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
            Serial.print("getGear() ");
            Serial.println(getGear());
            Serial.print("checkGear() ");
            Serial.println(checkGear());
          //if (getGear() != checkGear()){ // meaning possibly the user switched gears but...
            // its is not the gear the transmission is in right now
            // Now all the logic for automatic gear shifting with a tiny twist

            //////////////////////////////////////////////////////////
            /////////////////       UP SHIFTING     //////////////////
            //////////////////////////////////////////////////////////

            if(getPace() <= gear1 && getPace() > getStopSpeed()){
              setGear('2'); // set gear to next level;
              // then throttle at this gear
              throttle(pwm);
            }else if(getPace() <= gear2 && getPace() > gear1){
              setGear('3');
              // then throttle at this gear
              throttle(pwm);
            }
            else if(getPace() <= gear3 && getPace() > gear2){
              setGear('4');
              // then throttle at this gear
              throttle(pwm);
            }
            else if(getPace() <= gear4 && getPace() > gear3){
              setGear('5');
              // then throttle at this gear
              throttle(pwm);
            }

            //////////////////////////////////////////////////////////
            ////////////////       DOWN SHIFTING     /////////////////
            //////////////////////////////////////////////////////////

          //}
        break;
      }// End MANUAL TRANSMISSION
    break;
  }
}

void Engine::channelize(Adafruit_PWMServoDriver pwm){
  setPace(pace-819);
  pwm.setPin(getPinL(),pace);
  pwm.setPin(getPinR(),pace);
  Serial.println(getPace());
}

<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2005-2007 by the FIFE Team                              *
 *   fife-public@lists.sourceforge.net                                     *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE 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 St, Fifth Floor, Boston, MA  02110-1301  USA              *
 ***************************************************************************/

// Standard C++ library includes

// 3rd party library includes

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "model/metamodel/grids/cellgrid.h"
#include "model/structures/layer.h"
#include "util/logger.h"

#include "camera.h"
#include "view.h"

namespace FIFE {
	static Logger _log(LM_CAMERA);

	Camera::Camera():
		m_matrix(),
		m_inverse_matrix(),
		m_tilt(0),
		m_rotation(0),
		m_zoom(1),
		m_location(),
		m_viewport(),
		m_screen_cell_width(1),
		m_screen_cell_height(1),
		m_reference_scale(1) {
		updateMatrices();
	}

	Camera::~Camera() {
	}

	void Camera::updateMatrices() {
		double scale = 1.0 / (m_zoom * m_reference_scale);
		m_matrix.loadScale(scale, scale, 1);
		m_matrix.applyRotate(m_rotation, 0.0, 0.0, 1.0);
		m_matrix.applyRotate(m_tilt, 1.0, 0.0, 0.0);
		if (m_location.getLayer()) {
			CellGrid* cg = m_location.getLayer()->getCellGrid();
			if (cg) {
				ExactModelCoordinate pt = m_location.getElevationCoordinates();
				m_matrix.applyTranslate(pt.x  * m_reference_scale, pt.y * m_reference_scale, 0);
			}
		}
		m_inverse_matrix = m_matrix.inverse();
	}

	ExactModelCoordinate Camera::toElevationCoordinates(ScreenPoint screen_coords) {
		screen_coords.x -= m_viewport.w / 2;
		screen_coords.y -= m_viewport.h / 2;
		return m_matrix * intPt2doublePt(screen_coords);
	}

	ScreenPoint Camera::toScreenCoordinates(ExactModelCoordinate elevation_coords) {
		ScreenPoint pt = doublePt2intPt(m_inverse_matrix * elevation_coords);
		pt.x += m_viewport.w / 2;
		pt.y += m_viewport.h / 2;
		return pt;
	}

	void Camera::updateReferenceScale() {
		CellGrid* cg = NULL;
		if (m_location.getLayer()) {
			cg = m_location.getLayer()->getCellGrid();
		}
		if (!cg) {
			return;
		}

		ModelCoordinate cell(0,0);
		std::vector<ExactModelCoordinate> vertices;
		cg->getVertices(vertices, cell);

		DoubleMatrix mtx;
		mtx.loadRotate(m_rotation, 0.0, 0.0, 1.0);
		mtx.applyRotate(m_tilt, 1.0, 0.0, 0.0);
		mtx = mtx.inverse();
		double x1, x2, y1, y2;
		for (unsigned int i = 0; i < vertices.size(); i++) {
			vertices[i] = cg->toElevationCoordinates(vertices[i]);
			vertices[i] = mtx * vertices[i];
			if (i == 0) {
				x1 = x2 = vertices[0].x;
				y1 = y2 = vertices[0].y;
			}
			else {
				x1 = std::min(vertices[i].x, x1);
				x2 = std::max(vertices[i].x, x2);
				y1 = std::min(vertices[i].y, y1);
				y2 = std::max(vertices[i].y, y2);
			}
		}
		m_reference_scale = static_cast<double>(m_screen_cell_width) / (x2 - x1);

		FL_DBG(_log, "Updating reference scale");
		FL_DBG(_log, LMsg("   tilt=") << m_tilt << " rot=" << m_rotation);
		FL_DBG(_log, LMsg("   x1=") << x1 << " x2=" << x2 << " y1=" << y1 << " y2=" << y2);
		FL_DBG(_log, LMsg("   m_screen_cell_width=") << m_screen_cell_width);
	}
}
<commit_msg>small scaling fix for camera matrix calculations. Now the z coordinate should make more sense in techdemo mouse clicks<commit_after>/***************************************************************************
 *   Copyright (C) 2005-2007 by the FIFE Team                              *
 *   fife-public@lists.sourceforge.net                                     *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE 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 St, Fifth Floor, Boston, MA  02110-1301  USA              *
 ***************************************************************************/

// Standard C++ library includes

// 3rd party library includes

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "model/metamodel/grids/cellgrid.h"
#include "model/structures/layer.h"
#include "util/logger.h"

#include "camera.h"
#include "view.h"

namespace FIFE {
	static Logger _log(LM_CAMERA);

	Camera::Camera():
		m_matrix(),
		m_inverse_matrix(),
		m_tilt(0),
		m_rotation(0),
		m_zoom(1),
		m_location(),
		m_viewport(),
		m_screen_cell_width(1),
		m_screen_cell_height(1),
		m_reference_scale(1) {
		updateMatrices();
	}

	Camera::~Camera() {
	}

	void Camera::updateMatrices() {
		double scale = 1.0 / (m_zoom * m_reference_scale);
		m_matrix.loadScale(scale, scale, scale);
		m_matrix.applyRotate(m_rotation, 0.0, 0.0, 1.0);
		m_matrix.applyRotate(m_tilt, 1.0, 0.0, 0.0);
		if (m_location.getLayer()) {
			CellGrid* cg = m_location.getLayer()->getCellGrid();
			if (cg) {
				ExactModelCoordinate pt = m_location.getElevationCoordinates();
				m_matrix.applyTranslate(pt.x  * m_reference_scale, pt.y * m_reference_scale, 0);
			}
		}
		m_inverse_matrix = m_matrix.inverse();
	}

	ExactModelCoordinate Camera::toElevationCoordinates(ScreenPoint screen_coords) {
		screen_coords.x -= m_viewport.w / 2;
		screen_coords.y -= m_viewport.h / 2;
		return m_matrix * intPt2doublePt(screen_coords);
	}

	ScreenPoint Camera::toScreenCoordinates(ExactModelCoordinate elevation_coords) {
		ScreenPoint pt = doublePt2intPt(m_inverse_matrix * elevation_coords);
		pt.x += m_viewport.w / 2;
		pt.y += m_viewport.h / 2;
		return pt;
	}

	void Camera::updateReferenceScale() {
		CellGrid* cg = NULL;
		if (m_location.getLayer()) {
			cg = m_location.getLayer()->getCellGrid();
		}
		if (!cg) {
			return;
		}

		ModelCoordinate cell(0,0);
		std::vector<ExactModelCoordinate> vertices;
		cg->getVertices(vertices, cell);

		DoubleMatrix mtx;
		mtx.loadRotate(m_rotation, 0.0, 0.0, 1.0);
		mtx.applyRotate(m_tilt, 1.0, 0.0, 0.0);
		mtx = mtx.inverse();
		double x1, x2, y1, y2;
		for (unsigned int i = 0; i < vertices.size(); i++) {
			vertices[i] = cg->toElevationCoordinates(vertices[i]);
			vertices[i] = mtx * vertices[i];
			if (i == 0) {
				x1 = x2 = vertices[0].x;
				y1 = y2 = vertices[0].y;
			}
			else {
				x1 = std::min(vertices[i].x, x1);
				x2 = std::max(vertices[i].x, x2);
				y1 = std::min(vertices[i].y, y1);
				y2 = std::max(vertices[i].y, y2);
			}
		}
		m_reference_scale = static_cast<double>(m_screen_cell_width) / (x2 - x1);

		FL_DBG(_log, "Updating reference scale");
		FL_DBG(_log, LMsg("   tilt=") << m_tilt << " rot=" << m_rotation);
		FL_DBG(_log, LMsg("   x1=") << x1 << " x2=" << x2 << " y1=" << y1 << " y2=" << y2);
		FL_DBG(_log, LMsg("   m_screen_cell_width=") << m_screen_cell_width);
	}
}
<|endoftext|>


<commit_before>#include "Memory.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager),  // TODO: RuntimeHelper not needed
	m_memory{getBuilder(), _runtimeManager.getMem()},
	m_gasMeter(_gasMeter)
{}

llvm::Function* Memory::getRequireFunc()
{
	auto& func = m_require;
	if (!func)
	{
		llvm::Type* argTypes[] = {Array::getType()->getPointerTo(), Type::Word, Type::Word, Type::BytePtr, Type::GasPtr};
		func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
		func->setDoesNotThrow();

		auto mem = &func->getArgumentList().front();
		mem->setName("mem");
		auto blkOffset = mem->getNextNode();
		blkOffset->setName("blkOffset");
		auto blkSize = blkOffset->getNextNode();
		blkSize->setName("blkSize");
		auto jmpBuf = blkSize->getNextNode();
		jmpBuf->setName("jmpBuf");
		auto gas = jmpBuf->getNextNode();
		gas->setName("gas");

		auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
		auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
		auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
		auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);

		InsertPointGuard guard(m_builder); // Restores insert point at function exit

		// BB "Pre": Ignore checks with size 0
		m_builder.SetInsertPoint(preBB);
		m_builder.CreateCondBr(m_builder.CreateICmpNE(blkSize, Constant::get(0)), checkBB, returnBB, Type::expectTrue);

		// BB "Check"
		m_builder.SetInsertPoint(checkBB);
		static const auto c_inputMax = uint64_t(2) << 40; // max value of blkSize and blkOffset that will not result in integer overflow in calculations below
		auto blkOffsetOk = m_builder.CreateICmpULE(blkOffset, Constant::get(c_inputMax), "blkOffsetOk");
		auto blkO = m_builder.CreateSelect(blkOffsetOk, m_builder.CreateTrunc(blkOffset, Type::Size), m_builder.getInt64(c_inputMax), "bklO");
		auto blkSizeOk = m_builder.CreateICmpULE(blkSize, Constant::get(c_inputMax), "blkSizeOk");
		auto blkS = m_builder.CreateSelect(blkSizeOk, m_builder.CreateTrunc(blkSize, Type::Size), m_builder.getInt64(c_inputMax), "bklS");

		auto sizeReq0 = m_builder.CreateNUWAdd(blkO, blkS, "sizeReq0");
		auto sizeReq = m_builder.CreateAnd(m_builder.CreateNUWAdd(sizeReq0, m_builder.getInt64(31)), uint64_t(-1) << 5, "sizeReq"); // s' = ((s0 + 31) / 32) * 32
		auto sizeCur = m_memory.size(mem);
		auto sizeOk = m_builder.CreateICmpULE(sizeReq, sizeCur, "sizeOk");

		m_builder.CreateCondBr(sizeOk, returnBB, resizeBB, Type::expectTrue);

		// BB "Resize"
		m_builder.SetInsertPoint(resizeBB);
		// Check gas first
		auto sizeExt = m_builder.CreateNUWSub(sizeReq, sizeCur, "sizeExt");
		auto sizeSum = m_builder.CreateNUWAdd(sizeReq, sizeCur, "sizeSum");
		auto costL = m_builder.CreateLShr(sizeExt, 5, "costL");
		auto costQ1 = m_builder.CreateLShr(sizeExt, 20, "costQ1");
		auto costQ2 = m_builder.CreateLShr(sizeSum, 20, "costQ2");
		auto costQ = m_builder.CreateNUWAdd(costQ1, costQ2, "costQ");
		auto cost = m_builder.CreateNUWAdd(costL, costQ, "cost");
		auto costOk = m_builder.CreateAnd(blkOffsetOk, blkSizeOk, "costOk");
		auto c = m_builder.CreateSelect(costOk, costL, m_builder.getInt64(std::numeric_limits<int64_t>::max()), "c");
		m_gasMeter.countMemory(c, jmpBuf, gas);
		// Resize
		m_memory.extend(mem, sizeReq);
		m_builder.CreateBr(returnBB);

		// BB "Return"
		m_builder.SetInsertPoint(returnBB);
		m_builder.CreateRetVoid();
	}
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType)
{
	auto isWord = _valueType == Type::Word;

	llvm::Type* storeArgs[] = {Array::getType()->getPointerTo(), Type::Word, _valueType};
	llvm::Type* loadArgs[] = {Array::getType()->getPointerTo(), Type::Word};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	auto mem = &func->getArgumentList().front();
	mem->setName("mem");
	auto index = mem->getNextNode();
	index->setName("index");

	if (_isStore)
	{
		auto valueArg = index->getNextNode();
		valueArg->setName("value");
		auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg;
		auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
		auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr");
		m_builder.CreateStore(value, valuePtr);
		m_builder.CreateRetVoid();
	}
	else
	{
		auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
		llvm::Value* ret = m_builder.CreateLoad(memPtr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Function* Memory::getLoadWordFunc()
{
	auto& func = m_loadWord;
	if (!func)
		func = createFunc(false, Type::Word);
	return func;
}

llvm::Function* Memory::getStoreWordFunc()
{
	auto& func = m_storeWord;
	if (!func)
		func = createFunc(true, Type::Word);
	return func;
}

llvm::Function* Memory::getStoreByteFunc()
{
	auto& func = m_storeByte;
	if (!func)
		func = createFunc(true, Type::Byte);
	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
	return createCall(getLoadWordFunc(), {getRuntimeManager().getMem(), _addr});
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
	createCall(getStoreWordFunc(), {getRuntimeManager().getMem(), _addr, _word});
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8));
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	createCall(getStoreByteFunc(), {getRuntimeManager().getMem(), _addr, byte});
}

llvm::Value* Memory::getData()
{
	auto memPtr = m_builder.CreateBitCast(getRuntimeManager().getMem(), Type::BytePtr->getPointerTo());
	auto data = m_builder.CreateLoad(memPtr, "data");
	assert(data->getType() == Type::BytePtr);
	return data;
}

llvm::Value* Memory::getSize()
{
	return m_builder.CreateZExt(m_memory.size(), Type::Word, "msize"); // TODO: Allow placing i64 on stack
}

llvm::Value* Memory::getBytePtr(llvm::Value* _index)
{
	auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64
	return m_builder.CreateGEP(getData(), idx, "ptr");
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_size))
	{
		if (!constant->getValue())
			return;
	}
	createCall(getRequireFunc(), {getRuntimeManager().getMem(), _offset, _size, getRuntimeManager().getJmpBuf(), getRuntimeManager().getGasPtr()});
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	require(_destMemIdx, _reqBytes);

	// Additional copy cost
	// TODO: This round ups to 32 happens in many places
	auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas);
	auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32));
	m_gasMeter.countCopy(copyWords);

	// Algorithm:
	// isOutsideData = idx256 >= size256
	// idx64  = trunc idx256
	// size64 = trunc size256
	// dataLeftSize = size64 - idx64  // safe if not isOutsideData
	// reqBytes64 = trunc _reqBytes   // require() handles large values
	// bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64)  // min
	// bytesToCopy = select(isOutsideData, 0, bytesToCopy0)

	auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize);
	auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size);
	auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size);
	auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64);
	auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize);
	auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes);
	auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner);

	auto src = m_builder.CreateGEP(_srcPtr, idx64, "src");
	auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64
	auto dst = m_memory.getPtr(getRuntimeManager().getMem(), dstIdx);
	auto dst2 = m_builder.CreateGEP(getData(), dstIdx, "dst2");
	m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
	m_builder.CreateMemCpy(dst2, src, bytesToCopy, 0);
}

}
}
}
<commit_msg>Quadratic memory cost<commit_after>#include "Memory.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager),  // TODO: RuntimeHelper not needed
	m_memory{getBuilder(), _runtimeManager.getMem()},
	m_gasMeter(_gasMeter)
{}

llvm::Function* Memory::getRequireFunc()
{
	auto& func = m_require;
	if (!func)
	{
		llvm::Type* argTypes[] = {Array::getType()->getPointerTo(), Type::Word, Type::Word, Type::BytePtr, Type::GasPtr};
		func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
		func->setDoesNotThrow();

		auto mem = &func->getArgumentList().front();
		mem->setName("mem");
		auto blkOffset = mem->getNextNode();
		blkOffset->setName("blkOffset");
		auto blkSize = blkOffset->getNextNode();
		blkSize->setName("blkSize");
		auto jmpBuf = blkSize->getNextNode();
		jmpBuf->setName("jmpBuf");
		auto gas = jmpBuf->getNextNode();
		gas->setName("gas");

		auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
		auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
		auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
		auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);

		InsertPointGuard guard(m_builder); // Restores insert point at function exit

		// BB "Pre": Ignore checks with size 0
		m_builder.SetInsertPoint(preBB);
		m_builder.CreateCondBr(m_builder.CreateICmpNE(blkSize, Constant::get(0)), checkBB, returnBB, Type::expectTrue);

		// BB "Check"
		m_builder.SetInsertPoint(checkBB);
		static const auto c_inputMax = uint64_t(1) << 32; // max value of blkSize and blkOffset that will not result in integer overflow in calculations below
		auto blkOffsetOk = m_builder.CreateICmpULE(blkOffset, Constant::get(c_inputMax), "blkOffsetOk");
		auto blkO = m_builder.CreateSelect(blkOffsetOk, m_builder.CreateTrunc(blkOffset, Type::Size), m_builder.getInt64(c_inputMax), "bklO");
		auto blkSizeOk = m_builder.CreateICmpULE(blkSize, Constant::get(c_inputMax), "blkSizeOk");
		auto blkS = m_builder.CreateSelect(blkSizeOk, m_builder.CreateTrunc(blkSize, Type::Size), m_builder.getInt64(c_inputMax), "bklS");

		auto sizeReq0 = m_builder.CreateNUWAdd(blkO, blkS, "sizeReq0");
		auto sizeReq = m_builder.CreateAnd(m_builder.CreateNUWAdd(sizeReq0, m_builder.getInt64(31)), uint64_t(-1) << 5, "sizeReq"); // s' = ((s0 + 31) / 32) * 32
		auto sizeCur = m_memory.size(mem);
		auto sizeOk = m_builder.CreateICmpULE(sizeReq, sizeCur, "sizeOk");

		m_builder.CreateCondBr(sizeOk, returnBB, resizeBB, Type::expectTrue);

		// BB "Resize"
		m_builder.SetInsertPoint(resizeBB);
		// Check gas first
		auto w1 = m_builder.CreateLShr(sizeReq, 5);
		auto w1s = m_builder.CreateNUWMul(w1, w1);
		auto c1 = m_builder.CreateAdd(w1, m_builder.CreateLShr(w1s, 10));
		auto w0 = m_builder.CreateLShr(sizeCur, 5);
		auto w0s = m_builder.CreateNUWMul(w0, w0);
		auto c0 = m_builder.CreateAdd(w0, m_builder.CreateLShr(w0s, 10));
		auto cc = m_builder.CreateNUWSub(c1, c0);
		auto costOk = m_builder.CreateAnd(blkOffsetOk, blkSizeOk, "costOk");
		auto c = m_builder.CreateSelect(costOk, cc, m_builder.getInt64(std::numeric_limits<int64_t>::max()), "c");
		m_gasMeter.countMemory(c, jmpBuf, gas);
		// Resize
		m_memory.extend(mem, sizeReq);
		m_builder.CreateBr(returnBB);

		// BB "Return"
		m_builder.SetInsertPoint(returnBB);
		m_builder.CreateRetVoid();
	}
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType)
{
	auto isWord = _valueType == Type::Word;

	llvm::Type* storeArgs[] = {Array::getType()->getPointerTo(), Type::Word, _valueType};
	llvm::Type* loadArgs[] = {Array::getType()->getPointerTo(), Type::Word};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	auto mem = &func->getArgumentList().front();
	mem->setName("mem");
	auto index = mem->getNextNode();
	index->setName("index");

	if (_isStore)
	{
		auto valueArg = index->getNextNode();
		valueArg->setName("value");
		auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg;
		auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
		auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr");
		m_builder.CreateStore(value, valuePtr);
		m_builder.CreateRetVoid();
	}
	else
	{
		auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
		llvm::Value* ret = m_builder.CreateLoad(memPtr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Function* Memory::getLoadWordFunc()
{
	auto& func = m_loadWord;
	if (!func)
		func = createFunc(false, Type::Word);
	return func;
}

llvm::Function* Memory::getStoreWordFunc()
{
	auto& func = m_storeWord;
	if (!func)
		func = createFunc(true, Type::Word);
	return func;
}

llvm::Function* Memory::getStoreByteFunc()
{
	auto& func = m_storeByte;
	if (!func)
		func = createFunc(true, Type::Byte);
	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
	return createCall(getLoadWordFunc(), {getRuntimeManager().getMem(), _addr});
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
	createCall(getStoreWordFunc(), {getRuntimeManager().getMem(), _addr, _word});
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8));
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	createCall(getStoreByteFunc(), {getRuntimeManager().getMem(), _addr, byte});
}

llvm::Value* Memory::getData()
{
	auto memPtr = m_builder.CreateBitCast(getRuntimeManager().getMem(), Type::BytePtr->getPointerTo());
	auto data = m_builder.CreateLoad(memPtr, "data");
	assert(data->getType() == Type::BytePtr);
	return data;
}

llvm::Value* Memory::getSize()
{
	return m_builder.CreateZExt(m_memory.size(), Type::Word, "msize"); // TODO: Allow placing i64 on stack
}

llvm::Value* Memory::getBytePtr(llvm::Value* _index)
{
	auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64
	return m_builder.CreateGEP(getData(), idx, "ptr");
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_size))
	{
		if (!constant->getValue())
			return;
	}
	createCall(getRequireFunc(), {getRuntimeManager().getMem(), _offset, _size, getRuntimeManager().getJmpBuf(), getRuntimeManager().getGasPtr()});
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	require(_destMemIdx, _reqBytes);

	// Additional copy cost
	// TODO: This round ups to 32 happens in many places
	auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas);
	auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32));
	m_gasMeter.countCopy(copyWords);

	// Algorithm:
	// isOutsideData = idx256 >= size256
	// idx64  = trunc idx256
	// size64 = trunc size256
	// dataLeftSize = size64 - idx64  // safe if not isOutsideData
	// reqBytes64 = trunc _reqBytes   // require() handles large values
	// bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64)  // min
	// bytesToCopy = select(isOutsideData, 0, bytesToCopy0)

	auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize);
	auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size);
	auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size);
	auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64);
	auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize);
	auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes);
	auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner);

	auto src = m_builder.CreateGEP(_srcPtr, idx64, "src");
	auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64
	auto dst = m_memory.getPtr(getRuntimeManager().getMem(), dstIdx);
	auto dst2 = m_builder.CreateGEP(getData(), dstIdx, "dst2");
	m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
	m_builder.CreateMemCpy(dst2, src, bytesToCopy, 0);
}

}
}
}
<|endoftext|>