<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "objectdescription.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtCore/QPointer>
#include <QtGui/QIcon>
#ifndef QT_NO_DBUS
#include <QtDBus/QtDBus>
#endif

QT_BEGIN_NAMESPACE

namespace Phonon
{

class PlatformPlugin;
class FactoryPrivate : public Phonon::Factory::Sender
{
    friend QObject *Factory::backend(bool);
    Q_OBJECT
    public:
        FactoryPrivate();
        ~FactoryPrivate();
        bool createBackend();
        PlatformPlugin *platformPlugin();

        QPointer<QObject> m_backendObject;
        PlatformPlugin *m_platformPlugin;
        bool m_noPlatformPlugin;

        QList<QObject *> objects;
        QList<MediaNodePrivate *> mediaNodePrivateList;

    private Q_SLOTS:
        /**
         * This is called via DBUS when the user changes the Phonon Backend.
         */
        void phononBackendChanged();

        /**
         * unregisters the backend object
         */
        void objectDestroyed(QObject *);

        void objectDescriptionChanged(ObjectDescriptionType);
};

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::setBackend(QObject *b)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    globalFactory->m_backendObject = b;
}

/*void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}*/

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default
        // (finding the first loadable backend).
        const QLatin1String suffix("/phonon_backend/");
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  load failed:"
                             << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }

                // no backend found, don't leave an unused plugin in memory
                pluginLoader.unload();
            }

            if (m_backendObject) {
                break;
            }
        }
        if (!m_backendObject) {
            pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (m_platformPlugin) {
        return m_platformPlugin;
    }
    if (m_noPlatformPlugin) {
        return 0;
    }
#ifndef QT_NO_DBUS
    if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
        pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
    }
#endif
    const QString suffix(QLatin1String("/phonon_platform/"));
    Q_ASSERT(QCoreApplication::instance());
    foreach (QString libPath, QCoreApplication::libraryPaths()) {
        libPath += suffix;
        const QDir dir(libPath);
        if (!dir.exists()) {
            pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
            continue;
        }
        foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
            QPluginLoader pluginLoader(libPath + pluginName);
            if (!pluginLoader.load()) {
                pDebug() << Q_FUNC_INFO << "  platform plugin load failed:"
                    << pluginLoader.errorString();
                continue;
            }
            pDebug() << pluginLoader.instance();
            QObject *qobj = pluginLoader.instance();
            m_platformPlugin = qobject_cast<PlatformPlugin *>(qobj);
            pDebug() << m_platformPlugin;
            if (m_platformPlugin) {
                connect(qobj, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
                        SLOT(objectDescriptionChanged(ObjectDescriptionType)));
                return m_platformPlugin;
            } else {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the platform plugin was not loadable:" << pluginLoader.errorString();
                pluginLoader.unload();
            }
        }
    }
    pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
    m_noPlatformPlugin = true;
    return 0;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (globalFactory.isDestroyed()) {
        return 0;
    }
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

QT_END_NAMESPACE

#include "factory.moc"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<commit_msg>make it stop playback a bit faster on shutdown. Especially with streams and the xine backend there was a quite noticable delay<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "mediaobject.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "objectdescription.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtCore/QPointer>
#include <QtGui/QIcon>
#ifndef QT_NO_DBUS
#include <QtDBus/QtDBus>
#endif

QT_BEGIN_NAMESPACE

namespace Phonon
{

class PlatformPlugin;
class FactoryPrivate : public Phonon::Factory::Sender
{
    friend QObject *Factory::backend(bool);
    Q_OBJECT
    public:
        FactoryPrivate();
        ~FactoryPrivate();
        bool createBackend();
        PlatformPlugin *platformPlugin();

        QPointer<QObject> m_backendObject;
        PlatformPlugin *m_platformPlugin;
        bool m_noPlatformPlugin;

        QList<QObject *> objects;
        QList<MediaNodePrivate *> mediaNodePrivateList;

    private Q_SLOTS:
        /**
         * This is called via DBUS when the user changes the Phonon Backend.
         */
        void phononBackendChanged();

        /**
         * unregisters the backend object
         */
        void objectDestroyed(QObject *);

        void objectDescriptionChanged(ObjectDescriptionType);
};

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::setBackend(QObject *b)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    globalFactory->m_backendObject = b;
}

/*void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}*/

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default
        // (finding the first loadable backend).
        const QLatin1String suffix("/phonon_backend/");
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  load failed:"
                             << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }

                // no backend found, don't leave an unused plugin in memory
                pluginLoader.unload();
            }

            if (m_backendObject) {
                break;
            }
        }
        if (!m_backendObject) {
            pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (QObject *o, objects) {
        MediaObject *m = qobject_cast<MediaObject *>(o);
        if (m) {
            m->stop();
        }
    }
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (m_platformPlugin) {
        return m_platformPlugin;
    }
    if (m_noPlatformPlugin) {
        return 0;
    }
#ifndef QT_NO_DBUS
    if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
        pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
    }
#endif
    const QString suffix(QLatin1String("/phonon_platform/"));
    Q_ASSERT(QCoreApplication::instance());
    foreach (QString libPath, QCoreApplication::libraryPaths()) {
        libPath += suffix;
        const QDir dir(libPath);
        if (!dir.exists()) {
            pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
            continue;
        }
        foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
            QPluginLoader pluginLoader(libPath + pluginName);
            if (!pluginLoader.load()) {
                pDebug() << Q_FUNC_INFO << "  platform plugin load failed:"
                    << pluginLoader.errorString();
                continue;
            }
            pDebug() << pluginLoader.instance();
            QObject *qobj = pluginLoader.instance();
            m_platformPlugin = qobject_cast<PlatformPlugin *>(qobj);
            pDebug() << m_platformPlugin;
            if (m_platformPlugin) {
                connect(qobj, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
                        SLOT(objectDescriptionChanged(ObjectDescriptionType)));
                return m_platformPlugin;
            } else {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the platform plugin was not loadable:" << pluginLoader.errorString();
                pluginLoader.unload();
            }
        }
    }
    pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
    m_noPlatformPlugin = true;
    return 0;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (globalFactory.isDestroyed()) {
        return 0;
    }
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

QT_END_NAMESPACE

#include "factory.moc"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void array_for_matrix(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
  typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  ColVectorType cv1 = ColVectorType::Random(rows);
  RowVectorType rv1 = RowVectorType::Random(cols);

  Scalar  s1 = internal::random<Scalar>(),
          s2 = internal::random<Scalar>();

  // scalar addition
  VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
  VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows,cols,s1) + m1);
  VERIFY_IS_APPROX(((m1*Scalar(2)).array() - s2).matrix(), (m1+m1) - MatrixType::Constant(rows,cols,s2) );
  m3 = m1;
  m3.array() += s2;
  VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
  m3 = m1;
  m3.array() -= s1;
  VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());

  // reductions
  VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
  VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
  if (!internal::isApprox(m1.sum(), (m1+m2).sum()))
    VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
  VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));

  // vector-wise ops
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);

  // empty objects
  VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(),  RowVectorType::Zero(cols));
  VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));
}

template<typename MatrixType> void comparisons(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  Index r = internal::random<Index>(0, rows-1),
        c = internal::random<Index>(0, cols-1);

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
  VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
  if (rows*cols>1)
  {
    m3 = m1;
    m3(r,c) += 1;
    VERIFY(! (m1.array() < m3.array()).all() );
    VERIFY(! (m1.array() > m3.array()).all() );
  }

  // comparisons to scalar
  VERIFY( (m1.array() != (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() > (m1(r,c)-1) ).any() );
  VERIFY( (m1.array() < (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() == m1(r,c) ).any() );

  // test Select
  VERIFY_IS_APPROX( (m1.array()<m2.array()).select(m1,m2), m1.cwiseMin(m2) );
  VERIFY_IS_APPROX( (m1.array()>m2.array()).select(m1,m2), m1.cwiseMax(m2) );
  Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
  for (int j=0; j<cols; ++j)
  for (int i=0; i<rows; ++i)
    m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(MatrixType::Zero(rows,cols),m1), m3);
  // shorter versions:
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(0,m1), m3);
  VERIFY_IS_APPROX( (m1.array().abs()>=MatrixType::Constant(rows,cols,mid).array())
                        .select(m1,0), m3);
  // even shorter version:
  VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);

  // count
  VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);

  typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;

  // TODO allows colwise/rowwise for array
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
}

