<commit_before>/*
* This file is part of the PySide project.
*
* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Contact: PySide team <contact@pyside.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "signalmanager.h"
#include "pysidesignal.h"
#include "pysideproperty.h"
#include "pysideproperty_p.h"
#include "pyside.h"

#include <QHash>
#include <QStringList>
#include <QMetaMethod>
#include <autodecref.h>
#include <gilstate.h>
#include <QDebug>
#include <limits>
#include <typeresolver.h>
#include <basewrapper.h>
#include <conversions.h>

#if QSLOT_CODE != 1 || QSIGNAL_CODE != 2
#error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value!
#endif
#define PYSIDE_SLOT '1'
#define PYSIDE_SIGNAL '2'
#include "globalreceiver.h"

#define PYTHON_TYPE "PyObject"

namespace PySide {

static int callMethod(QObject* object, int id, void** args);

PyObjectWrapper::PyObjectWrapper()
    :m_me(Py_None)
{
    Py_INCREF(m_me);
}

PyObjectWrapper::PyObjectWrapper(PyObject* me)
    : m_me(me)
{
    Py_INCREF(m_me);
}

PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other)
    : m_me(other.m_me)
{
    Py_INCREF(m_me);
}

PyObjectWrapper::~PyObjectWrapper()
{
    Py_DECREF(m_me);
}

PyObjectWrapper::operator PyObject*() const
{
    return m_me;
}

};

namespace Shiboken {

template<>
struct Converter<PySide::PyObjectWrapper>
{
    static PySide::PyObjectWrapper toCpp(PyObject* obj)
    {
        return PySide::PyObjectWrapper(obj);
    }

    static PyObject* toPython(void* obj)
    {
        return toPython(*reinterpret_cast<PySide::PyObjectWrapper*>(obj));
    }

    static PyObject* toPython(const PySide::PyObjectWrapper& obj)
    {
        Py_INCREF((PyObject*)obj);
        return obj;
    }
};

};

using namespace PySide;

struct SignalManager::SignalManagerPrivate
{
    GlobalReceiver m_globalReceiver;
};

static void clearSignalManager()
{
    PySide::SignalManager::instance().clear();
}

SignalManager::SignalManager() : m_d(new SignalManagerPrivate)
{
    // Register Qt primitive typedefs used on signals.
    using namespace Shiboken;

    // Register PyObject type to use in queued signal and slot connections
    qRegisterMetaType<PyObjectWrapper>(PYTHON_TYPE);

    TypeResolver::createValueTypeResolver<PyObjectWrapper>(PYTHON_TYPE);
    TypeResolver::createValueTypeResolver<PyObjectWrapper>("object");
    TypeResolver::createValueTypeResolver<PyObjectWrapper>("PySide::PyObjectWrapper");
    PySide::registerCleanupFunction(clearSignalManager);
}

void SignalManager::clear()
{
    delete m_d;
    m_d = new SignalManagerPrivate();
}

SignalManager::~SignalManager()
{
    delete m_d;
}

SignalManager& SignalManager::instance()
{
    static SignalManager me;
    return me;
}

QObject* SignalManager::globalReceiver()
{
    return &m_d->m_globalReceiver;
}

void SignalManager::globalReceiverConnectNotify(QObject* source, int slotIndex)
{
    m_d->m_globalReceiver.connectNotify(source, slotIndex);
}

void SignalManager::globalReceiverDisconnectNotify(QObject* source, int slotIndex)
{
    m_d->m_globalReceiver.disconnectNotify(source, slotIndex);
}

void SignalManager::addGlobalSlot(const char* slot, PyObject* callback)
{
    m_d->m_globalReceiver.addSlot(slot, callback);
}

static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args)
{
    void* signalArgs[2] = {0, args};
    QMetaObject::activate(source, signalIndex, signalArgs);
    return true;
}

static bool emitNormalSignal(QObject* source, int signalIndex, const char* signal, PyObject* args, const QStringList& argTypes)
{
    Shiboken::AutoDecRef sequence(PySequence_Fast(args, 0));
    int argsGiven = PySequence_Fast_GET_SIZE(sequence.object());
    if (argsGiven > argTypes.count()) {
        PyErr_Format(PyExc_TypeError, "%s only accepts %d arguments, %d given!", signal, argTypes.count(), argsGiven);
        return false;
    }

    void** signalArgs = new void*[argsGiven+1];
    void** signalValues = new void*[argsGiven];
    signalArgs[0] = 0;

    int i;
    for (i = 0; i < argsGiven; ++i) {
        Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(qPrintable(argTypes[i]));
        if (typeResolver) {
            typeResolver->toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i), &signalValues[i], true);
            if (Shiboken::TypeResolver::getType(qPrintable(argTypes[i])) == Shiboken::TypeResolver::ObjectType)
                signalArgs[i+1] = &signalValues[i];
            else
                signalArgs[i+1] = signalValues[i];
        } else {
            PyErr_Format(PyExc_TypeError, "Unknown type used to emit a signal: %s", qPrintable(argTypes[i]));
            break;
        }
    }

    bool ok = i == argsGiven;
    if (ok)
        QMetaObject::activate(source, signalIndex, signalArgs);

    //cleanup memory
    for (int j = 0; j < i; ++j)
        Shiboken::TypeResolver::get(qPrintable(argTypes[j]))->deleteObject(signalArgs[j+1]);

    delete[] signalArgs;
    delete[] signalValues;

    return ok;
}

bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args)
{
    if (!Signal::checkQtSignal(signal))
        return false;
    signal++;

    int signalIndex = source->metaObject()->indexOfSignal(signal);
    if (signalIndex != -1) {
        bool isShortCircuit;
        QStringList argTypes = Signal::getArgsFromSignature(signal, &isShortCircuit);

        if (isShortCircuit)
            return emitShortCircuitSignal(source, signalIndex, args);
        else
            return emitNormalSignal(source, signalIndex, signal, args, argTypes);
    }
    return false;
}

int SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args)
{
    const QMetaObject* metaObject = object->metaObject();
    PySideProperty* pp = 0;
    PyObject* pp_name = 0;
    QMetaProperty mp;
    Shiboken::TypeResolver* typeResolver = 0;
    PyObject* pySelf = 0;

    if (call != QMetaObject::InvokeMetaMethod) {
        mp = metaObject->property(id);
        if (!mp.isValid())
            return id - metaObject->methodCount();

        Shiboken::GilState gil;
        pySelf = Shiboken::BindingManager::instance().retrieveWrapper(object);
        Q_ASSERT(pySelf);
        pp_name = PyString_FromString(mp.name());
        pp = Property::getObject(pySelf, pp_name);
        if (!pp) {
            qWarning("Invalid property.");
            Py_XDECREF(pp_name);
            return id - metaObject->methodCount();
        }
        typeResolver = Shiboken::TypeResolver::get(mp.typeName());
        Q_ASSERT(typeResolver);
    }

    switch(call) {
#ifndef QT_NO_PROPERTIES
        case QMetaObject::ReadProperty:
        {
            Shiboken::GilState gil;
            PyObject* value = Property::getValue(pp, pySelf);
            if (value) {
                typeResolver->toCpp(value, &args[0]);
                Py_DECREF(value);
            } else if (PyErr_Occurred()) {
                PyErr_Print(); // Clear any errors but print them to stderr
            }
            break;
        }

        case QMetaObject::WriteProperty:
        {
            Shiboken::GilState gil;
            Shiboken::AutoDecRef value(typeResolver->toPython(args[0]));
            Property::setValue(pp, pySelf, value);
            break;
        }

        case QMetaObject::ResetProperty:
        {
            Shiboken::GilState gil;
            Property::reset(pp, pp_name);
            break;
        }

        case QMetaObject::QueryPropertyDesignable:
        case QMetaObject::QueryPropertyScriptable:
        case QMetaObject::QueryPropertyStored:
        case QMetaObject::QueryPropertyEditable:
        case QMetaObject::QueryPropertyUser:
            break;
#endif
        case QMetaObject::InvokeMetaMethod:
            id = callMethod(object, id, args);
            break;

        default:
            qWarning("Unsupported meta invocation type.");
    }

    if (call == QMetaObject::InvokeMetaMethod)
        id = id - metaObject->methodCount();
    else
        id = id - metaObject->propertyCount();

    if (pp || pp_name) {
        Shiboken::GilState gil;
        Py_XDECREF(pp);
        Py_XDECREF(pp_name);
    }
    return id;
}

static int PySide::callMethod(QObject* object, int id, void** args)
{
    const QMetaObject* metaObject = object->metaObject();
    QMetaMethod method = metaObject->method(id);

    if (method.methodType() == QMetaMethod::Signal) {
        // emit python signal
        QMetaObject::activate(object, id, args);
    } else {
        // call python slot
        Shiboken::GilState gil;
        QList<QByteArray> paramTypes = method.parameterTypes();
        PyObject* self = Shiboken::BindingManager::instance().retrieveWrapper(object);
        PyObject* preparedArgs = NULL;
        Py_ssize_t args_size = paramTypes.count();

        if (args_size)
            preparedArgs = PyTuple_New(args_size);

        for (int i = 0, max = paramTypes.count(); i < max; ++i) {
            void* data = args[i+1];
            const char* dataType = paramTypes[i].constData();

            PyObject* arg = Shiboken::TypeResolver::get(dataType)->toPython(data);
            PyTuple_SET_ITEM(preparedArgs, i, arg);
        }

        QString methodName = method.signature();
        methodName = methodName.left(methodName.indexOf('('));

        Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(self, qPrintable(methodName)));
        if (!pyMethod.isNull()) {
            Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, preparedArgs));
            if (retval.isNull()) {
                qWarning() << "Error calling slot" << methodName;
                PyErr_Print();
            }
        } else {
            qWarning() << "Dynamic slot" << methodName << "not found!";
        }
        Py_XDECREF(preparedArgs);
    }
    return -1;
}

bool SignalManager::registerMetaMethod(QObject* source, const char* signature, QMetaMethod::MethodType type)
{
    Q_ASSERT(source);
    const QMetaObject* metaObject = source->metaObject();
    int methodIndex = metaObject->indexOfMethod(signature);
    // Create the dynamic signal is needed
    if (methodIndex == -1) {
        Shiboken::SbkBaseWrapper* self = (Shiboken::SbkBaseWrapper*) Shiboken::BindingManager::instance().retrieveWrapper(source);
        if (!self->containsCppWrapper) {
            qWarning() << "Invalid Signal signature:" << signature;
            return false;
        } else {
            PySide::DynamicQMetaObject* dynMetaObj = reinterpret_cast<PySide::DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject));
            if (type == QMetaMethod::Signal)
                dynMetaObj->addSignal(signature);
            else
                dynMetaObj->addSlot(signature);
        }
    }
    return true;
}

bool SignalManager::hasConnectionWith(const QObject *object)
{
    return m_d->m_globalReceiver.hasConnectionWith(object);
}
<commit_msg>Fill the argument used on metacall for slot functions.<commit_after>/*
* This file is part of the PySide project.
*
* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Contact: PySide team <contact@pyside.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "signalmanager.h"
#include "pysidesignal.h"
#include "pysideproperty.h"
#include "pysideproperty_p.h"
#include "pyside.h"

#include <QHash>
#include <QStringList>
#include <QMetaMethod>
#include <autodecref.h>
#include <gilstate.h>
#include <QDebug>
#include <limits>
#include <typeresolver.h>
#include <basewrapper.h>
#include <conversions.h>

#if QSLOT_CODE != 1 || QSIGNAL_CODE != 2
#error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value!
#endif
#define PYSIDE_SLOT '1'
#define PYSIDE_SIGNAL '2'
#include "globalreceiver.h"

#define PYTHON_TYPE "PyObject"

namespace PySide {

static int callMethod(QObject* object, int id, void** args);

PyObjectWrapper::PyObjectWrapper()
    :m_me(Py_None)
{
    Py_INCREF(m_me);
}

PyObjectWrapper::PyObjectWrapper(PyObject* me)
    : m_me(me)
{
    Py_INCREF(m_me);
}

PyObjectWrapper::PyObjectWrapper(const PyObjectWrapper &other)
    : m_me(other.m_me)
{
    Py_INCREF(m_me);
}

PyObjectWrapper::~PyObjectWrapper()
{
    Py_DECREF(m_me);
}

PyObjectWrapper::operator PyObject*() const
{
    return m_me;
}

};

namespace Shiboken {

template<>
struct Converter<PySide::PyObjectWrapper>
{
    static PySide::PyObjectWrapper toCpp(PyObject* obj)
    {
        return PySide::PyObjectWrapper(obj);
    }

    static PyObject* toPython(void* obj)
    {
        return toPython(*reinterpret_cast<PySide::PyObjectWrapper*>(obj));
    }

    static PyObject* toPython(const PySide::PyObjectWrapper& obj)
    {
        Py_INCREF((PyObject*)obj);
        return obj;
    }
};

};

using namespace PySide;

struct SignalManager::SignalManagerPrivate
{
    GlobalReceiver m_globalReceiver;
};

static void clearSignalManager()
{
    PySide::SignalManager::instance().clear();
}

SignalManager::SignalManager() : m_d(new SignalManagerPrivate)
{
    // Register Qt primitive typedefs used on signals.
    using namespace Shiboken;

    // Register PyObject type to use in queued signal and slot connections
    qRegisterMetaType<PyObjectWrapper>(PYTHON_TYPE);

    TypeResolver::createValueTypeResolver<PyObjectWrapper>(PYTHON_TYPE);
    TypeResolver::createValueTypeResolver<PyObjectWrapper>("object");
    TypeResolver::createValueTypeResolver<PyObjectWrapper>("PySide::PyObjectWrapper");
    PySide::registerCleanupFunction(clearSignalManager);
}

void SignalManager::clear()
{
    delete m_d;
    m_d = new SignalManagerPrivate();
}

SignalManager::~SignalManager()
{
    delete m_d;
}

SignalManager& SignalManager::instance()
{
    static SignalManager me;
    return me;
}

QObject* SignalManager::globalReceiver()
{
    return &m_d->m_globalReceiver;
}

void SignalManager::globalReceiverConnectNotify(QObject* source, int slotIndex)
{
    m_d->m_globalReceiver.connectNotify(source, slotIndex);
}

void SignalManager::globalReceiverDisconnectNotify(QObject* source, int slotIndex)
{
    m_d->m_globalReceiver.disconnectNotify(source, slotIndex);
}

void SignalManager::addGlobalSlot(const char* slot, PyObject* callback)
{
    m_d->m_globalReceiver.addSlot(slot, callback);
}

static bool emitShortCircuitSignal(QObject* source, int signalIndex, PyObject* args)
{
    void* signalArgs[2] = {0, args};
    QMetaObject::activate(source, signalIndex, signalArgs);
    return true;
}

static bool emitNormalSignal(QObject* source, int signalIndex, const char* signal, PyObject* args, const QStringList& argTypes)
{
    Shiboken::AutoDecRef sequence(PySequence_Fast(args, 0));
    int argsGiven = PySequence_Fast_GET_SIZE(sequence.object());
    if (argsGiven > argTypes.count()) {
        PyErr_Format(PyExc_TypeError, "%s only accepts %d arguments, %d given!", signal, argTypes.count(), argsGiven);
        return false;
    }

    void** signalArgs = new void*[argsGiven+1];
    void** signalValues = new void*[argsGiven];
    signalArgs[0] = 0;

    int i;
    for (i = 0; i < argsGiven; ++i) {
        Shiboken::TypeResolver* typeResolver = Shiboken::TypeResolver::get(qPrintable(argTypes[i]));
        if (typeResolver) {
            typeResolver->toCpp(PySequence_Fast_GET_ITEM(sequence.object(), i), &signalValues[i], true);
            if (Shiboken::TypeResolver::getType(qPrintable(argTypes[i])) == Shiboken::TypeResolver::ObjectType)
                signalArgs[i+1] = &signalValues[i];
            else
                signalArgs[i+1] = signalValues[i];
        } else {
            PyErr_Format(PyExc_TypeError, "Unknown type used to emit a signal: %s", qPrintable(argTypes[i]));
            break;
        }
    }

    bool ok = i == argsGiven;
    if (ok)
        QMetaObject::activate(source, signalIndex, signalArgs);

    //cleanup memory
    for (int j = 0; j < i; ++j)
        Shiboken::TypeResolver::get(qPrintable(argTypes[j]))->deleteObject(signalArgs[j+1]);

    delete[] signalArgs;
    delete[] signalValues;

    return ok;
}

bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args)
{
    if (!Signal::checkQtSignal(signal))
        return false;
    signal++;

    int signalIndex = source->metaObject()->indexOfSignal(signal);
    if (signalIndex != -1) {
        bool isShortCircuit;
        QStringList argTypes = Signal::getArgsFromSignature(signal, &isShortCircuit);

        if (isShortCircuit)
            return emitShortCircuitSignal(source, signalIndex, args);
        else
            return emitNormalSignal(source, signalIndex, signal, args, argTypes);
    }
    return false;
}

int SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args)
{
    const QMetaObject* metaObject = object->metaObject();
    PySideProperty* pp = 0;
    PyObject* pp_name = 0;
    QMetaProperty mp;
    Shiboken::TypeResolver* typeResolver = 0;
    PyObject* pySelf = 0;

    if (call != QMetaObject::InvokeMetaMethod) {
        mp = metaObject->property(id);
        if (!mp.isValid())
            return id - metaObject->methodCount();

        Shiboken::GilState gil;
        pySelf = Shiboken::BindingManager::instance().retrieveWrapper(object);
        Q_ASSERT(pySelf);
        pp_name = PyString_FromString(mp.name());
        pp = Property::getObject(pySelf, pp_name);
        if (!pp) {
            qWarning("Invalid property.");
            Py_XDECREF(pp_name);
            return id - metaObject->methodCount();
        }
        typeResolver = Shiboken::TypeResolver::get(mp.typeName());
        Q_ASSERT(typeResolver);
    }

    switch(call) {
#ifndef QT_NO_PROPERTIES
        case QMetaObject::ReadProperty:
        {
            Shiboken::GilState gil;
            PyObject* value = Property::getValue(pp, pySelf);
            if (value) {
                typeResolver->toCpp(value, &args[0]);
                Py_DECREF(value);
            } else if (PyErr_Occurred()) {
                PyErr_Print(); // Clear any errors but print them to stderr
            }
            break;
        }

        case QMetaObject::WriteProperty:
        {
            Shiboken::GilState gil;
            Shiboken::AutoDecRef value(typeResolver->toPython(args[0]));
            Property::setValue(pp, pySelf, value);
            break;
        }

        case QMetaObject::ResetProperty:
        {
            Shiboken::GilState gil;
            Property::reset(pp, pp_name);
            break;
        }

        case QMetaObject::QueryPropertyDesignable:
        case QMetaObject::QueryPropertyScriptable:
        case QMetaObject::QueryPropertyStored:
        case QMetaObject::QueryPropertyEditable:
        case QMetaObject::QueryPropertyUser:
            break;
#endif
        case QMetaObject::InvokeMetaMethod:
            id = callMethod(object, id, args);
            break;

        default:
            qWarning("Unsupported meta invocation type.");
    }

    if (call == QMetaObject::InvokeMetaMethod)
        id = id - metaObject->methodCount();
    else
        id = id - metaObject->propertyCount();

    if (pp || pp_name) {
        Shiboken::GilState gil;
        Py_XDECREF(pp);
        Py_XDECREF(pp_name);
    }
    return id;
}

static int PySide::callMethod(QObject* object, int id, void** args)
{
    const QMetaObject* metaObject = object->metaObject();
    QMetaMethod method = metaObject->method(id);

    if (method.methodType() == QMetaMethod::Signal) {
        // emit python signal
        QMetaObject::activate(object, id, args);
    } else {
        // call python slot
        Shiboken::GilState gil;
        QList<QByteArray> paramTypes = method.parameterTypes();
        PyObject* self = Shiboken::BindingManager::instance().retrieveWrapper(object);
        PyObject* preparedArgs = NULL;
        Py_ssize_t args_size = paramTypes.count();

        if (args_size)
            preparedArgs = PyTuple_New(args_size);

        for (int i = 0, max = paramTypes.count(); i < max; ++i) {
            void* data = args[i+1];
            const char* dataType = paramTypes[i].constData();

            PyObject* arg = Shiboken::TypeResolver::get(dataType)->toPython(data);
            PyTuple_SET_ITEM(preparedArgs, i, arg);
        }

        QString methodName = method.signature();
        methodName = methodName.left(methodName.indexOf('('));

        Shiboken::AutoDecRef pyMethod(PyObject_GetAttrString(self, qPrintable(methodName)));
        if (!pyMethod.isNull()) {
            Shiboken::AutoDecRef retval(PyObject_CallObject(pyMethod, preparedArgs));
            if (retval.isNull()) {
                qWarning() << "Error calling slot" << methodName;
                PyErr_Print();
            } else {
                const char* returnType = method.typeName();
                if (returnType && (strlen(returnType) > 0))
                    Shiboken::TypeResolver::get(returnType)->toCpp(retval, &args[0]);
            }
        } else {
            qWarning() << "Dynamic slot" << methodName << "not found!";
        }
        Py_XDECREF(preparedArgs);
    }
    return -1;
}

bool SignalManager::registerMetaMethod(QObject* source, const char* signature, QMetaMethod::MethodType type)
{
    Q_ASSERT(source);
    const QMetaObject* metaObject = source->metaObject();
    int methodIndex = metaObject->indexOfMethod(signature);
    // Create the dynamic signal is needed
    if (methodIndex == -1) {
        Shiboken::SbkBaseWrapper* self = (Shiboken::SbkBaseWrapper*) Shiboken::BindingManager::instance().retrieveWrapper(source);
        if (!self->containsCppWrapper) {
            qWarning() << "Invalid Signal signature:" << signature;
            return false;
        } else {
            PySide::DynamicQMetaObject* dynMetaObj = reinterpret_cast<PySide::DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject));
            if (type == QMetaMethod::Signal)
                dynMetaObj->addSignal(signature);
            else
                dynMetaObj->addSlot(signature);
        }
    }
    return true;
}

bool SignalManager::hasConnectionWith(const QObject *object)
{
    return m_d->m_globalReceiver.hasConnectionWith(object);
}
<|endoftext|>


<commit_before>// The K3 Runtime Collections Library.
//
// This file contains definitions for the various operations performed on K3 collections, used by
// the generated C++ code. The C++ realizations of K3 Collections will inherit from the
// K3::Collection class, providing a suitable content type.
//
// TODO:
//  - Use <algorithm> routines to perform collection transformations? In particular, investigate
//    order-of-operations semantics.
//  - Use container agnostic mutation operations?
//  - Use bulk mutation operations (iterator-based insertion, for example)?
//  - Optimize all the unnecessary copies, using std::move?
#ifndef K3_RUNTIME_COLLECTIONS_H
#define K3_RUNTIME_COLLECTIONS_H

#include <functional>
#include <list>
#include <map>
#include <memory>
#include <tuple>

#include <Engine.hpp>
#include <dataspace/StlDS.hpp>
#include <dataspace/SetDS.hpp>
#include <dataspace/ListDS.hpp>
#include <dataspace/SortedDS.hpp>
#include <boost/serialization/base_object.hpp>

namespace K3 {
  template <template <class...> class D, class E>
  class Collection: public D<E> {
    public:
      Collection(Engine * e) : D<E>(e) {};

      template <template <class> class F>
      Collection(const Collection<F, E> other) : D<E>(other)  {}

      template <template <class> class F>
      Collection(Collection<F, E>&& other) : D<E>(other) {}

      Collection(D<E> other) : D<E>(other) {}

      // TODO: shared_ptr vs. value?
      std::shared_ptr<E> peek() { return D<E>::peek(); }

      void insert(const E& elem) { D<E>::insert(elem); }
      void insert(E&& elem) { D<E>::insert(elem); }

      void erase(const E& elem)  { D<E>::erase(elem); }

      void update(const E& v1, const E& v2) { D<E>::update(v1,v2); }
      void update(const E& v1, E&& v2) { D<E>::update(v1,v2); }

      std::tuple<Collection<D, E>, Collection<D, E>> split() {
        auto tup = D<E>::split();
        D<E> ds1 = get<0>(tup);
        D<E> ds2 = get<1>(tup);
        return std::make_tuple(Collection<D,E>(ds1), Collection<D,E>(ds2));
      }

      template <template <class> class F>
      Collection<D, E> combine(const Collection<F, E>& other) {
       return Collection<D,E>(D<E>::combine(other));
      }

      template <class T>
      Collection<D, T> map(std::function<T(E)> f) {
       return Collection<D,T>(D<E>::map(f));
      }

      Collection<D, E> filter(std::function<bool(E)> f) {
       return Collection<D,E>(D<E>::filter(f));
      }

      template <class Z>
      Z fold(std::function<Z(Z, E)> f, Z init) {
       return D<E>::fold(f, init);
      }

      template <class K, class Z>
      Collection<D, std::tuple<K, Z>> group_by(
        std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
          // Create a map to hold partial results
          std::map<K, Z> accs = std::map<K,Z>();
          // lambda to apply to each element
          std::function<void(E)> f = [&] (E elem) {
            K key = grouper(elem);
            if (accs.find(key) == accs.end()) {
              accs[key] = init;
            }
            accs[key] = folder(accs[key], elem);
          };
          D<E>::iterate(f);
          // Build Collection result
          Collection<D, std::tuple<K,Z>> result = Collection<D,std::tuple<K,Z>>(D<E>::getEngine());
          typename std::map<K,Z>::iterator it;
          for (it = accs.begin(); it != accs.end(); ++it) {
            std::tuple<K,Z> tup = std::make_tuple(it->first, it->second);
            result.insert(tup);
          }
         return result;
      }

      template <template <class> class F, class T>
      Collection<D, T> ext(std::function<Collection<F, T>(E)> expand) {
        Collection<D, T> result = Collection<D,T>(D<E>::getEngine());
        auto add_to_result = [&] (T elem) {result.insert(elem); };
        auto fun = [&] (E elem) {
          expand(elem).iterate(add_to_result);
        };
        D<E>::iterate(fun);
        return result;
      }

  private:
    friend class boost::serialization::access;
    // Serialize a collection by serializing its base-class (a dataspace)
    template<class Archive>
    void serialize(Archive &ar, const unsigned int version) {
      ar & boost::serialization::base_object<D<E>>(*this);
    }

  };

  template <typename E>
  // TODO: make this more generic? ie a SeqDS interface
  class Seq : public Collection<ListDS, E> {
    typedef Collection<ListDS, E> super;
     public:
      Seq(Engine * e) : super(e) {};

      Seq(const Seq<E>& other) : super(other)  {}

      Seq(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Seq<E>
      std::tuple<Seq<E>, Seq<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Seq<E>(ds1), Seq<E>(ds2));
      }

      Seq<E> combine(const Seq<E>& other) {
       return Seq<E>(super::combine(other));
      }

      template <class T>
      Seq<T> map(std::function<T(E)> f) {
       return Seq<T>(super::map(f));
      }

      Seq<E> filter(std::function<bool(E)> f) {
       return Seq<E>(super::filter(f));
      }

      Seq<E> sort(std::function<int(E,E)> f) {
        super s = super(ListDS<E>::sort(f));
        return Seq<E>(s);

      }

      template <class K, class Z>
      Seq<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<ListDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Seq<std::tuple<K,Z>>(s);
      }

      template <class T>
      Seq<T> ext(std::function<Collection<ListDS, T>(E)> expand) {
        Collection<ListDS, T> result = super::ext(expand);
        return Seq<T>(result);
      }
  };

  template <typename E>
  // TODO: make this more generic? ie a SetDS interface
  class Set : public Collection<SetDS, E> {
    typedef Collection<SetDS, E> super;
    typedef SetDS<E> dataspace;
     public:
      Set(Engine * e) : super(e) {};

      Set(const Set<E>& other) : super(other)  {}

      Set(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Set<E>
      std::tuple<Set<E>, Set<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Set<E>(ds1), Set<E>(ds2));
      }

      Set<E> combine(const Set<E>& other) {
       return Set<E>(super::combine(other));
      }

      template <class T>
      Set<T> map(std::function<T(E)> f) {
       return Set<T>(super::map(f));
      }

      Set<E> filter(std::function<bool(E)> f) {
       return Set<E>(super::filter(f));
      }

      template <class K, class Z>
      Set<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SetDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Set<std::tuple<K,Z>>(s);
      }

      template <class T>
      Set<T> ext(std::function<Collection<SetDS, T>(E)> expand) {
        Collection<SetDS, T> result = super::ext(expand);
        return Set<T>(result);
      }

      bool member(E e) {
        return dataspace::member(e);
      }

      bool isSubsetOf(SetDS<E> other) {
        return dataspace::isSubsetOf(other);
      }

      // TODO union is a reserved word
      Set union1(Set<E> other) {
        super s = super(dataspace::union1(other));
        return Set<E>(s);
      }

      Set intersect(Set<E> other) {
        super s = super(dataspace::intersect(other));
        return Set<E>(s);
      }

      Set difference(Set<E> other) {
        super s = super(dataspace::difference(other));
        return Set<E>(s);
      }

  };

  template <typename E>
  class Sorted : public Collection<SortedDS, E> {
    typedef Collection<SortedDS, E> super;
    typedef SortedDS<E> dataspace;
     public:
      Sorted(Engine * e) : super(e) {};

      Sorted(const Sorted<E>& other) : super(other)  {}

      Sorted(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Sorted<E>
      std::tuple<Sorted<E>, Sorted<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Sorted<E>(ds1), Sorted<E>(ds2));
      }

      Sorted<E> combine(const Sorted<E>& other) {
       return Sorted<E>(super::combine(other));
      }

      template <class T>
      Sorted<T> map(std::function<T(E)> f) {
       return Sorted<T>(super::map(f));
      }

      Sorted<E> filter(std::function<bool(E)> f) {
       return Sorted<E>(super::filter(f));
      }

      template <class K, class Z>
      Sorted<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SortedDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Sorted<std::tuple<K,Z>>(s);
      }

      template <class T>
      Sorted<T> ext(std::function<Collection<SortedDS, T>(E)> expand) {
        Collection<SortedDS, T> result = super::ext(expand);
        return Sorted<T>(result);
      }

      shared_ptr<E> min() { return dataspace::min(); }

      shared_ptr<E> max() { return dataspace::max(); }

      shared_ptr<E> lowerBound(E a) { return dataspace::lowerBound(a); }

      shared_ptr<E> upperBound(E a) { return dataspace::lowerBound(a); }

      Sorted<E> slice(E a, E b) {
        super s = super(dataspace::slice(a,b));
        return Sorted<E>(s);
      }

  };
}

#endif
<commit_msg>Add ExternalCollection<commit_after>// The K3 Runtime Collections Library.
//
// This file contains definitions for the various operations performed on K3 collections, used by
// the generated C++ code. The C++ realizations of K3 Collections will inherit from the
// K3::Collection class, providing a suitable content type.
//
// TODO:
//  - Use <algorithm> routines to perform collection transformations? In particular, investigate
//    order-of-operations semantics.
//  - Use container agnostic mutation operations?
//  - Use bulk mutation operations (iterator-based insertion, for example)?
//  - Optimize all the unnecessary copies, using std::move?
#ifndef K3_RUNTIME_COLLECTIONS_H
#define K3_RUNTIME_COLLECTIONS_H

#include <functional>
#include <list>
#include <map>
#include <memory>
#include <tuple>

#include <Engine.hpp>
#include <dataspace/StlDS.hpp>
#include <dataspace/SetDS.hpp>
#include <dataspace/ListDS.hpp>
#include <dataspace/SortedDS.hpp>
#include <boost/serialization/base_object.hpp>

namespace K3 {
  template <template <class...> class D, class E>
  class Collection: public D<E> {
    public:
      Collection(Engine * e) : D<E>(e) {}

      template <template <class> class F>
      Collection(const Collection<F, E> other) : D<E>(other)  {}

      template <template <class> class F>
      Collection(Collection<F, E>&& other) : D<E>(other) {}

      Collection(D<E> other) : D<E>(other) {}

      std::shared_ptr<E> peek() { return D<E>::peek(); }

      void insert(const E& elem) { D<E>::insert(elem); }
      void insert(E&& elem) { D<E>::insert(elem); }

      void erase(const E& elem)  { D<E>::erase(elem); }

      void update(const E& v1, const E& v2) { D<E>::update(v1,v2); }
      void update(const E& v1, E&& v2) { D<E>::update(v1,v2); }

      std::tuple<Collection<D, E>, Collection<D, E>> split() {
        auto tup = D<E>::split();
        D<E> ds1 = get<0>(tup);
        D<E> ds2 = get<1>(tup);
        return std::make_tuple(Collection<D,E>(ds1), Collection<D,E>(ds2));
      }

      template <template <class> class F>
      Collection<D, E> combine(const Collection<F, E>& other) {
       return Collection<D,E>(D<E>::combine(other));
      }

      template <class T>
      Collection<D, T> map(std::function<T(E)> f) {
       return Collection<D,T>(D<E>::map(f));
      }

      Collection<D, E> filter(std::function<bool(E)> f) {
       return Collection<D,E>(D<E>::filter(f));
      }

      template <class Z>
      Z fold(std::function<Z(Z, E)> f, Z init) {
       return D<E>::fold(f, init);
      }

      template <class K, class Z>
      Collection<D, std::tuple<K, Z>> group_by(
        std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
          // Create a map to hold partial results
          std::map<K, Z> accs = std::map<K,Z>();
          // lambda to apply to each element
          std::function<void(E)> f = [&] (E elem) {
            K key = grouper(elem);
            if (accs.find(key) == accs.end()) {
              accs[key] = init;
            }
            accs[key] = folder(accs[key], elem);
          };
          D<E>::iterate(f);
          // Build Collection result
          Collection<D, std::tuple<K,Z>> result = Collection<D,std::tuple<K,Z>>(D<E>::getEngine());
          typename std::map<K,Z>::iterator it;
          for (it = accs.begin(); it != accs.end(); ++it) {
            std::tuple<K,Z> tup = std::make_tuple(it->first, it->second);
            result.insert(tup);
          }
         return result;
      }

      template <template <class> class F, class T>
      Collection<D, T> ext(std::function<Collection<F, T>(E)> expand) {
        Collection<D, T> result = Collection<D,T>(D<E>::getEngine());
        auto add_to_result = [&] (T elem) {result.insert(elem); };
        auto fun = [&] (E elem) {
          expand(elem).iterate(add_to_result);
        };
        D<E>::iterate(fun);
        return result;
      }

  private:
    friend class boost::serialization::access;
    // Serialize a collection by serializing its base-class (a dataspace)
    template<class Archive>
    void serialize(Archive &ar, const unsigned int version) {
      ar & boost::serialization::base_object<D<E>>(*this);
    }

  };

  template <typename E>
  // TODO: make this more generic? ie a SeqDS interface
  class Seq : public Collection<ListDS, E> {
    typedef Collection<ListDS, E> Super;
     public:
      Seq(Engine * e) : Super(e) {};

      Seq(const Seq<E>& other) : Super(other)  {}

      Seq(Super other) : Super(other) {}

      // Convert from Collection<ListDS, E> to Seq<E>
      std::tuple<Seq<E>, Seq<E>> split() {
        auto tup = Super::split();
        Super ds1 = get<0>(tup);
        Super ds2 = get<1>(tup);
        return std::make_tuple(Seq<E>(ds1), Seq<E>(ds2));
      }

      Seq<E> combine(const Seq<E>& other) {
       return Seq<E>(Super::combine(other));
      }

      template <class T>
      Seq<T> map(std::function<T(E)> f) {
       return Seq<T>(Super::map(f));
      }

      Seq<E> filter(std::function<bool(E)> f) {
       return Seq<E>(Super::filter(f));
      }

      Seq<E> sort(std::function<int(E,E)> f) {
        Super s = Super(ListDS<E>::sort(f));
        return Seq<E>(s);

      }

      template <class K, class Z>
      Seq<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<ListDS, std::tuple<K,Z>> s = Super::group_by(grouper,folder,init);
        return Seq<std::tuple<K,Z>>(s);
      }

      template <class T>
      Seq<T> ext(std::function<Collection<ListDS, T>(E)> expand) {
        Collection<ListDS, T> result = Super::ext(expand);
        return Seq<T>(result);
      }
  };

  template <typename E>
  // TODO: make this more generic? ie a SetDS interface
  class Set : public Collection<SetDS, E> {
    typedef Collection<SetDS, E> Super;
    typedef SetDS<E> dataspace;
     public:
      Set(Engine * e) : Super(e) {};

      Set(const Set<E>& other) : Super(other)  {}

      Set(Super other) : Super(other) {}

      // Convert from Collection<ListDS, E> to Set<E>
      std::tuple<Set<E>, Set<E>> split() {
        auto tup = Super::split();
        Super ds1 = get<0>(tup);
        Super ds2 = get<1>(tup);
        return std::make_tuple(Set<E>(ds1), Set<E>(ds2));
      }

      Set<E> combine(const Set<E>& other) {
       return Set<E>(Super::combine(other));
      }

      template <class T>
      Set<T> map(std::function<T(E)> f) {
       return Set<T>(Super::map(f));
      }

      Set<E> filter(std::function<bool(E)> f) {
       return Set<E>(Super::filter(f));
      }

      template <class K, class Z>
      Set<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SetDS, std::tuple<K,Z>> s = Super::group_by(grouper,folder,init);
        return Set<std::tuple<K,Z>>(s);
      }

      template <class T>
      Set<T> ext(std::function<Collection<SetDS, T>(E)> expand) {
        Collection<SetDS, T> result = Super::ext(expand);
        return Set<T>(result);
      }

      bool member(E e) {
        return dataspace::member(e);
      }

      bool isSubsetOf(SetDS<E> other) {
        return dataspace::isSubsetOf(other);
      }

      // TODO union is a reserved word
      Set union1(Set<E> other) {
        Super s = Super(dataspace::union1(other));
        return Set<E>(s);
      }

      Set intersect(Set<E> other) {
        Super s = Super(dataspace::intersect(other));
        return Set<E>(s);
      }

      Set difference(Set<E> other) {
        Super s = Super(dataspace::difference(other));
        return Set<E>(s);
      }

  };

  template <typename E>
  class Sorted : public Collection<SortedDS, E> {
    typedef Collection<SortedDS, E> Super;
    typedef SortedDS<E> dataspace;
     public:
      Sorted(Engine * e) : Super(e) {};

      Sorted(const Sorted<E>& other) : Super(other)  {}

      Sorted(Super other) : Super(other) {}

      // Convert from Collection<ListDS, E> to Sorted<E>
      std::tuple<Sorted<E>, Sorted<E>> split() {
        auto tup = Super::split();
        Super ds1 = get<0>(tup);
        Super ds2 = get<1>(tup);
        return std::make_tuple(Sorted<E>(ds1), Sorted<E>(ds2));
      }

      Sorted<E> combine(const Sorted<E>& other) {
       return Sorted<E>(Super::combine(other));
      }

      template <class T>
      Sorted<T> map(std::function<T(E)> f) {
       return Sorted<T>(Super::map(f));
      }

      Sorted<E> filter(std::function<bool(E)> f) {
       return Sorted<E>(Super::filter(f));
      }

      template <class K, class Z>
      Sorted<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SortedDS, std::tuple<K,Z>> s = Super::group_by(grouper,folder,init);
        return Sorted<std::tuple<K,Z>>(s);
      }

      template <class T>
      Sorted<T> ext(std::function<Collection<SortedDS, T>(E)> expand) {
        Collection<SortedDS, T> result = Super::ext(expand);
        return Sorted<T>(result);
      }

      shared_ptr<E> min() { return dataspace::min(); }

      shared_ptr<E> max() { return dataspace::max(); }

      shared_ptr<E> lowerBound(E a) { return dataspace::lowerBound(a); }

      shared_ptr<E> upperBound(E a) { return dataspace::lowerBound(a); }

      Sorted<E> slice(E a, E b) {
        Super s = Super(dataspace::slice(a,b));
        return Sorted<E>(s);
      }

  };

  template <typename E>
  // TODO: make this more generic? ie an ExternalDS interface
  class ExternalCollection : public Collection<FileDS, E> {
    typedef Collection<FileDS, E> Super;
    typedef FileDS<E> Dataspace;
     public:
      ExternalCollection(Engine * e) : Super(e) {};

      ExternalCollection(const ExternalCollection<E>& other) : Super(other)  {}

      ExternalCollection(const Super& other) : Super(other) {}
      ExternalCollection(Super&& other) : Super(std::move(other)) {}

      // Convert from Collection<ListDS, E> to Set<E>
      std::tuple<Set<E>, Set<E>> split() {
        auto tup = Super::split();
        Super& ds1 = get<0>(tup);
        Super& ds2 = get<1>(tup);
        return std::make_tuple(ExternalCollection<E>(ds1), ExternalCollection<E>(ds2));
      }

      ExternalCollection<E> combine(const ExternalCollection<E>& other) {
       return ExternalCollection<E>(Super::combine(other));
      }

      template <class T>
      ExternalCollection<T> map(std::function<T(E)> f) {
       return ExternalCollection<T>(Super::map(f));
      }

      ExternalCollection<E> filter(std::function<bool(E)> f) {
       return ExternalCollection<E>(Super::filter(f));
      }

      template <class K, class Z>
      ExternalCollection<std::tuple<K, Z>> group_by
            (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<FileDS, std::tuple<K,Z>> s = Super::group_by(grouper,folder,init);
        return ExternalCollection<std::tuple<K,Z>>(s);
      }

      template <class T>
      ExternalCollection<T> ext(std::function<Collection<SetDS, T>(E)> expand) {
        Collection<SetDS, T> result = Super::ext(expand);
        return ExternalCollection<T>(result);
      }
  };
}

#endif
<|endoftext|>


<commit_before>
#include "PolycodeView.h"
#include "PolyWinCore.h"
#include "PolyCoreServices.h"
#include "PolyCoreInput.h"
#include "PolyRenderer.h"

using namespace Polycode;

Win32Core *core = NULL;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	int nWidth, nHeight;

	if(!core)
		return DefWindowProc(hWnd, message, wParam, lParam);

	switch (message)
	{
	case WM_SIZE:
		nWidth = LOWORD(lParam);
		nHeight = HIWORD(lParam);
		if(core)
			core->getServices()->getRenderer()->Resize(nWidth, nHeight);
	break;

	case WM_MOUSEMOVE:
		if(core)
			core->handleMouseMove(lParam,wParam);
	break;

	case WM_MOUSEWHEEL:
		if(core)
			core->handleMouseWheel(lParam,wParam);
	break;

	case WM_LBUTTONDOWN:
		if(core)
			core->handleMouseDown(CoreInput::MOUSE_BUTTON1, lParam,wParam);
	break;
	case WM_LBUTTONUP:
		if(core)
			core->handleMouseUp(CoreInput::MOUSE_BUTTON1, lParam,wParam);
	break;

	case WM_RBUTTONDOWN:
		if(core)
			core->handleMouseDown(CoreInput::MOUSE_BUTTON2, lParam,wParam);
	break;
	case WM_RBUTTONUP:
		if(core)
			core->handleMouseUp(CoreInput::MOUSE_BUTTON2, lParam,wParam);
	break;

	case WM_MBUTTONDOWN:
		if(core)
			core->handleMouseDown(CoreInput::MOUSE_BUTTON3, lParam,wParam);
	break;
	case WM_MBUTTONUP:
		if(core)
			core->handleMouseUp(CoreInput::MOUSE_BUTTON3, lParam,wParam);
	break;
	case WM_KEYDOWN:
		if(core) {
				wchar_t unicodeChar = 0;
				MSG m;
				m.hwnd = hWnd;
				m.message = message;
				m.wParam = wParam;
				m.lParam = lParam;
				m.time = 0;
				if ( PeekMessage(&m, hWnd, 0, WM_USER, PM_NOREMOVE) && (m.message == WM_CHAR) ) {
					GetMessage(&m, hWnd, 0, WM_USER);
			    		unicodeChar = (wchar_t)m.wParam;
				}

			core->handleKeyDown(lParam,wParam, unicodeChar);
		}
	break;
	case WM_KEYUP:
		if(core)
			core->handleKeyUp(lParam,wParam);
	break;
	case WM_CLOSE:
		if(core)
			core->Shutdown();
	break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

PolycodeView::PolycodeView(HINSTANCE hInstance, int nCmdShow, LPCTSTR windowTitle) : PolycodeViewBase() {

WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, IDI_APPLICATION);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= NULL;
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= L"POLYCODEAPPLICATION";
	wcex.hIconSm		= LoadIcon(hInstance, IDI_APPLICATION);

	RegisterClassEx(&wcex);

  hwnd = CreateWindowEx(WS_EX_APPWINDOW, L"POLYCODEAPPLICATION", windowTitle, WS_OVERLAPPED|WS_SYSMENU,
      0, 0, 640, 480, NULL, NULL, hInstance, NULL);

  windowData = (void*)&hwnd;

   ShowWindow(hwnd, nCmdShow);
   UpdateWindow(hwnd);

}

PolycodeView::~PolycodeView() {

}<commit_msg>Close-to-quit works correctly in Windows PolycodeView<commit_after>
#include "PolycodeView.h"
#include "PolyWinCore.h"
#include "PolyCoreServices.h"
#include "PolyCoreInput.h"
#include "PolyRenderer.h"

using namespace Polycode;

Win32Core *core = NULL;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	int nWidth, nHeight;
	bool useDefault = false;

	if(!core)
		return DefWindowProc(hWnd, message, wParam, lParam);

	switch (message)
	{
	case WM_SIZE:
		nWidth = LOWORD(lParam);
		nHeight = HIWORD(lParam);
		if(core)
			core->getServices()->getRenderer()->Resize(nWidth, nHeight);
	break;

	case WM_MOUSEMOVE:
		if(core)
			core->handleMouseMove(lParam,wParam);
	break;

	case WM_MOUSEWHEEL:
		if(core)
			core->handleMouseWheel(lParam,wParam);
	break;

	case WM_LBUTTONDOWN:
		if(core)
			core->handleMouseDown(CoreInput::MOUSE_BUTTON1, lParam,wParam);
	break;
	case WM_LBUTTONUP:
		if(core)
			core->handleMouseUp(CoreInput::MOUSE_BUTTON1, lParam,wParam);
	break;

	case WM_RBUTTONDOWN:
		if(core)
			core->handleMouseDown(CoreInput::MOUSE_BUTTON2, lParam,wParam);
	break;
	case WM_RBUTTONUP:
		if(core)
			core->handleMouseUp(CoreInput::MOUSE_BUTTON2, lParam,wParam);
	break;

	case WM_MBUTTONDOWN:
		if(core)
			core->handleMouseDown(CoreInput::MOUSE_BUTTON3, lParam,wParam);
	break;
	case WM_MBUTTONUP:
		if(core)
			core->handleMouseUp(CoreInput::MOUSE_BUTTON3, lParam,wParam);
	break;
	case WM_KEYDOWN:
		if(core) {
				wchar_t unicodeChar = 0;
				MSG m;
				m.hwnd = hWnd;
				m.message = message;
				m.wParam = wParam;
				m.lParam = lParam;
				m.time = 0;
				if ( PeekMessage(&m, hWnd, 0, WM_USER, PM_NOREMOVE) && (m.message == WM_CHAR) ) {
					GetMessage(&m, hWnd, 0, WM_USER);
			    		unicodeChar = (wchar_t)m.wParam;
				}

			core->handleKeyDown(lParam,wParam, unicodeChar);
		}
	break;
	case WM_KEYUP:
		if(core)
			core->handleKeyUp(lParam,wParam);
	break;
	case WM_CLOSE:
		if(core)
			core->Shutdown();
		useDefault = true;
	break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		useDefault = true;
		break;
	}

	if (useDefault)
		return DefWindowProc(hWnd, message, wParam, lParam);
	else
		return 0;
}

PolycodeView::PolycodeView(HINSTANCE hInstance, int nCmdShow, LPCTSTR windowTitle) : PolycodeViewBase() {

WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, IDI_APPLICATION);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= NULL;
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= L"POLYCODEAPPLICATION";
	wcex.hIconSm		= LoadIcon(hInstance, IDI_APPLICATION);

	RegisterClassEx(&wcex);

  hwnd = CreateWindowEx(WS_EX_APPWINDOW, L"POLYCODEAPPLICATION", windowTitle, WS_OVERLAPPED|WS_SYSMENU,
      0, 0, 640, 480, NULL, NULL, hInstance, NULL);

  windowData = (void*)&hwnd;

   ShowWindow(hwnd, nCmdShow);
   UpdateWindow(hwnd);

}

PolycodeView::~PolycodeView() {

}<|endoftext|>


<commit_before>///
/// @file
/// @details Defines the functions that perform the basic tests for the racecar drivetrain.
///
/// <!-- Copyright (c) Tim Beaudet 2017 - All Rights Reserved -->
///-----------------------------------------------------------------------------------------------------------------///

#include "basic_test.h"

#include "../racecar/racecar_wheel.h"

#include <cstdio>

#define log_test(message, ...)   printf(message, ##__VA_ARGS__)
static const float kTestElipson(0.0001f);

class RotatingMass : public Racecar::RotatingBody
{
public:
	explicit RotatingMass(const float momentOfInertia) :
		RotatingBody()
	{
		SetInertia(momentOfInertia);
	}

	RotatingMass(const float massInKilograms, const float radiusInMeters) :
		RotatingBody()
	{
		SetInertia(Racecar::ComputeInertiaMetric(massInKilograms, radiusInMeters));
	}

	virtual ~RotatingMass(void)
	{
	}
};

bool Racecar::UnitTests::PerformBasicTests(void)
{
	RotatingMass rotatingMass(10.0f); //10kg-m.
	RotatingMass rotatingMass2(10.0f, 1.0f);

	if (fabsf(rotatingMass.GetInertia() - rotatingMass2.GetInertia() > kTestElipson))
	{
		log_test("Failed accessing expected moments of inertia.");
		return false;
	}

	return false;
}
<commit_msg>Adding more tests!<commit_after>///
/// @file
/// @details Defines the functions that perform the basic tests for the racecar drivetrain.
///
/// <!-- Copyright (c) Tim Beaudet 2017 - All Rights Reserved -->
///-----------------------------------------------------------------------------------------------------------------///

#include "basic_test.h"

#include "../racecar/racecar_wheel.h"

#include <cstdio>

#define log_test(message, ...)   printf(message, ##__VA_ARGS__)
static const float kTestElipson(0.0001f);

class RotatingMass : public Racecar::RotatingBody
{
public:
	explicit RotatingMass(const float momentOfInertia) :
		RotatingBody()
	{
		SetInertia(momentOfInertia);
	}

	RotatingMass(const float massInKilograms, const float radiusInMeters) :
		RotatingBody()
	{
		SetInertia(Racecar::ComputeInertiaMetric(massInKilograms, radiusInMeters));
	}

	virtual ~RotatingMass(void)
	{
	}
};

bool ConstructionTest(void);
bool ConstantTorqueTest(void);

bool Racecar::UnitTests::PerformBasicTests(void)
{
	if (false == ConstructionTest()) { log_test("Failed: Expected to pass the ConstructionTest().\n"); return false; }
	if (false == ConstantTorqueTest()) { log_test("Failed: Expected to pass the ConstantTorqueTest().\n"); return false; }

	log_test("The Racecar has successfully passed technical inspection. You may now go racing!");
	return true;
}

bool ConstructionTest(void)
{
	RotatingMass rotatingMass(10.0f); //10kg-m.
	if (fabsf(rotatingMass.GetInertia() - 10.0f) > kTestElipson)
	{
		log_test("Failed accessing expected moments of inertia.");
		return false;
	}

	RotatingMass rotatingMass2(10.0f, 1.0f);
	if (fabsf(rotatingMass.GetInertia() - rotatingMass2.GetInertia()) > kTestElipson)
	{
		log_test("Failed accessing expected moments of inertia.");
		return false;
	}

	const float startingVelocity(rotatingMass.GetAngularVelocity());
	if (fabsf(startingVelocity) > kTestElipson)
	{
		log_test("Failed: Expected rotating body to have no angular velocity upon construction. Found: %f\n", startingVelocity);
		return false;
	}

	return true;
}

bool ConstantTorqueTest(void)
{
	RotatingMass rotatingMass(10.0f); //10kg-m.

	//Simulate 1 second of applying a 10Nm torque to the rotating body.
	for (int timer(0); timer < 1000; timer += 10)
	{
		rotatingMass.ApplyDownstreamTorque(10.0f, rotatingMass);
		rotatingMass.Simulate(); //Simulates 10ms of action.
	}

	const float finalVelocity(rotatingMass.GetAngularVelocity());
	log_test("Final velocity: %f\n", finalVelocity);

	return false;
}<|endoftext|>


<commit_before>/*
 * Jamoma 2-Dimensional Matrix Data Class
 * Copyright © 2011-2012, Timothy Place & Nathan Wolek
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTMatrix.h"
#include "TTEnvironment.h"
#include "TTBase.h"

#define thisTTClass			TTMatrix
#define thisTTClassName		"matrix"
#define thisTTClassTags		"matrix"

TT_OBJECT_CONSTRUCTOR,
	mData(NULL),
	mRowCount(1), // initialize to a 1x1 matrix by default (maybe we should be using the args?)
	mColumnCount(1), // initialize to a 1x1 matrix by default (maybe we should be using the args?)
	mElementCount(1),
	mComponentCount(1),
	mComponentStride(1),
	mDataCount(0),
	mType(TT("uint8")),
	mTypeSizeInBytes(1),
	mDataSize(0),
	mDataIsLocallyOwned(YES),
	mHeadPtr(NULL),
	mTailPtr(NULL)
{
	addAttributeWithGetterAndSetter(Dimensions, 	kTypeUInt32); // DEPRECATION in progress
	addAttributeWithSetter(RowCount, 				kTypeUInt32);
	addAttributeWithSetter(ColumnCount, 			kTypeUInt32);
	addAttributeWithSetter(Type,					kTypeUInt8);
	addAttributeWithSetter(ElementCount,			kTypeUInt8);

	addMessage(clear);
	addMessageWithArguments(fill);
	addMessageWithArguments(get);
	addMessageWithArguments(set);

	// TODO: getLockedPointer -- returns a pointer to the data, locks the matrix mutex
	// TODO: releaseLockedPointer -- releases the matrix mutex
	// TODO: the above two items mean we need a TTMutex member

	resize();

	// DEPRECATION in progress: setAttributeValue(TT("dimensions"), kTTVal1);

}

TTMatrix::~TTMatrix()
{
	if (mDataIsLocallyOwned)
		delete[] mData; // TODO: only do this if the refcount for the data is down to zero!
}

TTErr TTMatrix::resize()
{
	mComponentCount = mRowCount * mColumnCount;
	mDataCount = mComponentCount * mElementCount;
	mDataSize = mDataCount * mTypeSizeInBytes;
	mComponentStride = mTypeSizeInBytes * mElementCount;

	if (mDataIsLocallyOwned) {
		// TODO: currently, we are not preserving memory when resizing. Should we try to preserve the previous memory contents?
		// TODO: thread protection
		delete[] mData;
		mData = new TTByte[mDataSize];
		mHeadPtr = mData;
		mTailPtr = mData + mDataSize;
	}

	if (mDataSize && mData)
	{
		return kTTErrNone;
	} else {
		return kTTErrAllocFailed;
	}
}

TTErr TTMatrix::copy(const TTMatrix& source, TTMatrix& dest)
{
	dest.adaptTo(source);
	memcpy(dest.mData, source.mData, source.mDataSize);
	return kTTErrNone;
}

TTErr TTMatrix::adaptTo(const TTMatrix& anotherMatrix)
{
	TTValue v;

	// TODO: what should we do if anotherMatrix is not locally owned?
	// It would be nice to re-dimension the data, but we can't re-alloc / resize the number of bytes...

	anotherMatrix.getDimensions(v);
	setDimensions(v);

	setType(anotherMatrix.mType);
	setElementCount(anotherMatrix.mElementCount);

	return kTTErrNone;
}

TTBoolean TTMatrix::setRowCountWithoutResize(TTUInt32 aNewRowCount)
{
	if (aNewRowCount > 0)
	{
		mRowCount = aNewRowCount;
		return true;
	} else {
		return false;
	}
}

TTBoolean TTMatrix::setColumnCountWithoutResize(TTUInt32 aNewColumnCount)
{
	if (aNewColumnCount > 0)
	{
		mColumnCount = aNewColumnCount;
		return true;
	} else {
		return false;
	}
}

TTBoolean TTMatrix::setElementCountWithoutResize(TTUInt8 aNewElementCount)
{
	if (aNewElementCount > 0)
	{
		mElementCount = aNewElementCount;
		return true;
	} else {
		return false;
	}
}

TTBoolean TTMatrix::setTypeWithoutResize(TTDataInfoPtr aNewType)
{
	if (aNewType->isNumerical)
	{
		mType = aNewType->name;
		mTypeSizeInBytes = (aNewType->bitdepth / 8);
		return true;
	} else {
		return false;
	}
}

TTErr TTMatrix::setRowCount(const TTValue& aNewRowCount)
{
	TTUInt32 aNewRowCountInt = aNewRowCount;

	if (setRowCountWithoutResize(aNewRowCountInt))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setColumnCount(const TTValue& aNewColumnCount)
{
	TTUInt32 aNewColumnCountInt = aNewColumnCount;

	if (setColumnCountWithoutResize(aNewColumnCountInt))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setElementCount(const TTValue& newElementCount)
{
	TTUInt8 aNewElementCountInt = newElementCount;

	if (setElementCountWithoutResize(aNewElementCountInt))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setType(const TTValue& aType)
{
	TTSymbolPtr aNewTypeName = aType;
	TTDataInfoPtr aNewDataType = TTDataInfo::getInfoForType(aNewTypeName);

	if (setTypeWithoutResize(aNewDataType))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setDimensions(const TTValue& someNewDimensions)
{
	TTUInt32 aNewRowCount = 1;
	TTUInt32 aNewColumnCount = 1;

	TTUInt8	size = someNewDimensions.getSize();

	// needed to support old calls with 1 or 2 dimensions
	if (size > 0) { someNewDimensions.get(0, aNewRowCount); }
	if (size > 1) { someNewDimensions.get(1, aNewColumnCount); }

	if (this->setRowCountWithoutResize(aNewRowCount) &&
		this->setColumnCountWithoutResize(aNewColumnCount))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::getDimensions(TTValue& returnedDimensions) const
{
	returnedDimensions.setSize(2);
	returnedDimensions.set(0, mRowCount);
	returnedDimensions.set(1, mColumnCount);

	return kTTErrNone;
}

TTErr TTMatrix::clear()
{
	memset(mData, 0, mDataSize);
	return kTTErrNone;
}

TTErr TTMatrix::fill(const TTValue& anInputValue, TTValue &anUnusedOutputValue)
{
	TTBytePtr fillValue = new TTByte[mComponentStride];

	// TODO: here we have this ugly switch again...
	if (mType == TT("uint8"))
		anInputValue.getArray((TTUInt8*)fillValue, mElementCount);
	else if (mType == TT("int32"))
		anInputValue.getArray((TTInt32*)fillValue, mElementCount);
	else if (mType == TT("float32"))
		anInputValue.getArray((TTFloat32*)fillValue, mElementCount);
	else if (mType == TT("float64"))
		anInputValue.getArray((TTFloat64*)fillValue, mElementCount);

	for (TTUInt32 i=0; i<mDataSize; i += mComponentStride)
		memcpy(mData+i, fillValue, mComponentStride);

	delete[] fillValue;
	return kTTErrNone;
}

/*
	To find the index in the matrix:

	1D Matrix:	index = x
	2D Matrix:	index = dim_0 y  +  x
	3D Matrix:	index = dim_0 dim_1 z  +  dim_0 y  +  x
	etc.
 */