template<typename VectorType> void lpNorm(const VectorType& v)
{
  VectorType u = VectorType::Random(v.size());

  VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
  VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
  VERIFY_IS_APPROX(u.template lpNorm<2>(), internal::sqrt(u.array().abs().square().sum()));
  VERIFY_IS_APPROX(internal::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum());
}

void test_array_for_matrix()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( array_for_matrix(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( array_for_matrix(Matrix2f()) );
    CALL_SUBTEST_3( array_for_matrix(Matrix4d()) );
    CALL_SUBTEST_4( array_for_matrix(MatrixXcf(3, 3)) );
    CALL_SUBTEST_5( array_for_matrix(MatrixXf(8, 12)) );
    CALL_SUBTEST_6( array_for_matrix(MatrixXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( comparisons(Matrix2f()) );
    CALL_SUBTEST_3( comparisons(Matrix4d()) );
    CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) );
    CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( lpNorm(Vector2f()) );
    CALL_SUBTEST_7( lpNorm(Vector3d()) );
    CALL_SUBTEST_8( lpNorm(Vector4f()) );
    CALL_SUBTEST_5( lpNorm(VectorXf(16)) );
    CALL_SUBTEST_4( lpNorm(VectorXcf(10)) );
  }
}
<commit_msg>Added regression tests for bug #148.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void array_for_matrix(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> ColVectorType;
  typedef Matrix<Scalar, 1, MatrixType::ColsAtCompileTime> RowVectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  ColVectorType cv1 = ColVectorType::Random(rows);
  RowVectorType rv1 = RowVectorType::Random(cols);

  Scalar  s1 = internal::random<Scalar>(),
          s2 = internal::random<Scalar>();

  // scalar addition
  VERIFY_IS_APPROX(m1.array() + s1, s1 + m1.array());
  VERIFY_IS_APPROX((m1.array() + s1).matrix(), MatrixType::Constant(rows,cols,s1) + m1);
  VERIFY_IS_APPROX(((m1*Scalar(2)).array() - s2).matrix(), (m1+m1) - MatrixType::Constant(rows,cols,s2) );
  m3 = m1;
  m3.array() += s2;
  VERIFY_IS_APPROX(m3, (m1.array() + s2).matrix());
  m3 = m1;
  m3.array() -= s1;
  VERIFY_IS_APPROX(m3, (m1.array() - s1).matrix());

  // reductions
  VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum());
  VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum());
  if (!internal::isApprox(m1.sum(), (m1+m2).sum()))
    VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum());
  VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op<Scalar>()));

  // vector-wise ops
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() += cv1, m1.colwise() + cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.colwise() -= cv1, m1.colwise() - cv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1);
  m3 = m1;
  VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1);

  // empty objects
  VERIFY_IS_APPROX(m1.block(0,0,0,cols).colwise().sum(),  RowVectorType::Zero(cols));
  VERIFY_IS_APPROX(m1.block(0,0,rows,0).rowwise().prod(), ColVectorType::Ones(rows));

  // verify the const accessors exist
  const Scalar& ref_m1 = m.matrix().array().coeffRef(0);
  const Scalar& ref_m2 = m.matrix().array().coeffRef(0,0);
  const Scalar& ref_a1 = m.array().matrix().coeffRef(0);
  const Scalar& ref_a2 = m.array().matrix().coeffRef(0,0);
  VERIFY(&ref_a1 == &ref_m1);
  VERIFY(&ref_a2 == &ref_m2);
}

template<typename MatrixType> void comparisons(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  Index r = internal::random<Index>(0, rows-1),
        c = internal::random<Index>(0, cols-1);

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols);

  VERIFY(((m1.array() + Scalar(1)) > m1.array()).all());
  VERIFY(((m1.array() - Scalar(1)) < m1.array()).all());
  if (rows*cols>1)
  {
    m3 = m1;
    m3(r,c) += 1;
    VERIFY(! (m1.array() < m3.array()).all() );
    VERIFY(! (m1.array() > m3.array()).all() );
  }

  // comparisons to scalar
  VERIFY( (m1.array() != (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() > (m1(r,c)-1) ).any() );
  VERIFY( (m1.array() < (m1(r,c)+1) ).any() );
  VERIFY( (m1.array() == m1(r,c) ).any() );

  // test Select
  VERIFY_IS_APPROX( (m1.array()<m2.array()).select(m1,m2), m1.cwiseMin(m2) );
  VERIFY_IS_APPROX( (m1.array()>m2.array()).select(m1,m2), m1.cwiseMax(m2) );
  Scalar mid = (m1.cwiseAbs().minCoeff() + m1.cwiseAbs().maxCoeff())/Scalar(2);
  for (int j=0; j<cols; ++j)
  for (int i=0; i<rows; ++i)
    m3(i,j) = internal::abs(m1(i,j))<mid ? 0 : m1(i,j);
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(MatrixType::Zero(rows,cols),m1), m3);
  // shorter versions:
  VERIFY_IS_APPROX( (m1.array().abs()<MatrixType::Constant(rows,cols,mid).array())
                        .select(0,m1), m3);
  VERIFY_IS_APPROX( (m1.array().abs()>=MatrixType::Constant(rows,cols,mid).array())
                        .select(m1,0), m3);
  // even shorter version:
  VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);

  // count
  VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);

  typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;

  // TODO allows colwise/rowwise for array
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
}

template<typename VectorType> void lpNorm(const VectorType& v)
{
  VectorType u = VectorType::Random(v.size());

  VERIFY_IS_APPROX(u.template lpNorm<Infinity>(), u.cwiseAbs().maxCoeff());
  VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum());
  VERIFY_IS_APPROX(u.template lpNorm<2>(), internal::sqrt(u.array().abs().square().sum()));
  VERIFY_IS_APPROX(internal::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum());
}