// args passed-in should be the coordinates
// args returned will be the value at those coordinates
TTErr TTMatrix::get(const TTValue& anInputValue, TTValue &anOutputValue) const
{
	TTUInt16 dimensionCount = anInputValue.getSize();

	if (dimensionCount != mDimensions.size())
		return kTTErrWrongNumValues;

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = anInputValue.getInt32(d);

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	anOutputValue.clear();

	// TODO: here we have this ugly switch again...
	// Maybe we could just have duplicate pointers of different types in our class, and then we could access them more cleanly?
	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTUInt8*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTInt32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTFloat32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTFloat64*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

/*

template<typename T>
TTErr TTMatrix::get2dWithinBounds(TTRowID i, TTColumnID j, T& data)
{
		//TTUInt32 m = mRowCount;
		TTUInt32 n = mColumnCount;

		i -= 1;	// convert to zero-based indices for data access
		j -= 1;	// convert to zero-based indices for data access

		TTUInt32 distanceFromHead = (i*n+j) * mComponentStride;
		TTBoolean isInBounds = inBoundsZeroIndex(distanceFromHead);
		if (isInBounds)
		{
			data = *(T*)(mData + distanceFromHead);
			return kTTErrNone;
		} else {
			return kTTErrInvalidValue;
		}
}

*/

// args passed-in should be the coordinates plus the value
TTErr TTMatrix::set(const TTValue& anInputValue, TTValue &anUnusedOutputValue)
{
	TTValue		theValue;
	TTValue		theDimensions = anInputValue;
	TTUInt16	dimensionCount = anInputValue.getSize() - mElementCount;

	if (dimensionCount != mDimensions.size())
		return kTTErrWrongNumValues;

	theValue.copyFrom(anInputValue, dimensionCount);
	theDimensions.setSize(dimensionCount);

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = anInputValue.getInt32(d) - 1; // subtract 1 to get back to zero-based indices for mem access in C

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTUInt8*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTInt32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTFloat32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTFloat64*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

TTBoolean TTMatrix::allAttributesMatch(const TTMatrix* A, const TTMatrix* B)
{
	if (A->mType == B->mType  &&
		A->mElementCount == B->mElementCount &&
		A->mRowCount == B->mRowCount &&
		A->mColumnCount == B->mColumnCount)
		{
			return true;
		} else {
			return false;
		}
}

TTErr TTMatrix::iterate(TTMatrix* C, const TTMatrix* A, const TTMatrix* B, TTMatrixIterator iterator)
{
	//TTBoolean AmatchesB = allAttributesMatch(A, B);
	if (true) {
		int stride = A->mTypeSizeInBytes;
		int size = A->mDataSize;
		TTValue		dims;		// DEPRECATION in progress

		C->setAttributeValue(kTTSym_type, A->mType);
		C->setAttributeValue(kTTSym_elementCount, A->mElementCount);

		/* DEPRECATION in progress: the following section had to be changed to prevent malloc errors. results are less efficient code, but this will be regained once mRowCount & mColumnCount are fully implemented. */

		dims.setSize(2);
		dims.set(0, A->mRowCount);
		dims.set(1, A->mColumnCount);
		C->setAttributeValue(kTTSym_dimensions, dims);

		/* DEPRECATION in progress: end section to be changed */

		for (int k=0; k<size; k+=stride)
			(*iterator)(C->mData+k, A->mData+k, B->mData+k);

		return kTTErrNone;
	}
	else
		return kTTErrGeneric;
}

<commit_msg>TTMatrix: removing mDimensions from get/set in progress<commit_after>/*
 * Jamoma 2-Dimensional Matrix Data Class
 * Copyright © 2011-2012, Timothy Place & Nathan Wolek
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTMatrix.h"
#include "TTEnvironment.h"
#include "TTBase.h"

#define thisTTClass			TTMatrix
#define thisTTClassName		"matrix"
#define thisTTClassTags		"matrix"

TT_OBJECT_CONSTRUCTOR,
	mData(NULL),
	mRowCount(1), // initialize to a 1x1 matrix by default (maybe we should be using the args?)
	mColumnCount(1), // initialize to a 1x1 matrix by default (maybe we should be using the args?)
	mElementCount(1),
	mComponentCount(1),
	mComponentStride(1),
	mDataCount(0),
	mType(TT("uint8")),
	mTypeSizeInBytes(1),
	mDataSize(0),
	mDataIsLocallyOwned(YES),
	mHeadPtr(NULL),
	mTailPtr(NULL)
{
	addAttributeWithGetterAndSetter(Dimensions, 	kTypeUInt32); // DEPRECATION in progress
	addAttributeWithSetter(RowCount, 				kTypeUInt32);
	addAttributeWithSetter(ColumnCount, 			kTypeUInt32);
	addAttributeWithSetter(Type,					kTypeUInt8);
	addAttributeWithSetter(ElementCount,			kTypeUInt8);

	addMessage(clear);
	addMessageWithArguments(fill);
	addMessageWithArguments(get);
	addMessageWithArguments(set);

	// TODO: getLockedPointer -- returns a pointer to the data, locks the matrix mutex
	// TODO: releaseLockedPointer -- releases the matrix mutex
	// TODO: the above two items mean we need a TTMutex member

	resize();

	// DEPRECATION in progress: setAttributeValue(TT("dimensions"), kTTVal1);

}

TTMatrix::~TTMatrix()
{
	if (mDataIsLocallyOwned)
		delete[] mData; // TODO: only do this if the refcount for the data is down to zero!
}

TTErr TTMatrix::resize()
{
	mComponentCount = mRowCount * mColumnCount;
	mDataCount = mComponentCount * mElementCount;
	mDataSize = mDataCount * mTypeSizeInBytes;
	mComponentStride = mTypeSizeInBytes * mElementCount;

	if (mDataIsLocallyOwned) {
		// TODO: currently, we are not preserving memory when resizing. Should we try to preserve the previous memory contents?
		// TODO: thread protection
		delete[] mData;
		mData = new TTByte[mDataSize];
		mHeadPtr = mData;
		mTailPtr = mData + mDataSize;
	}

	if (mDataSize && mData)
	{
		return kTTErrNone;
	} else {
		return kTTErrAllocFailed;
	}
}

TTErr TTMatrix::copy(const TTMatrix& source, TTMatrix& dest)
{
	dest.adaptTo(source);
	memcpy(dest.mData, source.mData, source.mDataSize);
	return kTTErrNone;
}

TTErr TTMatrix::adaptTo(const TTMatrix& anotherMatrix)
{
	TTValue v;

	// TODO: what should we do if anotherMatrix is not locally owned?
	// It would be nice to re-dimension the data, but we can't re-alloc / resize the number of bytes...

	anotherMatrix.getDimensions(v);
	setDimensions(v);

	setType(anotherMatrix.mType);
	setElementCount(anotherMatrix.mElementCount);

	return kTTErrNone;
}

TTBoolean TTMatrix::setRowCountWithoutResize(TTUInt32 aNewRowCount)
{
	if (aNewRowCount > 0)
	{
		mRowCount = aNewRowCount;
		return true;
	} else {
		return false;
	}
}

TTBoolean TTMatrix::setColumnCountWithoutResize(TTUInt32 aNewColumnCount)
{
	if (aNewColumnCount > 0)
	{
		mColumnCount = aNewColumnCount;
		return true;
	} else {
		return false;
	}
}

TTBoolean TTMatrix::setElementCountWithoutResize(TTUInt8 aNewElementCount)
{
	if (aNewElementCount > 0)
	{
		mElementCount = aNewElementCount;
		return true;
	} else {
		return false;
	}
}

TTBoolean TTMatrix::setTypeWithoutResize(TTDataInfoPtr aNewType)
{
	if (aNewType->isNumerical)
	{
		mType = aNewType->name;
		mTypeSizeInBytes = (aNewType->bitdepth / 8);
		return true;
	} else {
		return false;
	}
}

TTErr TTMatrix::setRowCount(const TTValue& aNewRowCount)
{
	TTUInt32 aNewRowCountInt = aNewRowCount;

	if (setRowCountWithoutResize(aNewRowCountInt))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setColumnCount(const TTValue& aNewColumnCount)
{
	TTUInt32 aNewColumnCountInt = aNewColumnCount;

	if (setColumnCountWithoutResize(aNewColumnCountInt))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setElementCount(const TTValue& newElementCount)
{
	TTUInt8 aNewElementCountInt = newElementCount;

	if (setElementCountWithoutResize(aNewElementCountInt))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setType(const TTValue& aType)
{
	TTSymbolPtr aNewTypeName = aType;
	TTDataInfoPtr aNewDataType = TTDataInfo::getInfoForType(aNewTypeName);

	if (setTypeWithoutResize(aNewDataType))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::setDimensions(const TTValue& someNewDimensions)
{
	TTUInt32 aNewRowCount = 1;
	TTUInt32 aNewColumnCount = 1;

	TTUInt8	size = someNewDimensions.getSize();

	// needed to support old calls with 1 or 2 dimensions
	if (size > 0) { someNewDimensions.get(0, aNewRowCount); }
	if (size > 1) { someNewDimensions.get(1, aNewColumnCount); }

	if (this->setRowCountWithoutResize(aNewRowCount) &&
		this->setColumnCountWithoutResize(aNewColumnCount))
	{
		return resize();
	} else {
		return kTTErrInvalidValue;
	}
}

TTErr TTMatrix::getDimensions(TTValue& returnedDimensions) const
{
	returnedDimensions.setSize(2);
	returnedDimensions.set(0, mRowCount);
	returnedDimensions.set(1, mColumnCount);

	return kTTErrNone;
}

TTErr TTMatrix::clear()
{
	memset(mData, 0, mDataSize);
	return kTTErrNone;
}

TTErr TTMatrix::fill(const TTValue& anInputValue, TTValue &anUnusedOutputValue)
{
	TTBytePtr fillValue = new TTByte[mComponentStride];

	// TODO: here we have this ugly switch again...
	if (mType == TT("uint8"))
		anInputValue.getArray((TTUInt8*)fillValue, mElementCount);
	else if (mType == TT("int32"))
		anInputValue.getArray((TTInt32*)fillValue, mElementCount);
	else if (mType == TT("float32"))
		anInputValue.getArray((TTFloat32*)fillValue, mElementCount);
	else if (mType == TT("float64"))
		anInputValue.getArray((TTFloat64*)fillValue, mElementCount);

	for (TTUInt32 i=0; i<mDataSize; i += mComponentStride)
		memcpy(mData+i, fillValue, mComponentStride);

	delete[] fillValue;
	return kTTErrNone;
}

/*
	To find the index in the matrix:

	1D Matrix:	index = x
	2D Matrix:	index = dim_0 y  +  x
	3D Matrix:	index = dim_0 dim_1 z  +  dim_0 y  +  x
	etc.
 */

// args passed-in should be the 2 coordinates
// args returned will be the value(s) at those coordinates
TTErr TTMatrix::get(const TTValue& anInputValue, TTValue &anOutputValue) const
{
	TTUInt16 dimensionCount = anInputValue.getSize();

	if (dimensionCount != 2) // 2 dimensions only
		return kTTErrWrongNumValues;
/*
	TTUInt32 i, j, index;
	anInputValue.get(0, i);
	anInputValue.get(1, j)
	index = i*mColumnCount+j;
*/

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = anInputValue.getInt32(d);

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	anOutputValue.clear();

	// TODO: here we have this ugly switch again...
	// Maybe we could just have duplicate pointers of different types in our class, and then we could access them more cleanly?
	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTUInt8*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTInt32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTFloat32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			anOutputValue.append((TTFloat64*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

/*

template<typename T>
TTErr TTMatrix::get2dWithinBounds(TTRowID i, TTColumnID j, T& data)
{
		//TTUInt32 m = mRowCount;
		TTUInt32 n = mColumnCount;

		i -= 1;	// convert to zero-based indices for data access
		j -= 1;	// convert to zero-based indices for data access

		TTUInt32 distanceFromHead = (i*n+j) * mComponentStride;
		TTBoolean isInBounds = inBoundsZeroIndex(distanceFromHead);
		if (isInBounds)
		{
			data = *(T*)(mData + distanceFromHead);
			return kTTErrNone;
		} else {
			return kTTErrInvalidValue;
		}
}

*/

// args passed-in should be the coordinates plus the value
TTErr TTMatrix::set(const TTValue& anInputValue, TTValue &anUnusedOutputValue)
{
	TTValue		theValue;
	TTValue		theDimensions = anInputValue;
	TTUInt16	dimensionCount = anInputValue.getSize() - mElementCount;

	if (dimensionCount != ( 2 + mElementCount )) // 2 dimensions plus number of elements at coordinates
		return kTTErrWrongNumValues;

	theValue.copyFrom(anInputValue, dimensionCount);
	theDimensions.setSize(dimensionCount);

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = anInputValue.getInt32(d) - 1; // subtract 1 to get back to zero-based indices for mem access in C

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTUInt8*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTInt32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTFloat32*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			anInputValue.get(e+dimensionCount, *(TTFloat64*)(mData+(index*mComponentStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

TTBoolean TTMatrix::allAttributesMatch(const TTMatrix* A, const TTMatrix* B)
{
	if (A->mType == B->mType  &&
		A->mElementCount == B->mElementCount &&
		A->mRowCount == B->mRowCount &&
		A->mColumnCount == B->mColumnCount)
		{
			return true;
		} else {
			return false;
		}
}

TTErr TTMatrix::iterate(TTMatrix* C, const TTMatrix* A, const TTMatrix* B, TTMatrixIterator iterator)
{
	//TTBoolean AmatchesB = allAttributesMatch(A, B);
	if (true) {
		int stride = A->mTypeSizeInBytes;
		int size = A->mDataSize;
		TTValue		dims;		// DEPRECATION in progress

		C->setAttributeValue(kTTSym_type, A->mType);
		C->setAttributeValue(kTTSym_elementCount, A->mElementCount);

		/* DEPRECATION in progress: the following section had to be changed to prevent malloc errors. results are less efficient code, but this will be regained once mRowCount & mColumnCount are fully implemented. */

		dims.setSize(2);
		dims.set(0, A->mRowCount);
		dims.set(1, A->mColumnCount);
		C->setAttributeValue(kTTSym_dimensions, dims);

		/* DEPRECATION in progress: end section to be changed */

		for (int k=0; k<size; k+=stride)
			(*iterator)(C->mData+k, A->mData+k, B->mData+k);

		return kTTErrNone;
	}
	else
		return kTTErrGeneric;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2013 Gustaf Räntilä
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef LIBQ_THREAD_HPP
#define LIBQ_THREAD_HPP

#include <q/async_termination.hpp>

#include <q/detail/lib.hpp>

namespace q {

/**
 * @returns the number of hard (real) cores available on this machine
 */
std::size_t hard_cores( );

/**
 * @returns the number of soft cores (aka "threads") available on this machine
 */
std::size_t soft_cores( );

namespace detail {

void set_thread_name( const std::string& name );

} // namespace detail

// TODO: Reconsider
// thread* current_thread( );

/**
 * ...
 */
template< typename Ret = void >
class thread
: public std::enable_shared_from_this< thread< Ret > >
, public async_termination<
	q::arguments< >,
	std::tuple< expect< Ret > >
>
{
public:
	typedef expect< Ret >             expect_type;
	typedef std::tuple< expect_type > result_type;
	typedef async_termination<
		q::arguments< >,
		result_type
	>                                 async_terminate_base;

	thread( ) = delete;
	thread( thread< Ret >&& ) = delete;
	thread( const thread< Ret >& ) = delete;
	thread& operator=( const thread< Ret >& ) = delete;

	virtual ~thread( )
	{
		std::cerr << "destructing thread" << std::endl;

		if ( !running_.load( std::memory_order_seq_cst ) )
			return;

		if ( thread_.joinable( ) )
			thread_.join( );
		else
			// We end up here if and only if the thread function
			// itself holds the last reference to 'this'.
			// This happens only if terminate( ) has not been
			// called, and in such case, the thread must be
			// detached and left dangling unmanaged for a short
			// amount of time. We won't be able to wait for it to
			// complete which is unfortunate.
			thread_.detach( );
	}

	std::string name( ) const
	{
		return name_;
	}

	promise< result_type > terminate( )
	{
		auto _this = this->shared_from_this( );

		return async_terminate_base::terminate( )
		.finally( [ _this ]( ) mutable
		{
			// Although joining is a blocking operation,
			// this should never actually block, as this
			// function is only reached once the thread
			// function has completed. Joining should
			// therefore be instant, albeit requiring OS-
			// depentant work.
			_this->try_join( );
		} );
	}

	template< typename Fn, typename... Args >
	static typename std::enable_if<
		std::is_same< Q_RESULT_OF( Fn ), Ret >::value,
		std::shared_ptr< thread< Ret > >
	>::type
	construct( std::string name, const queue_ptr& queue,
		Fn&& fn, Args&&... args )
	{
		auto self = std::shared_ptr< thread< Ret > >(
			new thread< Ret >( std::move( name ), queue ) );

		self->run(
			std::forward< Fn >( fn ),
			std::forward< Args >( args )...
		);

		return self;
	}

protected:
	thread( std::string&& name, const queue_ptr& queue )
	: async_terminate_base( queue )
	, name_( std::move( name ) )
	, running_( false )
	, self_ref_( nullptr )
	{ }

	template< typename Fn, typename... Args >
	typename std::enable_if<
		std::is_same< Q_RESULT_OF( Fn ), Ret >::value
	>::type
	run( Fn&& fn, Args&&... args )
	{
		auto tmp_fn = make_temporarily_copyable(
			std::forward< Fn >( fn ) );

		auto params = forward_decay_as_tuple(
			std::forward< Args >( args )... );

		auto tmp_params = make_temporarily_copyable(
			std::move( params ) );

		auto _this = this->shared_from_this( );
		self_ref_ = _this;

		auto thread_fn = [ _this, tmp_fn, tmp_params ]( ) mutable
		{
			::q::detail::set_thread_name( _this->name_ );

			expect_type expect;

			auto fn = [ tmp_fn, tmp_params ]( ) mutable
			{
				return ::q::call_with_args_by_tuple(
					tmp_fn.consume( ),
					tmp_params.consume( ) );
			};

			try
			{
				expect = ::q::call_with_args_by_fun(
					fulfill< Ret >, fn );
			}
			catch ( ... )
			{
				expect = refuse< Ret >(
					std::current_exception( ) );
				LIBQ_UNCAUGHT_EXCEPTION(
					std::current_exception( ) );
			}

			/* This might seem unsafe, but the destructor of the
			 * class will ensure we join (hence wait for this
			 * operation to complete, which is fast, and at most
			 * will involve just a context switch).
			 */
			_this->termination_done(
				std::make_tuple( std::move( expect ) ) );
			_this.reset( );
		};

		thread_ = std::thread( thread_fn );
		running_.store( true, std::memory_order_seq_cst );
	}

private:
	// This won't do anything. Termination is acknowledged within the
	// thread function instead.
	void do_terminate( ) override
	{
		self_ref_.reset( );
	}

	void try_join( )
	{
		if ( !running_.load( std::memory_order_seq_cst ) )
			return;

		if ( thread_.joinable( ) )
		{
			running_.store( false, std::memory_order_seq_cst );
			thread_.join( );
		}
	}

	std::string                      name_;
	std::thread                      thread_;
	std::atomic< bool >              running_;
	std::shared_ptr< thread< Ret > > self_ref_;
};

/**
 * This is a reusable thread on which multiple tasks can be dispatched.
 * Each task can have its own set of arguments (and types).
 */
class versatile_thread
: public thread< >
{
public:
	versatile_thread( const std::string& name );
	versatile_thread( versatile_thread&& );
	versatile_thread( const versatile_thread& ) = delete;
	~versatile_thread( );

	template< typename Fn, typename... Args >
	void add_task( Fn&& fn, Args&&... args );

private:
	struct pimpl;
	std::unique_ptr< pimpl > pimpl_;
};

template< typename Fn, typename... Args >
std::shared_ptr< thread< Q_RESULT_OF( Fn ) > >
run( std::string name, const queue_ptr& queue, Fn&& fn, Args&&... args )
{
	return thread< Q_RESULT_OF( Fn ) >::construct(
	//return q::make_shared< thread< Q_RESULT_OF( Fn ) > >(
		std::move( name ),
		queue,
		std::forward< Fn >( fn ),
		std::forward< Args >( args )... );
}

} // namespace q

#endif // LIBQ_THREAD_HPP
<commit_msg>Some thread cleanup<commit_after>/*
 * Copyright 2013 Gustaf Räntilä
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef LIBQ_THREAD_HPP
#define LIBQ_THREAD_HPP

#include <q/async_termination.hpp>

#include <q/detail/lib.hpp>

namespace q {

/**
 * @returns the number of hard (real) cores available on this machine
 */
std::size_t hard_cores( );

/**
 * @returns the number of soft cores (aka "threads") available on this machine
 */
std::size_t soft_cores( );

namespace detail {

void set_thread_name( const std::string& name );

} // namespace detail

// TODO: Reconsider
// thread* current_thread( );

/**
 * ...
 */
template< typename Ret = void >
class thread
: public std::enable_shared_from_this< thread< Ret > >
, public async_termination<
	q::arguments< >,
	std::tuple< expect< Ret > >
>
{
public:
	typedef expect< Ret >             expect_type;
	typedef std::tuple< expect_type > result_type;
	typedef async_termination<
		q::arguments< >,
		result_type
	>                                 async_terminate_base;

	thread( ) = delete;
	thread( thread< Ret >&& ) = delete;
	thread( const thread< Ret >& ) = delete;
	thread& operator=( const thread< Ret >& ) = delete;

	virtual ~thread( ) noexcept
	{
		std::cerr << "destructing thread" << std::endl;
		if ( !try_join( ) )
			// We end up here if and only if the thread function
			// itself holds the last reference to 'this'.
			// This happens only if terminate( ) has not been
			// called, and in such case, the thread must be
			// detached and left dangling unmanaged for a short
			// amount of time. We won't be able to wait for it to
			// complete which is unfortunate.
			thread_.detach( );
	}

	std::string name( ) const
	{
		return name_;
	}

	promise< result_type > terminate( )
	{
		auto _this = this->shared_from_this( );

		return async_terminate_base::terminate( );
	}

	q::expect< > await_termination( )
	{
		try_join( );
	}

	template< typename Fn, typename... Args >
	static typename std::enable_if<
		std::is_same< Q_RESULT_OF( Fn ), Ret >::value,
		std::shared_ptr< thread< Ret > >
	>::type
	construct( std::string name, const queue_ptr& queue,
		Fn&& fn, Args&&... args )
	{
		auto self = std::shared_ptr< thread< Ret > >(
			new thread< Ret >( std::move( name ), queue ) );

		self->run(
			std::forward< Fn >( fn ),
			std::forward< Args >( args )...
		);

		return self;
	}

protected:
	thread( std::string&& name, const queue_ptr& queue )
	: async_terminate_base( queue )
	, name_( std::move( name ) )
	, running_( false )
	, self_ref_( nullptr )
	{ }

	template< typename Fn, typename... Args >
	typename std::enable_if<
		std::is_same< Q_RESULT_OF( Fn ), Ret >::value
	>::type
	run( Fn&& fn, Args&&... args )
	{
		auto tmp_fn = make_temporarily_copyable(
			std::forward< Fn >( fn ) );

		auto params = forward_decay_as_tuple(
			std::forward< Args >( args )... );

		auto tmp_params = make_temporarily_copyable(
			std::move( params ) );

		auto _this = this->shared_from_this( );
		self_ref_ = _this;

		auto thread_fn = [ _this, tmp_fn, tmp_params ]( ) mutable
		{
			::q::detail::set_thread_name( _this->name_ );

			expect_type expect;

			auto fn = [ tmp_fn, tmp_params ]( ) mutable
			{
				return ::q::call_with_args_by_tuple(
					tmp_fn.consume( ),
					tmp_params.consume( ) );
			};

			try
			{
				expect = ::q::call_with_args_by_fun(
					fulfill< Ret >, fn );
			}
			catch ( ... )
			{
				// Consider only one of these
				expect = refuse< Ret >(
					std::current_exception( ) );
				LIBQ_UNCAUGHT_EXCEPTION(
					std::current_exception( ) );
			}

			/* This might seem unsafe, but the destructor of the
			 * class will ensure we join (hence wait for this
			 * operation to complete, which is fast, and at most
			 * will involve just a context switch).
			 */
			_this->termination_done(
				std::make_tuple( std::move( expect ) ) );
			_this.reset( );
		};

		thread_ = std::thread( thread_fn );
		running_.store( true, std::memory_order_seq_cst );
	}

private:
	// This won't do anything. Termination is acknowledged within the
	// thread function instead.
	void do_terminate( ) override
	{
		self_ref_.reset( );
	}

	bool try_join( )
	{
		if ( !running_.load( std::memory_order_seq_cst ) )
			return true;

		if ( thread_.joinable( ) )
		{
			running_.store( false, std::memory_order_seq_cst );
			thread_.join( );
			return true;
		}

		return false;
	}

	std::string                      name_;
	std::thread                      thread_;
	std::atomic< bool >              running_;
	std::shared_ptr< thread< Ret > > self_ref_;
};

/**
 * This is a reusable thread on which multiple tasks can be dispatched.
 * Each task can have its own set of arguments (and types).
 */
class versatile_thread
: public thread< >
{
public:
	versatile_thread( const std::string& name );
	versatile_thread( versatile_thread&& );
	versatile_thread( const versatile_thread& ) = delete;
	~versatile_thread( );

	template< typename Fn, typename... Args >
	void add_task( Fn&& fn, Args&&... args );

private:
	struct pimpl;
	std::unique_ptr< pimpl > pimpl_;
};

template< typename Fn, typename... Args >
std::shared_ptr< thread< Q_RESULT_OF( Fn ) > >
run( std::string name, const queue_ptr& queue, Fn&& fn, Args&&... args )
{
	return thread< Q_RESULT_OF( Fn ) >::construct(
	//return q::make_shared< thread< Q_RESULT_OF( Fn ) > >(
		std::move( name ),
		queue,
		std::forward< Fn >( fn ),
		std::forward< Args >( args )... );
}

} // namespace q

#endif // LIBQ_THREAD_HPP
<|endoftext|>