void test_array_for_matrix()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( array_for_matrix(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( array_for_matrix(Matrix2f()) );
    CALL_SUBTEST_3( array_for_matrix(Matrix4d()) );
    CALL_SUBTEST_4( array_for_matrix(MatrixXcf(3, 3)) );
    CALL_SUBTEST_5( array_for_matrix(MatrixXf(8, 12)) );
    CALL_SUBTEST_6( array_for_matrix(MatrixXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( comparisons(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( comparisons(Matrix2f()) );
    CALL_SUBTEST_3( comparisons(Matrix4d()) );
    CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) );
    CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( lpNorm(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( lpNorm(Vector2f()) );
    CALL_SUBTEST_7( lpNorm(Vector3d()) );
    CALL_SUBTEST_8( lpNorm(Vector4f()) );
    CALL_SUBTEST_5( lpNorm(VectorXf(16)) );
    CALL_SUBTEST_4( lpNorm(VectorXcf(10)) );
  }
}
<|endoftext|>


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

#include "v8.h"
#include "accessors.h"
#include "top.h"

#include "cctest.h"

using namespace v8::internal;

static Object* AllocateAfterFailures() {
  static int attempts = 0;
  if (++attempts < 3) return Failure::RetryAfterGC(0);

  // New space.
  NewSpace* new_space = Heap::new_space();
  static const int kNewSpaceFillerSize = ByteArray::SizeFor(0);
  while (new_space->Available() > kNewSpaceFillerSize) {
    int available_before = new_space->Available();
    CHECK(!Heap::AllocateByteArray(0)->IsFailure());
    if (available_before == new_space->Available()) {
      // It seems that we are avoiding new space allocations when
      // allocation is forced, so no need to fill up new space
      // in order to make the test harder.
      break;
    }
  }
  CHECK(!Heap::AllocateByteArray(100)->IsFailure());
  CHECK(!Heap::AllocateFixedArray(100, NOT_TENURED)->IsFailure());

  // Make sure we can allocate through optimized allocation functions
  // for specific kinds.
  CHECK(!Heap::AllocateFixedArray(100)->IsFailure());
  CHECK(!Heap::AllocateHeapNumber(0.42)->IsFailure());
  CHECK(!Heap::AllocateArgumentsObject(Smi::FromInt(87), 10)->IsFailure());
  Object* object = Heap::AllocateJSObject(*Top::object_function());
  CHECK(!Heap::CopyJSObject(JSObject::cast(object))->IsFailure());

  // Old data space.
  OldSpace* old_data_space = Heap::old_data_space();
  static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0);
  while (old_data_space->Available() > kOldDataSpaceFillerSize) {
    CHECK(!Heap::Heap::AllocateByteArray(0, TENURED)->IsFailure());
  }
  CHECK(!Heap::AllocateRawAsciiString(100, TENURED)->IsFailure());

  // Large object space.
  while (!Heap::OldGenerationAllocationLimitReached()) {
    CHECK(!Heap::AllocateFixedArray(10000, TENURED)->IsFailure());
  }
  CHECK(!Heap::AllocateFixedArray(10000, TENURED)->IsFailure());

  // Map space.
  MapSpace* map_space = Heap::map_space();
  static const int kMapSpaceFillerSize = Map::kSize;
  InstanceType instance_type = JS_OBJECT_TYPE;
  int instance_size = JSObject::kHeaderSize;
  while (map_space->Available() > kMapSpaceFillerSize) {
    CHECK(!Heap::AllocateMap(instance_type, instance_size)->IsFailure());
  }
  CHECK(!Heap::AllocateMap(instance_type, instance_size)->IsFailure());

  // Test that we can allocate in old pointer space and code space.
  CHECK(!Heap::AllocateFixedArray(100, TENURED)->IsFailure());
  CHECK(!Heap::CopyCode(Builtins::builtin(Builtins::Illegal))->IsFailure());

  // Return success.
  return Smi::FromInt(42);
}

static Handle<Object> Test() {
  CALL_HEAP_FUNCTION(AllocateAfterFailures(), Object);
}

TEST(StressHandles) {
  v8::Persistent<v8::Context> env = v8::Context::New();
  v8::HandleScope scope;
  env->Enter();
  Handle<Object> o = Test();
  CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
  env->Exit();
}

static Object* TestAccessorGet(Object* object, void*) {
  return AllocateAfterFailures();
}

const AccessorDescriptor kDescriptor = {
  TestAccessorGet,
  0,
  0
};

TEST(StressJS) {
  v8::Persistent<v8::Context> env = v8::Context::New();
  v8::HandleScope scope;
  env->Enter();
  Handle<JSFunction> function =
      Factory::NewFunction(Factory::function_symbol(), Factory::null_value());
  // Force the creation of an initial map and set the code to
  // something empty.
  Factory::NewJSObject(function);
  function->set_code(Builtins::builtin(Builtins::EmptyFunction));
  // Patch the map to have an accessor for "get".
  Handle<Map> map(function->initial_map());
  Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
  Handle<Proxy> proxy = Factory::NewProxy(&kDescriptor);
  instance_descriptors = Factory::CopyAppendProxyDescriptor(
      instance_descriptors,
      Factory::NewStringFromAscii(Vector<const char>("get", 3)),
      proxy,
      static_cast<PropertyAttributes>(0));
  map->set_instance_descriptors(*instance_descriptors);
  // Add the Foo constructor the global object.
  env->Global()->Set(v8::String::New("Foo"), v8::Utils::ToLocal(function));
  // Call the accessor through JavaScript.
  v8::Handle<v8::Value> result =
      v8::Script::Compile(v8::String::New("(new Foo).get"))->Run();
  CHECK_EQ(42, result->Int32Value());
  env->Exit();
}

// CodeRange test.
// Tests memory management in a CodeRange by allocating and freeing blocks,
// using a pseudorandom generator to choose block sizes geometrically
// distributed between 2 * Page::kPageSize and 2^5 + 1 * Page::kPageSize.
// Ensure that the freed chunks are collected and reused by allocating (in
// total) more than the size of the CodeRange.

// This pseudorandom generator does not need to be particularly good.
// Use the lower half of the V8::Random() generator.
unsigned int Pseudorandom() {
  static uint32_t lo = 2345;
  lo = 18273 * (lo & 0xFFFF) + (lo >> 16);  // Provably not 0.
  return lo & 0xFFFF;
}

// Plain old data class.  Represents a block of allocated memory.
class Block {
 public:
  Block(void* base_arg, int size_arg)
      : base(base_arg), size(size_arg) {}

  void *base;
  int size;
};

TEST(CodeRange) {
  const int code_range_size = 16*MB;
  CodeRange::Setup(code_range_size);
  int current_allocated = 0;
  int total_allocated = 0;
  List<Block> blocks(1000);

  while (total_allocated < 5 * code_range_size) {
    if (current_allocated < code_range_size / 10) {
      // Allocate a block.
      // Geometrically distributed sizes, greater than Page::kPageSize.
      size_t requested = (Page::kPageSize << (Pseudorandom() % 6)) +
           Pseudorandom() % 5000 + 1;
      size_t allocated = 0;
      void* base = CodeRange::AllocateRawMemory(requested, &allocated);
      blocks.Add(Block(base, static_cast<int>(allocated)));
      current_allocated += static_cast<int>(allocated);
      total_allocated += static_cast<int>(allocated);
    } else {
      // Free a block.
      int index = Pseudorandom() % blocks.length();
      CodeRange::FreeRawMemory(blocks[index].base, blocks[index].size);
      current_allocated -= blocks[index].size;
      if (index < blocks.length() - 1) {
        blocks[index] = blocks.RemoveLast();
      } else {
        blocks.RemoveLast();
      }
    }
  }

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

#include "v8.h"
#include "accessors.h"
#include "top.h"

#include "cctest.h"

using namespace v8::internal;

static Object* AllocateAfterFailures() {
  static int attempts = 0;
  if (++attempts < 3) return Failure::RetryAfterGC(0);

  // New space.
  NewSpace* new_space = Heap::new_space();
  static const int kNewSpaceFillerSize = ByteArray::SizeFor(0);
  while (new_space->Available() > kNewSpaceFillerSize) {
    int available_before = new_space->Available();
    CHECK(!Heap::AllocateByteArray(0)->IsFailure());
    if (available_before == new_space->Available()) {
      // It seems that we are avoiding new space allocations when
      // allocation is forced, so no need to fill up new space
      // in order to make the test harder.
      break;
    }
  }
  CHECK(!Heap::AllocateByteArray(100)->IsFailure());
  CHECK(!Heap::AllocateFixedArray(100, NOT_TENURED)->IsFailure());

  // Make sure we can allocate through optimized allocation functions
  // for specific kinds.
  CHECK(!Heap::AllocateFixedArray(100)->IsFailure());
  CHECK(!Heap::AllocateHeapNumber(0.42)->IsFailure());
  CHECK(!Heap::AllocateArgumentsObject(Smi::FromInt(87), 10)->IsFailure());
  Object* object = Heap::AllocateJSObject(*Top::object_function());
  CHECK(!Heap::CopyJSObject(JSObject::cast(object))->IsFailure());

  // Old data space.
  OldSpace* old_data_space = Heap::old_data_space();
  static const int kOldDataSpaceFillerSize = ByteArray::SizeFor(0);
  while (old_data_space->Available() > kOldDataSpaceFillerSize) {
    CHECK(!Heap::AllocateByteArray(0, TENURED)->IsFailure());
  }
  CHECK(!Heap::AllocateRawAsciiString(100, TENURED)->IsFailure());

  // Large object space.
  while (!Heap::OldGenerationAllocationLimitReached()) {
    CHECK(!Heap::AllocateFixedArray(10000, TENURED)->IsFailure());
  }
  CHECK(!Heap::AllocateFixedArray(10000, TENURED)->IsFailure());

  // Map space.
  MapSpace* map_space = Heap::map_space();
  static const int kMapSpaceFillerSize = Map::kSize;
  InstanceType instance_type = JS_OBJECT_TYPE;
  int instance_size = JSObject::kHeaderSize;
  while (map_space->Available() > kMapSpaceFillerSize) {
    CHECK(!Heap::AllocateMap(instance_type, instance_size)->IsFailure());
  }
  CHECK(!Heap::AllocateMap(instance_type, instance_size)->IsFailure());

  // Test that we can allocate in old pointer space and code space.
  CHECK(!Heap::AllocateFixedArray(100, TENURED)->IsFailure());
  CHECK(!Heap::CopyCode(Builtins::builtin(Builtins::Illegal))->IsFailure());

  // Return success.
  return Smi::FromInt(42);
}

static Handle<Object> Test() {
  CALL_HEAP_FUNCTION(AllocateAfterFailures(), Object);
}

TEST(StressHandles) {
  v8::Persistent<v8::Context> env = v8::Context::New();
  v8::HandleScope scope;
  env->Enter();
  Handle<Object> o = Test();
  CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
  env->Exit();
}

static Object* TestAccessorGet(Object* object, void*) {
  return AllocateAfterFailures();
}

const AccessorDescriptor kDescriptor = {
  TestAccessorGet,
  0,
  0
};

TEST(StressJS) {
  v8::Persistent<v8::Context> env = v8::Context::New();
  v8::HandleScope scope;
  env->Enter();
  Handle<JSFunction> function =
      Factory::NewFunction(Factory::function_symbol(), Factory::null_value());
  // Force the creation of an initial map and set the code to
  // something empty.
  Factory::NewJSObject(function);
  function->set_code(Builtins::builtin(Builtins::EmptyFunction));
  // Patch the map to have an accessor for "get".
  Handle<Map> map(function->initial_map());
  Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
  Handle<Proxy> proxy = Factory::NewProxy(&kDescriptor);
  instance_descriptors = Factory::CopyAppendProxyDescriptor(
      instance_descriptors,
      Factory::NewStringFromAscii(Vector<const char>("get", 3)),
      proxy,
      static_cast<PropertyAttributes>(0));
  map->set_instance_descriptors(*instance_descriptors);
  // Add the Foo constructor the global object.
  env->Global()->Set(v8::String::New("Foo"), v8::Utils::ToLocal(function));
  // Call the accessor through JavaScript.
  v8::Handle<v8::Value> result =
      v8::Script::Compile(v8::String::New("(new Foo).get"))->Run();
  CHECK_EQ(42, result->Int32Value());
  env->Exit();
}

// CodeRange test.
// Tests memory management in a CodeRange by allocating and freeing blocks,
// using a pseudorandom generator to choose block sizes geometrically
// distributed between 2 * Page::kPageSize and 2^5 + 1 * Page::kPageSize.
// Ensure that the freed chunks are collected and reused by allocating (in
// total) more than the size of the CodeRange.

// This pseudorandom generator does not need to be particularly good.
// Use the lower half of the V8::Random() generator.
unsigned int Pseudorandom() {
  static uint32_t lo = 2345;
  lo = 18273 * (lo & 0xFFFF) + (lo >> 16);  // Provably not 0.
  return lo & 0xFFFF;
}

// Plain old data class.  Represents a block of allocated memory.
class Block {
 public:
  Block(void* base_arg, int size_arg)
      : base(base_arg), size(size_arg) {}

  void *base;
  int size;
};

TEST(CodeRange) {
  const int code_range_size = 16*MB;
  CodeRange::Setup(code_range_size);
  int current_allocated = 0;
  int total_allocated = 0;
  List<Block> blocks(1000);

  while (total_allocated < 5 * code_range_size) {
    if (current_allocated < code_range_size / 10) {
      // Allocate a block.
      // Geometrically distributed sizes, greater than Page::kPageSize.
      size_t requested = (Page::kPageSize << (Pseudorandom() % 6)) +
           Pseudorandom() % 5000 + 1;
      size_t allocated = 0;
      void* base = CodeRange::AllocateRawMemory(requested, &allocated);
      blocks.Add(Block(base, static_cast<int>(allocated)));
      current_allocated += static_cast<int>(allocated);
      total_allocated += static_cast<int>(allocated);
    } else {
      // Free a block.
      int index = Pseudorandom() % blocks.length();
      CodeRange::FreeRawMemory(blocks[index].base, blocks[index].size);
      current_allocated -= blocks[index].size;
      if (index < blocks.length() - 1) {
        blocks[index] = blocks.RemoveLast();
      } else {
        blocks.RemoveLast();
      }
    }
  }

  CodeRange::TearDown();
}
<|endoftext|>


<commit_before>/*
promising:
http://elinux.org/Interfacing_with_I2C_Devices
https://i2c.wiki.kernel.org/index.php/Main_Page
*/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "LSM303.h"
#include "L3G4200D.h"

int main(int argc, char *argv[])
{
    I2CBus i2c("/dev/i2c-0");
    LSM303 compass(i2c);
    L3G4200D gyro(i2c);

    uint8_t result = compass.readMagReg(LSM303_WHO_AM_I_M);
    if (result != 0x3C)
    {
        std::cerr << "Error getting \"Who Am I\" register." << std::endl;
        exit(2);
    }

    compass.enableDefault();
    gyro.enableDefault();

    while(1)
    {
        compass.read();
        gyro.read();
        printf("%7d %7d %7d,  %7d %7d %7d,  %7d %7d %7d\n",
               compass.m(0), compass.m(1), compass.m(2),
               compass.a(0), compass.a(1), compass.a(2),
               gyro.g(0), gyro.g(1), gyro.g(2)
        );
        usleep(100*1000);
    }

    return 0;
}
<commit_msg>Added a calibration feature that just prints out the running mins and maxes.<commit_after>/*
promising:
http://elinux.org/Interfacing_with_I2C_Devices
https://i2c.wiki.kernel.org/index.php/Main_Page
*/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "LSM303.h"
#include "L3G4200D.h"

void streamRawValues(LSM303& compass, L3G4200D& gyro)
{
    compass.enableDefault();
    gyro.enableDefault();

    while(1)
    {
        compass.read();
        gyro.read();
        printf("%7d %7d %7d,  %7d %7d %7d,  %7d %7d %7d\n",
               compass.m(0), compass.m(1), compass.m(2),
               compass.a(0), compass.a(1), compass.a(2),
               gyro.g(0), gyro.g(1), gyro.g(2)
        );
        usleep(100*1000);
    }
}

void calibrate(LSM303& compass)
{
    compass.enableDefault();
    int_vector mag_max(0,0,0), mag_min(0,0,0);
    while(1)
    {
        compass.read();
        mag_min = mag_min.cwiseMin(compass.m);
        mag_max = mag_max.cwiseMax(compass.m);
        printf("%7d %7d %7d  %7d %7d %7d\n",
               mag_min(0), mag_min(1), mag_min(2),
               mag_max(0), mag_max(1), mag_max(2));
        usleep(10*1000);
    }
}

int main(int argc, char *argv[])
{
    I2CBus i2c("/dev/i2c-0");
    LSM303 compass(i2c);
    L3G4200D gyro(i2c);

    uint8_t result = compass.readMagReg(LSM303_WHO_AM_I_M);
    if (result != 0x3C)
    {
        std::cerr << "Error getting \"Who Am I\" register." << std::endl;
        exit(2);
    }

    if (argc > 1)
    {
        if (0 == strcmp("cal", argv[1]))
        {
            calibrate(compass);
        }
    }

    streamRawValues(compass, gyro);

    return 0;
}
<|endoftext|>


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

#include "ParallelPrimeSieve.h"
#include "PrimeSieve.h"
#include "PrimeNumberFinder.h"
#include "defs.h"
#include "imath.h"

#if defined(_OPENMP)
  #include <omp.h>
#endif

#include <cstdlib>
#include <stdexcept>
#include <algorithm>

ParallelPrimeSieve::ParallelPrimeSieve() :
  numThreads_(USE_IDEAL_NUM_THREADS), shm_(NULL) {
  // prevents prime k-tuplet gaps
  static_assert(defs::MIN_THREAD_INTERVAL < 100, "defs::MIN_THREAD_INTERVAL >= 100");
}

int ParallelPrimeSieve::getMaxThreads() {
#if defined(_OPENMP)
  return omp_get_max_threads();
#else
  return 1;
#endif
}

/**
 * Get the current set number of threads for sieving.
 */
int ParallelPrimeSieve::getNumThreads() const {
  return (numThreads_ == USE_IDEAL_NUM_THREADS)
      ? this->getIdealNumThreads()
      : numThreads_;
}

/**
 * Set the number of threads for sieving.
 * If numThreads is invalid (numThreads < 1 or > getMaxThreads()) it
 * is set to numThreads = USE_IDEAL_NUM_THREADS.
 */
void ParallelPrimeSieve::setNumThreads(int numThreads) {
  numThreads_ = (numThreads >= 1 && numThreads <= this->getMaxThreads())
      ? numThreads
      : USE_IDEAL_NUM_THREADS;
}

uint64_t ParallelPrimeSieve::getSieveInterval() const {
  return stopNumber_ - startNumber_;
}

/**
 * Get an ideal number of threads for the current set startNumber_,
 * stopNumber_ and flags_.
 */
int ParallelPrimeSieve::getIdealNumThreads() const {
  // 1 thread to print primes in sequential order
  if (flags_ & PRINT_FLAGS)
    return 1;
  // each thread should at least sieve an interval of size n^0.5/6 and
  // not smaller than defs::MIN_THREAD_INTERVAL
  uint64_t threadThreshold = std::max<uint64_t>(
      defs::MIN_THREAD_INTERVAL,
      isqrt(stopNumber_) / 6);
  // set to maxThreads if the sieve interval is sufficiently large
  int idealNumThreads = static_cast<int> (
      std::min<uint64_t>(
          this->getSieveInterval() / threadThreshold,
          this->getMaxThreads()));

  return std::max<int>(1, idealNumThreads);
}

/**
 * Get an interval size that ensures a good load balance among
 * threads whilst sieving.
 */
uint64_t ParallelPrimeSieve::getIdealInterval() const {
  int numThreads = this->getNumThreads();
  if (numThreads == 1)
    return this->getSieveInterval();

  // idealInterval = n^0.5*2000, 0.1 percent initialization
  uint64_t idealInterval = std::max<uint64_t>(
      defs::MIN_THREAD_INTERVAL,
      static_cast<uint64_t> (isqrt(stopNumber_)) * 2000);
  // maximum interval size per thread
  uint64_t maxThreadInterval = this->getSieveInterval() / numThreads;
  // correct the user's bad settings
  if (maxThreadInterval < this->getSieveInterval() &&
      maxThreadInterval < defs::MIN_THREAD_INTERVAL) {
    maxThreadInterval = this->getSieveInterval() / this->getIdealNumThreads();
  }
  return std::min<uint64_t>(idealInterval, maxThreadInterval);
}

/**
 * For use with the Qt primesieve application in ../qt-gui.
 * Initializes this ParallelPrimeSieve object with values from a
 * shared memory segment.
 */
void ParallelPrimeSieve::init(SharedMemory* shm) {
  if (shm == NULL)
    throw std::invalid_argument(
        "ParallelPrimeSieve: shared memory segment must not be NULL");
  shm_ = shm;
  this->setStartNumber(shm_->startNumber);
  this->setStopNumber(shm_->stopNumber);
  this->setSieveSize(shm_->sieveSize);
  this->setFlags(shm_->flags);
  this->setNumThreads(shm_->threads);
}

/**
 * Calculate the current status in percent of sieve().
 * @param processed The size of the processed interval (segment)
 */
void ParallelPrimeSieve::doStatus(uint32_t processed) {
#if defined(_OPENMP)
  #pragma omp critical (doStatus)
#endif
  {
    PrimeSieve::doStatus(processed);
    // communicate the current status via shared memory
    // to the Qt GUI process
    if (shm_ != NULL)
      shm_->status = status_;
  }
}

/**
 * Sieve the primes/prime k-tuplets within [startNumber_, stopNumber_]
 * in parallel using OpenMP.
 */
void ParallelPrimeSieve::sieve() {
  if (stopNumber_ < startNumber_)
    throw std::invalid_argument("STOP must be >= START");

#if defined(_OPENMP)
  double t1 = omp_get_wtime();
  this->reset();
  uint64_t idealInterval = this->getIdealInterval();
  uint64_t chunks = (idealInterval == 0)
      ? 1 : this->getSieveInterval() / idealInterval;
  uint64_t maxOffset = chunks * idealInterval;
  uint64_t maxStop = startNumber_ + maxOffset + 32 - maxOffset % 30;
  if (maxStop < stopNumber_)
    chunks++;
  int numThreads = this->getNumThreads();

  // the sieve interval [startNumber_, stopNumber_] is split into
  // numerous sub-intervals that are processed in parallel
  #pragma omp parallel for num_threads(numThreads) schedule(dynamic)
  for (int64_t i = 0; i < static_cast<int64_t> (chunks); i++) {
    uint64_t start = startNumber_ + idealInterval * i;
    uint64_t stop = startNumber_ + idealInterval * (i+1);
    // start/stop numbers must be chosen carefully for PrimeSieve
    // objects to prevent prime k-tuplets gaps
    if (i > 0)
      start += 32 - start % 30;
    stop += 32 - stop % 30;
    // sieve the primes within [start, stop]
    PrimeSieve ps(start, std::min<uint64_t>(stop, stopNumber_), this);
    ps.sieve();
    #pragma omp critical (counts)
    for (uint32_t j = 0; j < COUNTS_SIZE; j++)
      counts_[j] += ps.getCounts(j);
  }
  timeElapsed_ = omp_get_wtime() - t1;
#else
  PrimeSieve::sieve();
#endif
  // communicate the sieving results via shared memory
  // segment to the Qt GUI process
  if (shm_ != NULL) {
    for (uint32_t i = 0; i < COUNTS_SIZE; i++)
      shm_->counts[i] = counts_[i];
    shm_->timeElapsed = timeElapsed_;
  }
}
<commit_msg>fixed static_assert<commit_after>//
// Copyright (c) 2011 Kim Walisch, <kim.walisch@gmail.com>.
// All rights reserved.
//
// This file is part of primesieve.
// Visit: http://primesieve.googlecode.com
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//   * Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above
//     copyright notice, this list of conditions and the following
//     disclaimer in the documentation and/or other materials provided
//     with the distribution.
//   * Neither the name of the author nor the names of its
//     contributors may be used to endorse or promote products derived
//     from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

#include "ParallelPrimeSieve.h"
#include "PrimeSieve.h"
#include "PrimeNumberFinder.h"
#include "defs.h"
#include "imath.h"

#if defined(_OPENMP)
  #include <omp.h>
#endif

#include <cstdlib>
#include <stdexcept>
#include <algorithm>

ParallelPrimeSieve::ParallelPrimeSieve() :
  numThreads_(USE_IDEAL_NUM_THREADS), shm_(NULL) {
  // prevents prime k-tuplet gaps
  static_assert(defs::MIN_THREAD_INTERVAL >= 100,
               "defs::MIN_THREAD_INTERVAL >= 100");
}

int ParallelPrimeSieve::getMaxThreads() {
#if defined(_OPENMP)
  return omp_get_max_threads();
#else
  return 1;
#endif
}

/**
 * Get the current set number of threads for sieving.
 */
int ParallelPrimeSieve::getNumThreads() const {
  return (numThreads_ == USE_IDEAL_NUM_THREADS)
      ? this->getIdealNumThreads()
      : numThreads_;
}

/**
 * Set the number of threads for sieving.
 * If numThreads is invalid (numThreads < 1 or > getMaxThreads()) it
 * is set to numThreads = USE_IDEAL_NUM_THREADS.
 */
void ParallelPrimeSieve::setNumThreads(int numThreads) {
  numThreads_ = (numThreads >= 1 && numThreads <= this->getMaxThreads())
      ? numThreads
      : USE_IDEAL_NUM_THREADS;
}

uint64_t ParallelPrimeSieve::getSieveInterval() const {
  return stopNumber_ - startNumber_;
}

/**
 * Get an ideal number of threads for the current set startNumber_,
 * stopNumber_ and flags_.
 */
int ParallelPrimeSieve::getIdealNumThreads() const {
  // 1 thread to print primes in sequential order
  if (flags_ & PRINT_FLAGS)
    return 1;
  // each thread should at least sieve an interval of size n^0.5/6 and
  // not smaller than defs::MIN_THREAD_INTERVAL
  uint64_t threadThreshold = std::max<uint64_t>(
      defs::MIN_THREAD_INTERVAL,
      isqrt(stopNumber_) / 6);
  // set to maxThreads if the sieve interval is sufficiently large
  int idealNumThreads = static_cast<int> (
      std::min<uint64_t>(
          this->getSieveInterval() / threadThreshold,
          this->getMaxThreads()));

  return std::max<int>(1, idealNumThreads);
}

/**
 * Get an interval size that ensures a good load balance among
 * threads whilst sieving.
 */
uint64_t ParallelPrimeSieve::getIdealInterval() const {
  int numThreads = this->getNumThreads();
  if (numThreads == 1)
    return this->getSieveInterval();

  // idealInterval = n^0.5*2000, 0.1 percent initialization
  uint64_t idealInterval = std::max<uint64_t>(
      defs::MIN_THREAD_INTERVAL,
      static_cast<uint64_t> (isqrt(stopNumber_)) * 2000);
  // maximum interval size per thread
  uint64_t maxThreadInterval = this->getSieveInterval() / numThreads;
  // correct the user's bad settings
  if (maxThreadInterval < this->getSieveInterval() &&
      maxThreadInterval < defs::MIN_THREAD_INTERVAL) {
    maxThreadInterval = this->getSieveInterval() / this->getIdealNumThreads();
  }
  return std::min<uint64_t>(idealInterval, maxThreadInterval);
}

/**
 * For use with the Qt primesieve application in ../qt-gui.
 * Initializes this ParallelPrimeSieve object with values from a
 * shared memory segment.
 */
void ParallelPrimeSieve::init(SharedMemory* shm) {
  if (shm == NULL)
    throw std::invalid_argument(
        "ParallelPrimeSieve: shared memory segment must not be NULL");
  shm_ = shm;
  this->setStartNumber(shm_->startNumber);
  this->setStopNumber(shm_->stopNumber);
  this->setSieveSize(shm_->sieveSize);
  this->setFlags(shm_->flags);
  this->setNumThreads(shm_->threads);
}

/**
 * Calculate the current status in percent of sieve().
 * @param processed The size of the processed interval (segment)
 */
void ParallelPrimeSieve::doStatus(uint32_t processed) {
#if defined(_OPENMP)
  #pragma omp critical (doStatus)
#endif
  {
    PrimeSieve::doStatus(processed);
    // communicate the current status via shared memory
    // to the Qt GUI process
    if (shm_ != NULL)
      shm_->status = status_;
  }
}

/**
 * Sieve the primes/prime k-tuplets within [startNumber_, stopNumber_]
 * in parallel using OpenMP.
 */
void ParallelPrimeSieve::sieve() {
  if (stopNumber_ < startNumber_)
    throw std::invalid_argument("STOP must be >= START");

#if defined(_OPENMP)
  double t1 = omp_get_wtime();
  this->reset();
  uint64_t idealInterval = this->getIdealInterval();
  uint64_t chunks = (idealInterval == 0)
      ? 1 : this->getSieveInterval() / idealInterval;
  uint64_t maxOffset = chunks * idealInterval;
  uint64_t maxStop = startNumber_ + maxOffset + 32 - maxOffset % 30;
  if (maxStop < stopNumber_)
    chunks++;
  int numThreads = this->getNumThreads();

  // the sieve interval [startNumber_, stopNumber_] is split into
  // numerous sub-intervals that are processed in parallel
  #pragma omp parallel for num_threads(numThreads) schedule(dynamic)
  for (int64_t i = 0; i < static_cast<int64_t> (chunks); i++) {
    uint64_t start = startNumber_ + idealInterval * i;
    uint64_t stop = startNumber_ + idealInterval * (i+1);
    // start/stop numbers must be chosen carefully for PrimeSieve
    // objects to prevent prime k-tuplets gaps
    if (i > 0)
      start += 32 - start % 30;
    stop += 32 - stop % 30;
    // sieve the primes within [start, stop]
    PrimeSieve ps(start, std::min<uint64_t>(stop, stopNumber_), this);
    ps.sieve();
    #pragma omp critical (counts)
    for (uint32_t j = 0; j < COUNTS_SIZE; j++)
      counts_[j] += ps.getCounts(j);
  }
  timeElapsed_ = omp_get_wtime() - t1;
#else
  PrimeSieve::sieve();
#endif
  // communicate the sieving results via shared memory
  // segment to the Qt GUI process
  if (shm_ != NULL) {
    for (uint32_t i = 0; i < COUNTS_SIZE; i++)
      shm_->counts[i] = counts_[i];
    shm_->timeElapsed = timeElapsed_;
  }
}
<|endoftext|>


<commit_before>#include "vector.h"
#include "MinIMU9.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <system_error>

// TODO: print warning if accelerometer magnitude is not close to 1 when starting up

int millis()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (tv.tv_sec) * 1000 + (tv.tv_usec)/1000;
}

void print(matrix m)
{
    printf("%7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f",
           m(0,0), m(0,1), m(0,2),
           m(1,0), m(1,1), m(1,2),
           m(2,0), m(2,1), m(2,2));
}

void streamRawValues(IMU& imu)
{
    imu.enable();
    while(1)
    {
        imu.read();
        printf("%7d %7d %7d  %7d %7d %7d  %7d %7d %7d\n",
               imu.raw_m[0], imu.raw_m[1], imu.raw_m[2],
               imu.raw_a[0], imu.raw_a[1], imu.raw_a[2],
               imu.raw_g[0], imu.raw_g[1], imu.raw_g[2]
        );
        usleep(20*1000);
    }
}

matrix rotationFromCompass(const vector& acceleration, const vector& magnetic_field)
{
    vector up = acceleration;     // usually true
    vector magnetic_east = magnetic_field.cross(up);
    vector east = magnetic_east;  // a rough approximation
    vector north = up.cross(east);

    matrix rotationFromCompass;
    rotationFromCompass.row(0) = east;
    rotationFromCompass.row(1) = north;
    rotationFromCompass.row(2) = up;
    rotationFromCompass.row(0).normalize();
    rotationFromCompass.row(1).normalize();
    rotationFromCompass.row(2).normalize();

    return rotationFromCompass;
}

float heading(matrix rotation)
{
    // The board's x axis in earth coordinates.
    vector x = rotation.col(0);
    x.normalize();
    x(2) = 0;
    //float heading_weight = x.norm();

    // 0 = east, pi/2 = north
    return atan2(x(1), x(0));
}

typedef void fuse_function(quaternion& rotation, float dt, const vector& angular_velocity,
                  const vector& acceleration, const vector& magnetic_field);

void fuse_compass_only(quaternion& rotation, float dt, const vector& angular_velocity,
  const vector& acceleration, const vector& magnetic_field)
{
    rotation = rotationFromCompass(acceleration, magnetic_field);
}

void fuse_gyro_only(quaternion& rotation, float dt, const vector& angular_velocity,
  const vector& acceleration, const vector& magnetic_field)
{
    quaternion w = quaternion(1, angular_velocity(0)*dt/2, angular_velocity(1)*dt/2, angular_velocity(2)*dt/2);

    // UM6 does: rotation += rotation*w;
    rotation = rotation*w;
    rotation.normalize();

    // TODO: finish this algorithm

    //rotation *= updateMatrix(angular_velocity, dt);
    //rotation = normalize(rotation);
}

#define Kp_ROLLPITCH 1
#define Ki_ROLLPITCH 0.00002
#define Kp_YAW 1
#define Ki_YAW 0.00002

#define PI 3.14159265

void fuse_default(quaternion& rotation, float dt, const vector& angular_velocity,
  const vector& acceleration, const vector& magnetic_field)
{
    rotation = quaternion::Identity();
    // TODO: finish this algorithm

    //matrix rotationCompass = rotationFromCompass(acceleration, magnetic_field);

    // We trust the accelerometer more if it is telling us 1G.
    //float accel_weight = 1 - 2*abs(1 - acceleration.norm());
    //if (accel_weight < 0){ accel_weight = 0; }

    // Add a "torque" that makes our up vector (rotation.row(2))
    // get closer to the acceleration vector.
    //vector errorRollPitch = acceleration.cross(rotation.row(2)) * accel_weight;

    // Add a "torque" that makes our east vector (rotation.row(0))
    // get closer to east vector calculated from the compass.
    //vector errorYaw = rotationCompass.row(0).cross(rotation.row(0));

    //vector drift_correction = errorYaw * Kp_YAW + errorRollPitch * Kp_ROLLPITCH;

    //rotation *= updateMatrix(angular_velocity + drift_correction, dt);
    //rotation = normalize(rotation);
}

void ahrs(IMU& imu, fuse_function * fuse_func)
{
    imu.loadCalibration();
    imu.enable();
    imu.measureOffsets();

    // The quaternion that can convert a vector in body coordinates
    // to ground coordinates when it its changed to a matrix.
    quaternion rotation = quaternion::Identity();

    int start = millis(); // truncate 64-bit return value
    while(1)
    {
        int last_start = start;
        start = millis();
        float dt = (start-last_start)/1000.0;
        if (dt < 0){ throw std::runtime_error("time went backwards"); }

        vector angular_velocity = imu.readGyro();
        vector acceleration = imu.readAcc();
        vector magnetic_field = imu.readMag();

        fuse_func(rotation, dt, angular_velocity, acceleration, magnetic_field);

        matrix r = rotation.matrix();
        printf("%7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f  %7.4f %7.4f %7.4f  %7.4f %7.4f %7.4f\n",
               r(0,0), r(0,1), r(0,2),
               r(1,0), r(1,1), r(1,2),
               r(2,0), r(2,1), r(2,2),
               acceleration(0), acceleration(1), acceleration(2),
               magnetic_field(0), magnetic_field(1), magnetic_field(2));
        fflush(stdout);

        // Ensure that each iteration of the loop takes at least 20 ms.
        while(millis() - start < 20)
        {
            usleep(1000);
        }
    }
}

int main(int argc, char *argv[])
{
    try
    {
        MinIMU9 imu("/dev/i2c-0");

        imu.checkConnection();

        if (argc > 1)
        {
            const char * action = argv[1];
            if (0 == strcmp("raw", action))
            {
                streamRawValues(imu);
            }
            else if (0 == strcmp("gyro-only", action))
            {
                ahrs(imu, &fuse_gyro_only);
            }
            else if (0 == strcmp("compass-only", action))
            {
                ahrs(imu, &fuse_compass_only);
            }
            else
            {
                fprintf(stderr, "Unknown action '%s'.\n", action);
                return 3;
            }
        }
        else
        {
            ahrs(imu, &fuse_default);
        }
        return 0;
    }
    catch(const std::system_error & error)
    {
        std::string what = error.what();
        const std::error_code & code = error.code();
        std::cerr << "Error: " << what << "  " << code.message() << " (" << code << ")\n";
    }
    catch(const std::exception & error)
    {
        std::cerr << "Error: " << error.what() << '\n';
    }
    return 1;
}
<commit_msg>Simplified fuse_gyro_only.<commit_after>#include "vector.h"
#include "MinIMU9.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <system_error>

// TODO: print warning if accelerometer magnitude is not close to 1 when starting up

int millis()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (tv.tv_sec) * 1000 + (tv.tv_usec)/1000;
}

void print(matrix m)
{
    printf("%7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f",
           m(0,0), m(0,1), m(0,2),
           m(1,0), m(1,1), m(1,2),
           m(2,0), m(2,1), m(2,2));
}

void streamRawValues(IMU& imu)
{
    imu.enable();
    while(1)
    {
        imu.read();
        printf("%7d %7d %7d  %7d %7d %7d  %7d %7d %7d\n",
               imu.raw_m[0], imu.raw_m[1], imu.raw_m[2],
               imu.raw_a[0], imu.raw_a[1], imu.raw_a[2],
               imu.raw_g[0], imu.raw_g[1], imu.raw_g[2]
        );
        usleep(20*1000);
    }
}

matrix rotationFromCompass(const vector& acceleration, const vector& magnetic_field)
{
    vector up = acceleration;     // usually true
    vector magnetic_east = magnetic_field.cross(up);
    vector east = magnetic_east;  // a rough approximation
    vector north = up.cross(east);

    matrix rotationFromCompass;
    rotationFromCompass.row(0) = east;
    rotationFromCompass.row(1) = north;
    rotationFromCompass.row(2) = up;
    rotationFromCompass.row(0).normalize();
    rotationFromCompass.row(1).normalize();
    rotationFromCompass.row(2).normalize();

    return rotationFromCompass;
}

float heading(matrix rotation)
{
    // The board's x axis in earth coordinates.
    vector x = rotation.col(0);
    x.normalize();
    x(2) = 0;
    //float heading_weight = x.norm();

    // 0 = east, pi/2 = north
    return atan2(x(1), x(0));
}

typedef void fuse_function(quaternion& rotation, float dt, const vector& angular_velocity,
                  const vector& acceleration, const vector& magnetic_field);

void fuse_compass_only(quaternion& rotation, float dt, const vector& angular_velocity,
  const vector& acceleration, const vector& magnetic_field)
{
    rotation = rotationFromCompass(acceleration, magnetic_field);
}

void fuse_gyro_only(quaternion& rotation, float dt, const vector& angular_velocity,
  const vector& acceleration, const vector& magnetic_field)
{
    // First order approximation of the quaternion representing this rotation.
    quaternion w = quaternion(1, angular_velocity(0)*dt/2, angular_velocity(1)*dt/2, angular_velocity(2)*dt/2);

    // UM6 does: rotation += rotation*w, except their w has a 0 for the first component;
    // Is that the same as what we are doing?
    rotation *= w;
    rotation.normalize();
}

#define Kp_ROLLPITCH 1
#define Ki_ROLLPITCH 0.00002
#define Kp_YAW 1
#define Ki_YAW 0.00002

#define PI 3.14159265

void fuse_default(quaternion& rotation, float dt, const vector& angular_velocity,
  const vector& acceleration, const vector& magnetic_field)
{
    rotation = quaternion::Identity();
    // TODO: finish this algorithm

    //matrix rotationCompass = rotationFromCompass(acceleration, magnetic_field);

    // We trust the accelerometer more if it is telling us 1G.
    //float accel_weight = 1 - 2*abs(1 - acceleration.norm());
    //if (accel_weight < 0){ accel_weight = 0; }

    // Add a "torque" that makes our up vector (rotation.row(2))
    // get closer to the acceleration vector.
    //vector errorRollPitch = acceleration.cross(rotation.row(2)) * accel_weight;

    // Add a "torque" that makes our east vector (rotation.row(0))
    // get closer to east vector calculated from the compass.
    //vector errorYaw = rotationCompass.row(0).cross(rotation.row(0));

    //vector drift_correction = errorYaw * Kp_YAW + errorRollPitch * Kp_ROLLPITCH;

    //rotation *= updateMatrix(angular_velocity + drift_correction, dt);
    //rotation = normalize(rotation);
}

void ahrs(IMU& imu, fuse_function * fuse_func)
{
    imu.loadCalibration();
    imu.enable();
    imu.measureOffsets();

    // The quaternion that can convert a vector in body coordinates
    // to ground coordinates when it its changed to a matrix.
    quaternion rotation = quaternion::Identity();

    int start = millis(); // truncate 64-bit return value
    while(1)
    {
        int last_start = start;
        start = millis();
        float dt = (start-last_start)/1000.0;
        if (dt < 0){ throw std::runtime_error("time went backwards"); }

        vector angular_velocity = imu.readGyro();
        vector acceleration = imu.readAcc();
        vector magnetic_field = imu.readMag();

        fuse_func(rotation, dt, angular_velocity, acceleration, magnetic_field);

        matrix r = rotation.matrix();
        printf("%7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f  %7.4f %7.4f %7.4f  %7.4f %7.4f %7.4f\n",
               r(0,0), r(0,1), r(0,2),
               r(1,0), r(1,1), r(1,2),
               r(2,0), r(2,1), r(2,2),
               acceleration(0), acceleration(1), acceleration(2),
               magnetic_field(0), magnetic_field(1), magnetic_field(2));
        fflush(stdout);

        // Ensure that each iteration of the loop takes at least 20 ms.
        while(millis() - start < 20)
        {
            usleep(1000);
        }
    }
}

int main(int argc, char *argv[])
{
    try
    {
        MinIMU9 imu("/dev/i2c-0");

        imu.checkConnection();

        if (argc > 1)
        {
            const char * action = argv[1];
            if (0 == strcmp("raw", action))
            {
                streamRawValues(imu);
            }
            else if (0 == strcmp("gyro-only", action))
            {
                ahrs(imu, &fuse_gyro_only);
            }
            else if (0 == strcmp("compass-only", action))
            {
                ahrs(imu, &fuse_compass_only);
            }
            else
            {
                fprintf(stderr, "Unknown action '%s'.\n", action);
                return 3;
            }
        }
        else
        {
            ahrs(imu, &fuse_default);
        }
        return 0;
    }
    catch(const std::system_error & error)
    {
        std::string what = error.what();
        const std::error_code & code = error.code();
        std::cerr << "Error: " << what << "  " << code.message() << " (" << code << ")\n";
    }
    catch(const std::exception & error)
    {
        std::cerr << "Error: " << error.what() << '\n';
    }
    return 1;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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.
 */

#include "zorbautils/fatal.h"
#include "zorbatypes/xqpstring.h"
#include "store/naive/nsbindings.h"

namespace zorba { namespace simplestore {

NsBindingsContext::NsBindingsContext(ulong numBindings)
{
  theBindings.resize(numBindings);
#if 0
  std::cout << "Create binding context1 " << this << "; num bindings = "
            << numBindings << std::endl;
#endif
}

NsBindingsContext::NsBindingsContext(const store::NsBindings& bindings)
  :
  theBindings(bindings)
{
#if 0
  std::cout << "Create binding context2 " << this << "; num bindings = "
            << bindings.size() << std::endl;
#endif
}

NsBindingsContext::~NsBindingsContext()
{
#if 0
  std::cout << "Removing binding context " << this << "; num bindings = "
            << theBindings.size() << std::endl;
#endif
}

xqpStringStore* NsBindingsContext::findBinding(const xqpStringStore* prefix) const
{
  const NsBindingsContext* currentContext = this;

  while (currentContext != NULL)
  {
    const store::NsBindings& bindings = currentContext->theBindings;
    ulong numBindings = bindings.size();

    for (ulong i = 0; i < numBindings; i++)
    {
      if (bindings[i].first.getStore()->byteEqual(*prefix))
        return bindings[i].second.getStore();
    }

    currentContext = currentContext->getParent();
  }

  return NULL;
}

void NsBindingsContext::addBinding(
    xqpStringStore* prefix,
    xqpStringStore* ns)
{
  ulong numBindings = theBindings.size();

  for (ulong i = 0; i < numBindings; i++)
  {
    if (theBindings[i].first.getStore()->byteEqual(*prefix))
    {
      ZORBA_FATAL(theBindings[i].second.getStore()->byteEqual(*ns), "");

      return;
    }
  }

  theBindings.push_back(std::pair<xqpString, xqpString>(prefix, ns));
}

void NsBindingsContext::removeBinding(
    xqpStringStore* prefix,
    xqpStringStore* ns)
{
  ulong numBindings = theBindings.size();

  for (ulong i = 0; i < numBindings; i++)
  {
    if (theBindings[i].first.getStore()->byteEqual(*prefix))
    {
      ZORBA_FATAL(theBindings[i].second.getStore()->byteEqual(*ns), "");

      theBindings.erase(theBindings.begin() + i);
      return;
    }
  }
}

} // namespace store
} // namespace zorba

<commit_msg>Fixed some tests.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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.
 */

#include "zorbautils/fatal.h"
#include "zorbatypes/xqpstring.h"
#include "store/naive/nsbindings.h"

namespace zorba { namespace simplestore {

NsBindingsContext::NsBindingsContext(ulong numBindings)
{
  theBindings.resize(numBindings);
#if 0
  std::cout << "Create binding context1 " << this << "; num bindings = "
            << numBindings << std::endl;
#endif
}

NsBindingsContext::NsBindingsContext(const store::NsBindings& bindings)
  :
  theBindings(bindings)
{
#if 0
  std::cout << "Create binding context2 " << this << "; num bindings = "
            << bindings.size() << std::endl;
#endif
}

NsBindingsContext::~NsBindingsContext()
{
#if 0
  std::cout << "Removing binding context " << this << "; num bindings = "
            << theBindings.size() << std::endl;
#endif
}

xqpStringStore* NsBindingsContext::findBinding(const xqpStringStore* prefix) const
{
  const NsBindingsContext* currentContext = this;

  while (currentContext != NULL)
  {
    const store::NsBindings& bindings = currentContext->theBindings;
    ulong numBindings = bindings.size();

    for (ulong i = 0; i < numBindings; i++)
    {
      if (bindings[i].first.getStore()->byteEqual(*prefix))
        return bindings[i].second.getStore();
    }

    currentContext = currentContext->getParent();
  }

  return NULL;
}

void NsBindingsContext::addBinding(
    xqpStringStore* prefix,
    xqpStringStore* ns)
{
  ulong numBindings = theBindings.size();

  for (ulong i = 0; i < numBindings; i++)
  {
    if (theBindings[i].first.getStore()->byteEqual(*prefix))
    {
      if(!theBindings[i].second.getStore()->byteEqual(*ns))
      {
        ZORBA_FATAL(theBindings[i].second.getStore()->byteEqual(*ns), "");
      }
      return;
    }
  }

  theBindings.push_back(std::pair<xqpString, xqpString>(prefix, ns));
}

void NsBindingsContext::removeBinding(
    xqpStringStore* prefix,
    xqpStringStore* ns)
{
  ulong numBindings = theBindings.size();

  for (ulong i = 0; i < numBindings; i++)
  {
    if (theBindings[i].first.getStore()->byteEqual(*prefix))
    {
      ZORBA_FATAL(theBindings[i].second.getStore()->byteEqual(*ns), "");

      theBindings.erase(theBindings.begin() + i);
      return;
    }
  }
}

} // namespace store
} // namespace zorba

<|endoftext|>