<commit_before>/*  This file is part of the KDE project
    Copyright (C) 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 Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/

#include "path.h"
#include "path_p.h"

#include "phononnamespace_p.h"
#include "backendinterface.h"
#include "factory_p.h"
#include "medianode.h"
#include "medianode_p.h"

QT_BEGIN_NAMESPACE

namespace Phonon
{

class ConnectionTransaction
{
    public:
        ConnectionTransaction(BackendInterface *b, const QSet<QObject*> &x) : backend(b), list(x)
        {
            success = backend->startConnectionChange(list);
        }
        ~ConnectionTransaction()
        {
            backend->endConnectionChange(list);
        }
        operator bool()
        {
            return success;
        }
    private:
        bool success;
        BackendInterface *const backend;
        const QSet<QObject*> list;
};

PathPrivate::~PathPrivate()
{
#ifndef QT_NO_PHONON_EFFECT
    foreach (Effect *e, effects) {
        e->k_ptr->removeDestructionHandler(this);
    }
    delete effectsParent;
#endif
}

Path::~Path()
{
}

Path::Path()
    : d(new PathPrivate)
{
}

Path::Path(const Path &rhs)
    : d(rhs.d)
{
}

bool Path::isValid() const
{
    return d->sourceNode != 0 && d->sinkNode != 0;
}

#ifndef QT_NO_PHONON_EFFECT
Effect *Path::insertEffect(const EffectDescription &desc, Effect *insertBefore)
{
    if (!d->effectsParent) {
        d->effectsParent = new QObject;
    }
    Effect *e = new Effect(desc, d->effectsParent);
    if (!e->isValid()) {
        delete e;
        return 0;
    }
    bool success = insertEffect(e, insertBefore);
    if (!success) {
        delete e;
        return 0;
    }
    return e;
}

bool Path::insertEffect(Effect *newEffect, Effect *insertBefore)
{
    QObject *newEffectBackend = newEffect ? newEffect->k_ptr->backendObject() : 0;
    if (!isValid() || !newEffectBackend || d->effects.contains(newEffect) ||
            (insertBefore && (!d->effects.contains(insertBefore) || !insertBefore->k_ptr->backendObject()))) {
        return false;
    }
    QObject *leftNode = 0;
    QObject *rightNode = 0;
    const int insertIndex = insertBefore ? d->effects.indexOf(insertBefore) : d->effects.size();
    if (insertIndex == 0) {
        //prepend
        leftNode = d->sourceNode->k_ptr->backendObject();
    } else {
        leftNode = d->effects[insertIndex - 1]->k_ptr->backendObject();
    }

    if (insertIndex == d->effects.size()) {
        //append
        rightNode = d->sinkNode->k_ptr->backendObject();
    } else {
        Q_ASSERT(insertBefore);
        rightNode = insertBefore->k_ptr->backendObject();
    }

    QList<QObjectPair> disconnections, connections;
    disconnections << QObjectPair(leftNode, rightNode);
    connections << QObjectPair(leftNode, newEffectBackend)
        << QObjectPair(newEffectBackend, rightNode);

    if (d->executeTransaction(disconnections, connections)) {
        newEffect->k_ptr->addDestructionHandler(d.data());
        d->effects.insert(insertIndex, newEffect);
        return true;
    } else {
        return false;
    }
}

bool Path::removeEffect(Effect *effect)
{
    return d->removeEffect(effect);
}

QList<Effect *> Path::effects() const
{
    return d->effects;
}
#endif //QT_NO_PHONON_EFFECT

bool Path::reconnect(MediaNode *source, MediaNode *sink)
{
    if (!source || !sink || !source->k_ptr->backendObject() || !sink->k_ptr->backendObject()) {
        return false;
    }

    QList<QObjectPair> disconnections, connections;

    //backend objects
    QObject *bnewSource = source->k_ptr->backendObject();
    QObject *bnewSink = sink->k_ptr->backendObject();
    QObject *bcurrentSource = d->sourceNode ? d->sourceNode->k_ptr->backendObject() : 0;
    QObject *bcurrentSink = d->sinkNode ? d->sinkNode->k_ptr->backendObject() : 0;

    if (bnewSource != bcurrentSource) {
        //we need to change the source
#ifndef QT_NO_PHONON_EFFECT
        MediaNode *next = d->effects.isEmpty() ? sink : d->effects.first();
#else
        MediaNode *next = sink;
#endif //QT_NO_PHONON_EFFECT
        QObject *bnext = next->k_ptr->backendObject();
        if (bcurrentSource)
            disconnections << QObjectPair(bcurrentSource, bnext);
        connections << QObjectPair(bnewSource, bnext);
    }

    if (bnewSink != bcurrentSink) {
#ifndef QT_NO_PHONON_EFFECT
        MediaNode *previous = d->effects.isEmpty() ? source : d->effects.last();
#else
        MediaNode *previous = source;
#endif //QT_NO_PHONON_EFFECT
        QObject *bprevious = previous->k_ptr->backendObject();
        if (bcurrentSink)
            disconnections << QObjectPair(bprevious, bcurrentSink);
        QObjectPair pair(bprevious, bnewSink);
        if (!connections.contains(pair)) //avoid connecting twice
            connections << pair;
    }

    if (d->executeTransaction(disconnections, connections)) {

        //everything went well: let's update the path and the sink node
        if (d->sinkNode != sink) {
            if (d->sinkNode) {
                d->sinkNode->k_ptr->removeInputPath(*this);
                d->sinkNode->k_ptr->removeDestructionHandler(d.data());
            }
            sink->k_ptr->addInputPath(*this);
            d->sinkNode = sink;
            d->sinkNode->k_ptr->addDestructionHandler(d.data());
        }

        //everything went well: let's update the path and the source node
        if (d->sourceNode != source) {
            source->k_ptr->addOutputPath(*this);
            if (d->sourceNode) {
                d->sourceNode->k_ptr->removeOutputPath(*this);
                d->sourceNode->k_ptr->removeDestructionHandler(d.data());
            }
            d->sourceNode = source;
            d->sourceNode->k_ptr->addDestructionHandler(d.data());
        }
        return true;
    } else {
        return false;
    }
}

bool Path::disconnect()
{
    if (!isValid()) {
        return false;
    }

    QObjectList list;
    if (d->sourceNode)
        list << d->sourceNode->k_ptr->backendObject();
#ifndef QT_NO_PHONON_EFFECT
    foreach(Effect *e, d->effects) {
        list << e->k_ptr->backendObject();
    }
#endif
    if (d->sinkNode) {
        list << d->sinkNode->k_ptr->backendObject();
    }

    //lets build the disconnection list
    QList<QObjectPair> disco;
    if (list.count() >=2 ) {
        QObjectList::const_iterator it = list.begin();
        for(;it+1 != list.end();++it) {
            disco << QObjectPair(*it, *(it+1));
        }
    }

    if (d->executeTransaction(disco, QList<QObjectPair>())) {
        //everything went well, let's remove the reference
        //to the paths from the source and sink
        if (d->sourceNode) {
            d->sourceNode->k_ptr->removeOutputPath(*this);
            d->sourceNode->k_ptr->removeDestructionHandler(d.data());
        }
        d->sourceNode = 0;

#ifndef QT_NO_PHONON_EFFECT
        foreach(Effect *e, d->effects) {
            e->k_ptr->removeDestructionHandler(d.data());
        }
        d->effects.clear();
#endif

        if (d->sinkNode) {
            d->sinkNode->k_ptr->removeInputPath(*this);
            d->sinkNode->k_ptr->removeDestructionHandler(d.data());
        }
        d->sinkNode = 0;
        return true;
    } else {
        return false;
    }
}

MediaNode *Path::source() const
{
    return d->sourceNode;
}

MediaNode *Path::sink() const
{
    return d->sinkNode;
}

bool PathPrivate::executeTransaction( const QList<QObjectPair> &disconnections, const QList<QObjectPair> &connections)
{
    QSet<QObject*> nodesForTransaction;
    foreach(const QObjectPair &pair, disconnections) {
        nodesForTransaction << pair.first;
        nodesForTransaction << pair.second;
    }
    foreach(const QObjectPair &pair, connections) {
        nodesForTransaction << pair.first;
        nodesForTransaction << pair.second;
    }
    BackendInterface *backend = qobject_cast<BackendInterface *>(Factory::backend());
    if (!backend)
        return false;

    ConnectionTransaction transaction(backend, nodesForTransaction);
    if (!transaction)
        return false;

    QList<QObjectPair>::const_iterator it = disconnections.begin();
    for(;it != disconnections.end();++it) {
        const QObjectPair &pair = *it;
        if (!backend->disconnectNodes(pair.first, pair.second)) {

            //Error: a disconnection failed
            QList<QObjectPair>::const_iterator it2 = disconnections.begin();
            for(; it2 != it; ++it2) {
                const QObjectPair &pair = *it2;
                bool success = backend->connectNodes(pair.first, pair.second);
                Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
                Q_UNUSED(success);
            }
            return false;
        }
    }

    for(it = connections.begin(); it != connections.end();++it) {
        const QObjectPair &pair = *it;
        if (!backend->connectNodes(pair.first, pair.second)) {
            //Error: a connection failed
            QList<QObjectPair>::const_iterator it2 = connections.begin();
            for(; it2 != it; ++it2) {
                const QObjectPair &pair = *it2;
                bool success = backend->disconnectNodes(pair.first, pair.second);
                Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
                Q_UNUSED(success);
            }

            //and now let's reconnect the nodes that were disconnected: rollback
            foreach(const QObjectPair &pair, disconnections) {
                bool success = backend->connectNodes(pair.first, pair.second);
                Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
                Q_UNUSED(success);
            }

            return false;

        }
    }
    return true;
}

#ifndef QT_NO_PHONON_EFFECT
bool PathPrivate::removeEffect(Effect *effect)
{
    if (!effects.contains(effect))
        return false;

    QObject *leftNode = 0;
    QObject *rightNode = 0;
    const int index = effects.indexOf(effect);
    if (index == 0) {
        leftNode = sourceNode->k_ptr->backendObject(); //append
    } else {
        leftNode = effects[index - 1]->k_ptr->backendObject();
    }
    if (index == effects.size()-1) {
        rightNode = sinkNode->k_ptr->backendObject(); //prepend
    } else {
        rightNode = effects[index + 1]->k_ptr->backendObject();
    }

    QList<QObjectPair> disconnections, connections;
    QObject *beffect = effect->k_ptr->backendObject();
    disconnections << QObjectPair(leftNode, beffect) << QObjectPair(beffect, rightNode);
    connections << QObjectPair(leftNode, rightNode);

    if (executeTransaction(disconnections, connections)) {
        effect->k_ptr->removeDestructionHandler(this);
        effects.removeAt(index);
        return true;
    }
    return false;
}
#endif //QT_NO_PHONON_EFFECT

void PathPrivate::phononObjectDestroyed(MediaNodePrivate *mediaNodePrivate)
{
    Q_ASSERT(mediaNodePrivate);
    if (mediaNodePrivate == sinkNode->k_ptr || mediaNodePrivate == sourceNode->k_ptr) {
        //let's first disconnectq the path from its source and sink
        QObject *bsink = sinkNode->k_ptr->backendObject();
        QObject *bsource = sourceNode->k_ptr->backendObject();
        QList<QObjectPair> disconnections;
#ifndef QT_NO_PHONON_EFFECT
        disconnections << QObjectPair(bsource, effects.isEmpty() ? bsink : effects.first()->k_ptr->backendObject());
        if (!effects.isEmpty())
            disconnections << QObjectPair(effects.last()->k_ptr->backendObject(), bsink);
#else
        disconnections << QObjectPair(bsource, bsink);
#endif //QT_NO_PHONON_EFFECT

        executeTransaction(disconnections, QList<QObjectPair>());

        Path p; //temporary path
        p.d = this;
        if (mediaNodePrivate == sinkNode->k_ptr) {
            sourceNode->k_ptr->removeOutputPath(p);
            sourceNode->k_ptr->removeDestructionHandler(this);
        } else {
            sinkNode->k_ptr->removeInputPath(p);
            sinkNode->k_ptr->removeDestructionHandler(this);
        }
        sourceNode = 0;
        sinkNode = 0;
    } else {
#ifndef QT_NO_PHONON_EFFECT
        foreach (Effect *e, effects) {
            if (e->k_ptr == mediaNodePrivate) {
                removeEffect(e);
            }
        }
#endif //QT_NO_PHONON_EFFECT
    }
}

Path createPath(MediaNode *source, MediaNode *sink)
{
    Path p;
    if (!p.reconnect(source, sink)) {
        const QObject *const src = source ? (source->k_ptr->qObject()
#ifndef QT_NO_DYNAMIC_CAST
                ? source->k_ptr->qObject() : dynamic_cast<QObject *>(source)
#endif
                ) : 0;
        const QObject *const snk = sink ? (sink->k_ptr->qObject()
#ifndef QT_NO_DYNAMIC_CAST
                ? sink->k_ptr->qObject() : dynamic_cast<QObject *>(sink)
#endif
                ) : 0;
        pWarning() << "Phonon::createPath: Cannot connect "
            << (src ? src->metaObject()->className() : "")
            << '(' << (src ? (src->objectName().isEmpty() ? "no objectName" : qPrintable(src->objectName())) : "null") << ") to "
            << (snk ? snk->metaObject()->className() : "")
            << '(' << (snk ? (snk->objectName().isEmpty() ? "no objectName" : qPrintable(snk->objectName())) : "null")
            << ").";
    }
    return p;
}

Path & Path::operator=(const Path &other)
{
    d = other.d;
    return *this;
}

bool Path::operator==(const Path &other) const
{
    return d == other.d;
}

bool Path::operator!=(const Path &other) const
{
    return !operator==(other);
}

} // namespace Phonon

QT_END_NAMESPACE
<commit_msg>fix compilation with -DQT_STRICT_ITERATORS<commit_after>/*  This file is part of the KDE project
    Copyright (C) 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 Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/

#include "path.h"
#include "path_p.h"

#include "phononnamespace_p.h"
#include "backendinterface.h"
#include "factory_p.h"
#include "medianode.h"
#include "medianode_p.h"

QT_BEGIN_NAMESPACE

namespace Phonon
{

class ConnectionTransaction
{
    public:
        ConnectionTransaction(BackendInterface *b, const QSet<QObject*> &x) : backend(b), list(x)
        {
            success = backend->startConnectionChange(list);
        }
        ~ConnectionTransaction()
        {
            backend->endConnectionChange(list);
        }
        operator bool()
        {
            return success;
        }
    private:
        bool success;
        BackendInterface *const backend;
        const QSet<QObject*> list;
};

PathPrivate::~PathPrivate()
{
#ifndef QT_NO_PHONON_EFFECT
    foreach (Effect *e, effects) {
        e->k_ptr->removeDestructionHandler(this);
    }
    delete effectsParent;
#endif
}

Path::~Path()
{
}

Path::Path()
    : d(new PathPrivate)
{
}

Path::Path(const Path &rhs)
    : d(rhs.d)
{
}

bool Path::isValid() const
{
    return d->sourceNode != 0 && d->sinkNode != 0;
}

#ifndef QT_NO_PHONON_EFFECT
Effect *Path::insertEffect(const EffectDescription &desc, Effect *insertBefore)
{
    if (!d->effectsParent) {
        d->effectsParent = new QObject;
    }
    Effect *e = new Effect(desc, d->effectsParent);
    if (!e->isValid()) {
        delete e;
        return 0;
    }
    bool success = insertEffect(e, insertBefore);
    if (!success) {
        delete e;
        return 0;
    }
    return e;
}

bool Path::insertEffect(Effect *newEffect, Effect *insertBefore)
{
    QObject *newEffectBackend = newEffect ? newEffect->k_ptr->backendObject() : 0;
    if (!isValid() || !newEffectBackend || d->effects.contains(newEffect) ||
            (insertBefore && (!d->effects.contains(insertBefore) || !insertBefore->k_ptr->backendObject()))) {
        return false;
    }
    QObject *leftNode = 0;
    QObject *rightNode = 0;
    const int insertIndex = insertBefore ? d->effects.indexOf(insertBefore) : d->effects.size();
    if (insertIndex == 0) {
        //prepend
        leftNode = d->sourceNode->k_ptr->backendObject();
    } else {
        leftNode = d->effects[insertIndex - 1]->k_ptr->backendObject();
    }

    if (insertIndex == d->effects.size()) {
        //append
        rightNode = d->sinkNode->k_ptr->backendObject();
    } else {
        Q_ASSERT(insertBefore);
        rightNode = insertBefore->k_ptr->backendObject();
    }

    QList<QObjectPair> disconnections, connections;
    disconnections << QObjectPair(leftNode, rightNode);
    connections << QObjectPair(leftNode, newEffectBackend)
        << QObjectPair(newEffectBackend, rightNode);

    if (d->executeTransaction(disconnections, connections)) {
        newEffect->k_ptr->addDestructionHandler(d.data());
        d->effects.insert(insertIndex, newEffect);
        return true;
    } else {
        return false;
    }
}

bool Path::removeEffect(Effect *effect)
{
    return d->removeEffect(effect);
}

QList<Effect *> Path::effects() const
{
    return d->effects;
}
#endif //QT_NO_PHONON_EFFECT

bool Path::reconnect(MediaNode *source, MediaNode *sink)
{
    if (!source || !sink || !source->k_ptr->backendObject() || !sink->k_ptr->backendObject()) {
        return false;
    }

    QList<QObjectPair> disconnections, connections;

    //backend objects
    QObject *bnewSource = source->k_ptr->backendObject();
    QObject *bnewSink = sink->k_ptr->backendObject();
    QObject *bcurrentSource = d->sourceNode ? d->sourceNode->k_ptr->backendObject() : 0;
    QObject *bcurrentSink = d->sinkNode ? d->sinkNode->k_ptr->backendObject() : 0;

    if (bnewSource != bcurrentSource) {
        //we need to change the source
#ifndef QT_NO_PHONON_EFFECT
        MediaNode *next = d->effects.isEmpty() ? sink : d->effects.first();
#else
        MediaNode *next = sink;
#endif //QT_NO_PHONON_EFFECT
        QObject *bnext = next->k_ptr->backendObject();
        if (bcurrentSource)
            disconnections << QObjectPair(bcurrentSource, bnext);
        connections << QObjectPair(bnewSource, bnext);
    }

    if (bnewSink != bcurrentSink) {
#ifndef QT_NO_PHONON_EFFECT
        MediaNode *previous = d->effects.isEmpty() ? source : d->effects.last();
#else
        MediaNode *previous = source;
#endif //QT_NO_PHONON_EFFECT
        QObject *bprevious = previous->k_ptr->backendObject();
        if (bcurrentSink)
            disconnections << QObjectPair(bprevious, bcurrentSink);
        QObjectPair pair(bprevious, bnewSink);
        if (!connections.contains(pair)) //avoid connecting twice
            connections << pair;
    }

    if (d->executeTransaction(disconnections, connections)) {

        //everything went well: let's update the path and the sink node
        if (d->sinkNode != sink) {
            if (d->sinkNode) {
                d->sinkNode->k_ptr->removeInputPath(*this);
                d->sinkNode->k_ptr->removeDestructionHandler(d.data());
            }
            sink->k_ptr->addInputPath(*this);
            d->sinkNode = sink;
            d->sinkNode->k_ptr->addDestructionHandler(d.data());
        }

        //everything went well: let's update the path and the source node
        if (d->sourceNode != source) {
            source->k_ptr->addOutputPath(*this);
            if (d->sourceNode) {
                d->sourceNode->k_ptr->removeOutputPath(*this);
                d->sourceNode->k_ptr->removeDestructionHandler(d.data());
            }
            d->sourceNode = source;
            d->sourceNode->k_ptr->addDestructionHandler(d.data());
        }
        return true;
    } else {
        return false;
    }
}

bool Path::disconnect()
{
    if (!isValid()) {
        return false;
    }

    QObjectList list;
    if (d->sourceNode)
        list << d->sourceNode->k_ptr->backendObject();
#ifndef QT_NO_PHONON_EFFECT
    foreach(Effect *e, d->effects) {
        list << e->k_ptr->backendObject();
    }
#endif
    if (d->sinkNode) {
        list << d->sinkNode->k_ptr->backendObject();
    }

    //lets build the disconnection list
    QList<QObjectPair> disco;
    if (list.count() >=2 ) {
        QObjectList::const_iterator it = list.constBegin();
        for(;it+1 != list.constEnd();++it) {
            disco << QObjectPair(*it, *(it+1));
        }
    }

    if (d->executeTransaction(disco, QList<QObjectPair>())) {
        //everything went well, let's remove the reference
        //to the paths from the source and sink
        if (d->sourceNode) {
            d->sourceNode->k_ptr->removeOutputPath(*this);
            d->sourceNode->k_ptr->removeDestructionHandler(d.data());
        }
        d->sourceNode = 0;

#ifndef QT_NO_PHONON_EFFECT
        foreach(Effect *e, d->effects) {
            e->k_ptr->removeDestructionHandler(d.data());
        }
        d->effects.clear();
#endif

        if (d->sinkNode) {
            d->sinkNode->k_ptr->removeInputPath(*this);
            d->sinkNode->k_ptr->removeDestructionHandler(d.data());
        }
        d->sinkNode = 0;
        return true;
    } else {
        return false;
    }
}

MediaNode *Path::source() const
{
    return d->sourceNode;
}

MediaNode *Path::sink() const
{
    return d->sinkNode;
}

bool PathPrivate::executeTransaction( const QList<QObjectPair> &disconnections, const QList<QObjectPair> &connections)
{
    QSet<QObject*> nodesForTransaction;
    foreach(const QObjectPair &pair, disconnections) {
        nodesForTransaction << pair.first;
        nodesForTransaction << pair.second;
    }
    foreach(const QObjectPair &pair, connections) {
        nodesForTransaction << pair.first;
        nodesForTransaction << pair.second;
    }
    BackendInterface *backend = qobject_cast<BackendInterface *>(Factory::backend());
    if (!backend)
        return false;

    ConnectionTransaction transaction(backend, nodesForTransaction);
    if (!transaction)
        return false;

    QList<QObjectPair>::const_iterator it = disconnections.begin();
    for(;it != disconnections.end();++it) {
        const QObjectPair &pair = *it;
        if (!backend->disconnectNodes(pair.first, pair.second)) {

            //Error: a disconnection failed
            QList<QObjectPair>::const_iterator it2 = disconnections.begin();
            for(; it2 != it; ++it2) {
                const QObjectPair &pair = *it2;
                bool success = backend->connectNodes(pair.first, pair.second);
                Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
                Q_UNUSED(success);
            }
            return false;
        }
    }

    for(it = connections.begin(); it != connections.end();++it) {
        const QObjectPair &pair = *it;
        if (!backend->connectNodes(pair.first, pair.second)) {
            //Error: a connection failed
            QList<QObjectPair>::const_iterator it2 = connections.begin();
            for(; it2 != it; ++it2) {
                const QObjectPair &pair = *it2;
                bool success = backend->disconnectNodes(pair.first, pair.second);
                Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
                Q_UNUSED(success);
            }

            //and now let's reconnect the nodes that were disconnected: rollback
            foreach(const QObjectPair &pair, disconnections) {
                bool success = backend->connectNodes(pair.first, pair.second);
                Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
                Q_UNUSED(success);
            }

            return false;

        }
    }
    return true;
}

#ifndef QT_NO_PHONON_EFFECT
bool PathPrivate::removeEffect(Effect *effect)
{
    if (!effects.contains(effect))
        return false;

    QObject *leftNode = 0;
    QObject *rightNode = 0;
    const int index = effects.indexOf(effect);
    if (index == 0) {
        leftNode = sourceNode->k_ptr->backendObject(); //append
    } else {
        leftNode = effects[index - 1]->k_ptr->backendObject();
    }
    if (index == effects.size()-1) {
        rightNode = sinkNode->k_ptr->backendObject(); //prepend
    } else {
        rightNode = effects[index + 1]->k_ptr->backendObject();
    }

    QList<QObjectPair> disconnections, connections;
    QObject *beffect = effect->k_ptr->backendObject();
    disconnections << QObjectPair(leftNode, beffect) << QObjectPair(beffect, rightNode);
    connections << QObjectPair(leftNode, rightNode);

    if (executeTransaction(disconnections, connections)) {
        effect->k_ptr->removeDestructionHandler(this);
        effects.removeAt(index);
        return true;
    }
    return false;
}
#endif //QT_NO_PHONON_EFFECT

void PathPrivate::phononObjectDestroyed(MediaNodePrivate *mediaNodePrivate)
{
    Q_ASSERT(mediaNodePrivate);
    if (mediaNodePrivate == sinkNode->k_ptr || mediaNodePrivate == sourceNode->k_ptr) {
        //let's first disconnectq the path from its source and sink
        QObject *bsink = sinkNode->k_ptr->backendObject();
        QObject *bsource = sourceNode->k_ptr->backendObject();
        QList<QObjectPair> disconnections;
#ifndef QT_NO_PHONON_EFFECT
        disconnections << QObjectPair(bsource, effects.isEmpty() ? bsink : effects.first()->k_ptr->backendObject());
        if (!effects.isEmpty())
            disconnections << QObjectPair(effects.last()->k_ptr->backendObject(), bsink);
#else
        disconnections << QObjectPair(bsource, bsink);
#endif //QT_NO_PHONON_EFFECT

        executeTransaction(disconnections, QList<QObjectPair>());

        Path p; //temporary path
        p.d = this;
        if (mediaNodePrivate == sinkNode->k_ptr) {
            sourceNode->k_ptr->removeOutputPath(p);
            sourceNode->k_ptr->removeDestructionHandler(this);
        } else {
            sinkNode->k_ptr->removeInputPath(p);
            sinkNode->k_ptr->removeDestructionHandler(this);
        }
        sourceNode = 0;
        sinkNode = 0;
    } else {
#ifndef QT_NO_PHONON_EFFECT
        foreach (Effect *e, effects) {
            if (e->k_ptr == mediaNodePrivate) {
                removeEffect(e);
            }
        }
#endif //QT_NO_PHONON_EFFECT
    }
}

Path createPath(MediaNode *source, MediaNode *sink)
{
    Path p;
    if (!p.reconnect(source, sink)) {
        const QObject *const src = source ? (source->k_ptr->qObject()
#ifndef QT_NO_DYNAMIC_CAST
                ? source->k_ptr->qObject() : dynamic_cast<QObject *>(source)
#endif
                ) : 0;
        const QObject *const snk = sink ? (sink->k_ptr->qObject()
#ifndef QT_NO_DYNAMIC_CAST
                ? sink->k_ptr->qObject() : dynamic_cast<QObject *>(sink)
#endif
                ) : 0;
        pWarning() << "Phonon::createPath: Cannot connect "
            << (src ? src->metaObject()->className() : "")
            << '(' << (src ? (src->objectName().isEmpty() ? "no objectName" : qPrintable(src->objectName())) : "null") << ") to "
            << (snk ? snk->metaObject()->className() : "")
            << '(' << (snk ? (snk->objectName().isEmpty() ? "no objectName" : qPrintable(snk->objectName())) : "null")
            << ").";
    }
    return p;
}

Path & Path::operator=(const Path &other)
{
    d = other.d;
    return *this;
}

bool Path::operator==(const Path &other) const
{
    return d == other.d;
}

bool Path::operator!=(const Path &other) const
{
    return !operator==(other);
}

} // namespace Phonon

QT_END_NAMESPACE
<|endoftext|>


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

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <sstream>
#include <Corrade/TestSuite/Tester.h>

#include "Magnum/AbstractResourceLoader.h"
#include "Magnum/ResourceManager.h"

namespace Magnum { namespace Test {

struct ResourceManagerTest: TestSuite::Tester {
    explicit ResourceManagerTest();

    void state();
    void stateFallback();
    void stateDisallowed();
    void basic();
    void residentPolicy();
    void referenceCountedPolicy();
    void manualPolicy();
    void defaults();
    void clear();
    void clearWhileReferenced();
    void loader();
};

class Data {
    public:
        static std::size_t count;

        Data() { ++count; }
        ~Data() { --count; }
};

typedef Magnum::ResourceManager<Int, Data> ResourceManager;

size_t Data::count = 0;

ResourceManagerTest::ResourceManagerTest() {
    addTests({&ResourceManagerTest::state,
              &ResourceManagerTest::stateFallback,
              &ResourceManagerTest::stateDisallowed,
              &ResourceManagerTest::basic,
              &ResourceManagerTest::residentPolicy,
              &ResourceManagerTest::referenceCountedPolicy,
              &ResourceManagerTest::manualPolicy,
              &ResourceManagerTest::defaults,
              &ResourceManagerTest::clear,
              &ResourceManagerTest::clearWhileReferenced,
              &ResourceManagerTest::loader});
}

void ResourceManagerTest::state() {
    ResourceManager rm;

    Resource<Data> data = rm.get<Data>("data");
    CORRADE_VERIFY(!data);
    CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotLoaded);

    rm.set<Data>("data", nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
    CORRADE_VERIFY(!data);
    CORRADE_COMPARE(data.state(), ResourceState::Loading);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::Loading);

    rm.set<Data>("data", nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident);
    CORRADE_VERIFY(!data);
    CORRADE_COMPARE(data.state(), ResourceState::NotFound);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotFound);

    /* Nothing happened at all */
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::stateFallback() {
    {
        ResourceManager rm;
        rm.setFallback(new Data);

        Resource<Data> data = rm.get<Data>("data");
        CORRADE_VERIFY(data);
        CORRADE_COMPARE(data.state(), ResourceState::NotLoadedFallback);
        CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotLoadedFallback);

        rm.set<Data>("data", nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
        CORRADE_VERIFY(data);
        CORRADE_COMPARE(data.state(), ResourceState::LoadingFallback);
        CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::LoadingFallback);

        rm.set<Data>("data", nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident);
        CORRADE_VERIFY(data);
        CORRADE_COMPARE(data.state(), ResourceState::NotFoundFallback);
        CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotFoundFallback);

        /* Only fallback is here */
        CORRADE_COMPARE(Data::count, 1);
    }

    /* Fallback gets destroyed */
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::stateDisallowed() {
    ResourceManager rm;

    std::ostringstream out;
    Error::setOutput(&out);

    rm.set("data", Data(), ResourceDataState::Loading, ResourcePolicy::Resident);
    CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n");

    out.str({});
    rm.set<Data>("data", nullptr, ResourceDataState::Final, ResourcePolicy::Resident);
    CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n");
}

void ResourceManagerTest::basic() {
    ResourceManager rm;

    /* One mutable, one final */
    ResourceKey questionKey("the-question");
    ResourceKey answerKey("the-answer");
    rm.set(questionKey, 10, ResourceDataState::Mutable, ResourcePolicy::Resident);
    rm.set(answerKey, 42, ResourceDataState::Final, ResourcePolicy::Resident);
    Resource<Int> theQuestion = rm.get<Int>(questionKey);
    Resource<Int> theAnswer = rm.get<Int>(answerKey);

    /* Check basic functionality */
    CORRADE_COMPARE(theQuestion.state(), ResourceState::Mutable);
    CORRADE_COMPARE(theAnswer.state(), ResourceState::Final);
    CORRADE_COMPARE(*theQuestion, 10);
    CORRADE_COMPARE(*theAnswer, 42);
    CORRADE_COMPARE(rm.count<Int>(), 2);

    /* Cannot change already final resource */
    std::ostringstream out;
    Error::setOutput(&out);
    rm.set(answerKey, 43, ResourceDataState::Mutable, ResourcePolicy::Resident);
    CORRADE_COMPARE(*theAnswer, 42);
    CORRADE_COMPARE(out.str(), "ResourceManager::set(): cannot change already final resource " + answerKey.hexString() + '\n');

    /* But non-final can be changed */
    rm.set(questionKey, 20, ResourceDataState::Final, ResourcePolicy::Resident);
    CORRADE_COMPARE(theQuestion.state(), ResourceState::Final);
    CORRADE_COMPARE(*theQuestion, 20);
}

void ResourceManagerTest::residentPolicy() {
    ResourceManager* rm = new ResourceManager;

    rm->set("blah", new Data, ResourceDataState::Mutable, ResourcePolicy::Resident);
    CORRADE_COMPARE(Data::count, 1);

    rm->free();
    CORRADE_COMPARE(Data::count, 1);

    delete rm;
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::referenceCountedPolicy() {
    ResourceManager rm;

    ResourceKey dataRefCountKey("dataRefCount");

    /* Reference counted resources must be requested first */
    {
        rm.set(dataRefCountKey, new Data, ResourceDataState::Final, ResourcePolicy::ReferenceCounted);
        CORRADE_COMPARE(rm.count<Data>(), 0);
        Resource<Data> data = rm.get<Data>(dataRefCountKey);
        CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
        CORRADE_COMPARE(Data::count, 0);
    } {
        Resource<Data> data = rm.get<Data>(dataRefCountKey);
        CORRADE_COMPARE(rm.count<Data>(), 1);
        CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
        rm.set(dataRefCountKey, new Data, ResourceDataState::Final, ResourcePolicy::ReferenceCounted);
        CORRADE_COMPARE(data.state(), ResourceState::Final);
        CORRADE_COMPARE(Data::count, 1);
    }

    CORRADE_COMPARE(rm.count<Data>(), 0);
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::manualPolicy() {
    ResourceManager rm;

    ResourceKey dataKey("data");

    /* Manual free */
    {
        rm.set(dataKey, new Data, ResourceDataState::Mutable, ResourcePolicy::Manual);
        Resource<Data> data = rm.get<Data>(dataKey);
        rm.free();
    }

    CORRADE_COMPARE(rm.count<Data>(), 1);
    CORRADE_COMPARE(Data::count, 1);
    rm.free();
    CORRADE_COMPARE(rm.count<Data>(), 0);
    CORRADE_COMPARE(Data::count, 0);

    rm.set(dataKey, new Data, ResourceDataState::Mutable, ResourcePolicy::Manual);
    CORRADE_COMPARE(rm.count<Data>(), 1);
    CORRADE_COMPARE(Data::count, 1);
}

void ResourceManagerTest::defaults() {
    ResourceManager rm;
    rm.set("data", new Data);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::Final);
}

void ResourceManagerTest::clear() {
    ResourceManager rm;

    rm.set("blah", new Data);
    CORRADE_COMPARE(Data::count, 1);

    rm.free();
    CORRADE_COMPARE(Data::count, 1);

    rm.clear();
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::clearWhileReferenced() {
    /* Should cover also the destruction case */

    std::ostringstream out;
    Error::setOutput(&out);

    ResourceManager rm;
    rm.set("blah", Int());
    /** @todo this will leak, is there any better solution without hitting
        assertion in decrementReferenceCount()? */
    new Resource<Int>(rm.get<Int>("blah"));

    rm.clear();
    CORRADE_COMPARE(out.str(), "ResourceManager: cleared/destroyed while data are still referenced\n");
}

void ResourceManagerTest::loader() {
    class IntResourceLoader: public AbstractResourceLoader<Int> {
        public:
            IntResourceLoader(): resource(ResourceManager::instance().get<Data>("data")) {}

            void load() {
                set("hello", 773, ResourceDataState::Final, ResourcePolicy::Resident);
                setNotFound("world");
            }

        private:
            void doLoad(ResourceKey) override {}

            std::string doName(ResourceKey key) const override {
                if(key == ResourceKey("hello")) return "hello";
                return "";
            }

            /* To verify that the loader is destroyed before unloading
               _all types of_ resources */
            Resource<Data> resource;
    };

    auto rm = new ResourceManager;
    auto loader = new IntResourceLoader;
    rm->setLoader(loader);

    {
        Resource<Data> data = rm->get<Data>("data");
        Resource<Int> hello = rm->get<Int>("hello");
        Resource<Int> world = rm->get<Int>("world");
        CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
        CORRADE_COMPARE(hello.state(), ResourceState::Loading);
        CORRADE_COMPARE(world.state(), ResourceState::Loading);

        CORRADE_COMPARE(loader->requestedCount(), 2);
        CORRADE_COMPARE(loader->loadedCount(), 0);
        CORRADE_COMPARE(loader->notFoundCount(), 0);
        CORRADE_COMPARE(loader->name(ResourceKey("hello")), "hello");

        loader->load();
        CORRADE_COMPARE(hello.state(), ResourceState::Final);
        CORRADE_COMPARE(*hello, 773);
        CORRADE_COMPARE(world.state(), ResourceState::NotFound);

        CORRADE_COMPARE(loader->requestedCount(), 2);
        CORRADE_COMPARE(loader->loadedCount(), 1);
        CORRADE_COMPARE(loader->notFoundCount(), 1);

        /* Verify that the loader is deleted at proper time */
        rm->set("data", new Data);
        CORRADE_COMPARE(Data::count, 1);
    }

    delete rm;
    CORRADE_COMPARE(Data::count, 0);
}

}}

CORRADE_TEST_MAIN(Magnum::Test::ResourceManagerTest)
<commit_msg>Test cleanup.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <sstream>
#include <Corrade/TestSuite/Tester.h>

#include "Magnum/AbstractResourceLoader.h"
#include "Magnum/ResourceManager.h"

namespace Magnum { namespace Test {

struct ResourceManagerTest: TestSuite::Tester {
    explicit ResourceManagerTest();

    void state();
    void stateFallback();
    void stateDisallowed();
    void basic();
    void residentPolicy();
    void referenceCountedPolicy();
    void manualPolicy();
    void defaults();
    void clear();
    void clearWhileReferenced();
    void loader();
};

struct Data {
    static std::size_t count;

    explicit Data() { ++count; }
    ~Data() { --count; }
};

typedef Magnum::ResourceManager<Int, Data> ResourceManager;

size_t Data::count = 0;

ResourceManagerTest::ResourceManagerTest() {
    addTests({&ResourceManagerTest::state,
              &ResourceManagerTest::stateFallback,
              &ResourceManagerTest::stateDisallowed,
              &ResourceManagerTest::basic,
              &ResourceManagerTest::residentPolicy,
              &ResourceManagerTest::referenceCountedPolicy,
              &ResourceManagerTest::manualPolicy,
              &ResourceManagerTest::defaults,
              &ResourceManagerTest::clear,
              &ResourceManagerTest::clearWhileReferenced,
              &ResourceManagerTest::loader});
}

void ResourceManagerTest::state() {
    ResourceManager rm;

    Resource<Data> data = rm.get<Data>("data");
    CORRADE_VERIFY(!data);
    CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotLoaded);

    rm.set<Data>("data", nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
    CORRADE_VERIFY(!data);
    CORRADE_COMPARE(data.state(), ResourceState::Loading);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::Loading);

    rm.set<Data>("data", nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident);
    CORRADE_VERIFY(!data);
    CORRADE_COMPARE(data.state(), ResourceState::NotFound);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotFound);

    /* Nothing happened at all */
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::stateFallback() {
    {
        ResourceManager rm;
        rm.setFallback(new Data);

        Resource<Data> data = rm.get<Data>("data");
        CORRADE_VERIFY(data);
        CORRADE_COMPARE(data.state(), ResourceState::NotLoadedFallback);
        CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotLoadedFallback);

        rm.set<Data>("data", nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
        CORRADE_VERIFY(data);
        CORRADE_COMPARE(data.state(), ResourceState::LoadingFallback);
        CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::LoadingFallback);

        rm.set<Data>("data", nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident);
        CORRADE_VERIFY(data);
        CORRADE_COMPARE(data.state(), ResourceState::NotFoundFallback);
        CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotFoundFallback);

        /* Only fallback is here */
        CORRADE_COMPARE(Data::count, 1);
    }

    /* Fallback gets destroyed */
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::stateDisallowed() {
    ResourceManager rm;

    std::ostringstream out;
    Error::setOutput(&out);

    rm.set("data", Data(), ResourceDataState::Loading, ResourcePolicy::Resident);
    CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n");

    out.str({});
    rm.set<Data>("data", nullptr, ResourceDataState::Final, ResourcePolicy::Resident);
    CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n");
}

void ResourceManagerTest::basic() {
    ResourceManager rm;

    /* One mutable, one final */
    ResourceKey questionKey("the-question");
    ResourceKey answerKey("the-answer");
    rm.set(questionKey, 10, ResourceDataState::Mutable, ResourcePolicy::Resident);
    rm.set(answerKey, 42, ResourceDataState::Final, ResourcePolicy::Resident);
    Resource<Int> theQuestion = rm.get<Int>(questionKey);
    Resource<Int> theAnswer = rm.get<Int>(answerKey);

    /* Check basic functionality */
    CORRADE_COMPARE(theQuestion.state(), ResourceState::Mutable);
    CORRADE_COMPARE(theAnswer.state(), ResourceState::Final);
    CORRADE_COMPARE(*theQuestion, 10);
    CORRADE_COMPARE(*theAnswer, 42);
    CORRADE_COMPARE(rm.count<Int>(), 2);

    /* Cannot change already final resource */
    std::ostringstream out;
    Error::setOutput(&out);
    rm.set(answerKey, 43, ResourceDataState::Mutable, ResourcePolicy::Resident);
    CORRADE_COMPARE(*theAnswer, 42);
    CORRADE_COMPARE(out.str(), "ResourceManager::set(): cannot change already final resource " + answerKey.hexString() + '\n');

    /* But non-final can be changed */
    rm.set(questionKey, 20, ResourceDataState::Final, ResourcePolicy::Resident);
    CORRADE_COMPARE(theQuestion.state(), ResourceState::Final);
    CORRADE_COMPARE(*theQuestion, 20);
}

void ResourceManagerTest::residentPolicy() {
    ResourceManager* rm = new ResourceManager;

    rm->set("blah", new Data, ResourceDataState::Mutable, ResourcePolicy::Resident);
    CORRADE_COMPARE(Data::count, 1);

    rm->free();
    CORRADE_COMPARE(Data::count, 1);

    delete rm;
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::referenceCountedPolicy() {
    ResourceManager rm;

    ResourceKey dataRefCountKey("dataRefCount");

    /* Reference counted resources must be requested first */
    {
        rm.set(dataRefCountKey, new Data, ResourceDataState::Final, ResourcePolicy::ReferenceCounted);
        CORRADE_COMPARE(rm.count<Data>(), 0);
        Resource<Data> data = rm.get<Data>(dataRefCountKey);
        CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
        CORRADE_COMPARE(Data::count, 0);
    } {
        Resource<Data> data = rm.get<Data>(dataRefCountKey);
        CORRADE_COMPARE(rm.count<Data>(), 1);
        CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
        rm.set(dataRefCountKey, new Data, ResourceDataState::Final, ResourcePolicy::ReferenceCounted);
        CORRADE_COMPARE(data.state(), ResourceState::Final);
        CORRADE_COMPARE(Data::count, 1);
    }

    CORRADE_COMPARE(rm.count<Data>(), 0);
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::manualPolicy() {
    ResourceManager rm;

    ResourceKey dataKey("data");

    /* Manual free */
    {
        rm.set(dataKey, new Data, ResourceDataState::Mutable, ResourcePolicy::Manual);
        Resource<Data> data = rm.get<Data>(dataKey);
        rm.free();
    }

    CORRADE_COMPARE(rm.count<Data>(), 1);
    CORRADE_COMPARE(Data::count, 1);
    rm.free();
    CORRADE_COMPARE(rm.count<Data>(), 0);
    CORRADE_COMPARE(Data::count, 0);

    rm.set(dataKey, new Data, ResourceDataState::Mutable, ResourcePolicy::Manual);
    CORRADE_COMPARE(rm.count<Data>(), 1);
    CORRADE_COMPARE(Data::count, 1);
}

void ResourceManagerTest::defaults() {
    ResourceManager rm;
    rm.set("data", new Data);
    CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::Final);
}

void ResourceManagerTest::clear() {
    ResourceManager rm;

    rm.set("blah", new Data);
    CORRADE_COMPARE(Data::count, 1);

    rm.free();
    CORRADE_COMPARE(Data::count, 1);

    rm.clear();
    CORRADE_COMPARE(Data::count, 0);
}

void ResourceManagerTest::clearWhileReferenced() {
    /* Should cover also the destruction case */

    std::ostringstream out;
    Error::setOutput(&out);

    ResourceManager rm;
    rm.set("blah", Int());
    /** @todo this will leak, is there any better solution without hitting
        assertion in decrementReferenceCount()? */
    new Resource<Int>(rm.get<Int>("blah"));

    rm.clear();
    CORRADE_COMPARE(out.str(), "ResourceManager: cleared/destroyed while data are still referenced\n");
}

void ResourceManagerTest::loader() {
    class IntResourceLoader: public AbstractResourceLoader<Int> {
        public:
            IntResourceLoader(): resource(ResourceManager::instance().get<Data>("data")) {}

            void load() {
                set("hello", 773, ResourceDataState::Final, ResourcePolicy::Resident);
                setNotFound("world");
            }

        private:
            void doLoad(ResourceKey) override {}

            std::string doName(ResourceKey key) const override {
                if(key == ResourceKey("hello")) return "hello";
                return "";
            }

            /* To verify that the loader is destroyed before unloading
               _all types of_ resources */
            Resource<Data> resource;
    };

    auto rm = new ResourceManager;
    auto loader = new IntResourceLoader;
    rm->setLoader(loader);

    {
        Resource<Data> data = rm->get<Data>("data");
        Resource<Int> hello = rm->get<Int>("hello");
        Resource<Int> world = rm->get<Int>("world");
        CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
        CORRADE_COMPARE(hello.state(), ResourceState::Loading);
        CORRADE_COMPARE(world.state(), ResourceState::Loading);

        CORRADE_COMPARE(loader->requestedCount(), 2);
        CORRADE_COMPARE(loader->loadedCount(), 0);
        CORRADE_COMPARE(loader->notFoundCount(), 0);
        CORRADE_COMPARE(loader->name(ResourceKey("hello")), "hello");

        loader->load();
        CORRADE_COMPARE(hello.state(), ResourceState::Final);
        CORRADE_COMPARE(*hello, 773);
        CORRADE_COMPARE(world.state(), ResourceState::NotFound);

        CORRADE_COMPARE(loader->requestedCount(), 2);
        CORRADE_COMPARE(loader->loadedCount(), 1);
        CORRADE_COMPARE(loader->notFoundCount(), 1);

        /* Verify that the loader is deleted at proper time */
        rm->set("data", new Data);
        CORRADE_COMPARE(Data::count, 1);
    }

    delete rm;
    CORRADE_COMPARE(Data::count, 0);
}

}}

CORRADE_TEST_MAIN(Magnum::Test::ResourceManagerTest)
<|endoftext|>


<commit_before>/*
 * =====================================================================================
 *
 *       Filename:  3.cpp
 *
 *    Description:  Solution to the third problem of the `evens' section.
 *
 *        Version:  1.0
 *        Created:  28.01.2015  6,00,07
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Radoslav Georgiev (sid), rgeorgiev583@gmail.com
 *        Company:  Faculty of Mathematics and Informatics at Sofia University
 *
 * =====================================================================================
 */

#include <iostream>
#include <cstring>

using namespace std;

const int MAX_SIZE = 1000;
const char diff = 'a' - 'A';

bool isWordChar(char c)
{
    return c == '(' || c == ')' || c == '-' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
}

const char* skipWhitespaceReverse(const char* s)
{
    while (*s == ' ')
        s--;

    return s;
}

const char* goToEnd(const char* s)
{
    while (*s)
        s++;

    return s;
}

char toUpper(char c)
{
    return c >= 'a' && c <= 'z' ? c - diff : c;
}

char toLower(char c)
{
    return c >= 'A' && c <= 'Z' ? c + diff : c;
}

void swap(char* a, char* b)
{
    char x = *a;
    *a = *b;
    *b = x;
}

// Ако изречението е невалидно, връщаме NULL
char* reverseSentence(char* rev, const char* s)
{
    if (!s)
        return NULL;

    const char* end = goToEnd(s);
    end--;

    if (end < s || *end != '!' && *end != '.' && *end != '?')
        return NULL;

    end--;

    const char* beg = end;
    bool is_first = true;

    while (beg >= s)
    {
        while (beg >= s && isWordChar(*beg))
            beg--;

        if (beg == end)
            return NULL;

        beg++;

        if (beg < s)
        {
            char first[2];
            strncat(first, beg, 1);
            *first = toLower(*first);
            strcat(rev, first);
            strncat(rev, beg + 1, end - beg);
        }
        else
        {
            strncat(rev, beg, end - beg + 1);
            end = beg - 1;

            if (*end != ' ')
                return NULL;

            end--;

            if (end < s)
                return NULL;

            if (*end == ',' || *end == ':' || *end == ';')
                strncat(rev, end, 1);

            strncat(rev, end + 1, 1);
        }
    }

    *rev = toUpper(*rev);
    char *p = rev, *lp = NULL;
    int b = 0;

    while (p)
    {
        if (*p == '(')
        {
            b++;

            if (lp && b == 0)
            {
                swap(p, lp);
                lp = NULL;
            }
        }
        else if (*p == ')')
        {
            b--;

            if (b == -1)
                lp = p;
        }

        p++;
    }

    return rev;
}

int main()
{
    char s[MAX_SIZE], rev[MAX_SIZE];
    cin.getline(s, MAX_SIZE);

    cout << reverseSentence(rev, s) << endl;

    return 0;
}
<commit_msg>adjusted beginning and end pointers<commit_after>/*
 * =====================================================================================
 *
 *       Filename:  3.cpp
 *
 *    Description:  Solution to the third problem of the `evens' section.
 *
 *        Version:  1.0
 *        Created:  28.01.2015  6,00,07
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Radoslav Georgiev (sid), rgeorgiev583@gmail.com
 *        Company:  Faculty of Mathematics and Informatics at Sofia University
 *
 * =====================================================================================
 */

#include <iostream>
#include <cstring>

using namespace std;

const int MAX_SIZE = 1000;
const char diff = 'a' - 'A';

bool isWordChar(char c)
{
    return c == '(' || c == ')' || c == '-' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
}

const char* skipWhitespaceReverse(const char* s)
{
    while (*s == ' ')
        s--;

    return s;
}

const char* goToEnd(const char* s)
{
    while (*s)
        s++;

    return s;
}

char toUpper(char c)
{
    return c >= 'a' && c <= 'z' ? c - diff : c;
}

char toLower(char c)
{
    return c >= 'A' && c <= 'Z' ? c + diff : c;
}

void swap(char* a, char* b)
{
    char x = *a;
    *a = *b;
    *b = x;
}

// Ако изречението е невалидно, връщаме NULL
char* reverseSentence(char* rev, const char* s)
{
    if (!s)
        return NULL;

    const char* end = goToEnd(s);
    end--;

    if (end < s || *end != '!' && *end != '.' && *end != '?')
        return NULL;

    end--;

    do
    {
        const char* beg = end;

        while (beg >= s && isWordChar(*beg))
            beg--;

        if (beg == end)
            return NULL;

        if (beg++ < s)
        {
            char first[2];
            strncat(first, beg, 1);
            *first = toLower(*first);
            strcat(rev, first);
            strncat(rev, beg + 1, end - beg);
            end = beg - 1;
        }
        else
        {
            strncat(rev, beg, end - beg + 1);
            end = beg - 1;

            if (*end != ' ')
                return NULL;

            end--;

            if (end < s)
                return NULL;

            if (*end == ',' || *end == ':' || *end == ';')
                strncat(rev, end, 1);

            strncat(rev, end + 1, 1);
            end--;
        }
    }
    while (end >= s);

    *rev = toUpper(*rev);
    char *p = rev, *lp = NULL;
    int b = 0;

    while (p)
    {
        if (*p == '(')
        {
            b++;

            if (lp && b == 0)
            {
                swap(p, lp);
                lp = NULL;
            }
        }
        else if (*p == ')')
        {
            b--;

            if (b == -1)
                lp = p;
        }

        p++;
    }

    return rev;
}

int main()
{
    char s[MAX_SIZE], rev[MAX_SIZE];
    cin.getline(s, MAX_SIZE);

    cout << reverseSentence(rev, s) << endl;

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "renderer/atom_renderer_client.h"

#include <algorithm>

#include "base/command_line.h"
#include "common/node_bindings.h"
#include "common/options_switches.h"
#include "renderer/api/atom_renderer_bindings.h"
#include "renderer/atom_render_view_observer.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"

#include "common/v8/node_common.h"

namespace atom {

namespace {

// Security tokens.
const char* kExceptIframe = "except-iframe";
const char* kManualEnableIframe = "manual-enable-iframe";
const char* kDisable = "disable";
const char* kEnableNodeIntegration = "enable-node-integration";

// Scheme used by devtools
const char* kChromeDevToolsScheme = "chrome-devtools";

}  // namespace

AtomRendererClient::AtomRendererClient()
    : node_integration_(ALL),
      main_frame_(NULL) {
  // Translate the token.
  std::string token = CommandLine::ForCurrentProcess()->
      GetSwitchValueASCII(switches::kNodeIntegration);
  if (token == kExceptIframe)
    node_integration_ = EXCEPT_IFRAME;
  else if (token == kManualEnableIframe)
    node_integration_ = MANUAL_ENABLE_IFRAME;
  else if (token == kDisable)
    node_integration_ = DISABLE;

  if (IsNodeBindingEnabled()) {
    node_bindings_.reset(NodeBindings::Create(false));
    atom_bindings_.reset(new AtomRendererBindings);
  }
}

AtomRendererClient::~AtomRendererClient() {
}

void AtomRendererClient::RenderThreadStarted() {
  if (!IsNodeBindingEnabled())
    return;

  node_bindings_->Initialize();
  node_bindings_->PrepareMessageLoop();

  DCHECK(!global_env);

  // Create a default empty environment which would be used when we need to
  // run V8 code out of a window context (like running a uv callback).
  v8::HandleScope handle_scope(node_isolate);
  v8::Local<v8::Context> context = v8::Context::New(node_isolate);
  global_env = node::Environment::New(context);
}

void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) {
  new AtomRenderViewObserver(render_view, this);
}

void AtomRendererClient::DidCreateScriptContext(WebKit::WebFrame* frame,
                                                v8::Handle<v8::Context> context,
                                                int extension_group,
                                                int world_id) {
  // The first web frame is the main frame.
  if (main_frame_ == NULL)
    main_frame_ = frame;

  if (!IsNodeBindingEnabled(frame))
    return;

  v8::Context::Scope scope(context);

  // Check the existance of process object to prevent duplicate initialization.
  if (context->Global()->Has(v8::String::New("process")))
    return;

  // Give the node loop a run to make sure everything is ready.
  node_bindings_->RunMessageLoop();

  // Setup node environment for each window.
  node::Environment* env = node_bindings_->CreateEnvironment(context);

  // Add atom-shell extended APIs.
  atom_bindings_->BindToFrame(frame);

  // Store the created environment.
  web_page_envs_.push_back(env);

  // Make uv loop being wrapped by window context.
  if (node_bindings_->uv_env() == NULL)
    node_bindings_->set_uv_env(env);
}

void AtomRendererClient::WillReleaseScriptContext(
    WebKit::WebFrame* frame,
    v8::Handle<v8::Context> context,
    int world_id) {
  if (!IsNodeBindingEnabled(frame))
    return;

  node::Environment* env = node::Environment::GetCurrent(context);
  if (env == NULL) {
    LOG(ERROR) << "Encounter a non-node context when releasing script context";
    return;
  }

  // Clear the environment.
  web_page_envs_.erase(
      std::remove(web_page_envs_.begin(), web_page_envs_.end(), env),
      web_page_envs_.end());

  // Notice that we are not disposing the environment object here, because there
  // may still be pending uv operations in the uv loop, and when they got done
  // they would be needing the original environment.
  // So we are leaking the environment object here, just like Chrome leaking the
  // memory :) . Since it's only leaked when refreshing or unloading, so as long
  // as we make sure renderer process is restared then the memory would not be
  // leaked.
  // env->Dispose();

  // Wrap the uv loop with another environment.
  if (env == node_bindings_->uv_env()) {
    node::Environment* env = web_page_envs_.size() > 0 ? web_page_envs_[0] :
                                                         NULL;
    node_bindings_->set_uv_env(env);
  }
}

bool AtomRendererClient::ShouldFork(WebKit::WebFrame* frame,
                                    const GURL& url,
                                    const std::string& http_method,
                                    bool is_initial_navigation,
                                    bool is_server_redirect,
                                    bool* send_referrer) {
  // Handle all the navigations and reloads in browser.
  return true;
}

bool AtomRendererClient::IsNodeBindingEnabled(WebKit::WebFrame* frame) {
  if (node_integration_ == DISABLE)
    return false;
  // Node integration is enabled in main frame unless explictly disabled.
  else if (frame == main_frame_)
    return true;
  // Do not pollute devtools.
  else if (GURL(frame->document().url()).SchemeIs(kChromeDevToolsScheme))
    return false;
  else if (node_integration_ == MANUAL_ENABLE_IFRAME &&
           frame != NULL &&
           frame->uniqueName().utf8().find(kEnableNodeIntegration)
               == std::string::npos)
    return false;
  else if (node_integration_ == EXCEPT_IFRAME && frame != NULL)
    return false;
  else
    return true;
}

}  // namespace atom
<commit_msg>Fix polluting devtools in some cases.<commit_after>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "renderer/atom_renderer_client.h"

#include <algorithm>

#include "base/command_line.h"
#include "common/node_bindings.h"
#include "common/options_switches.h"
#include "renderer/api/atom_renderer_bindings.h"
#include "renderer/atom_render_view_observer.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"

#include "common/v8/node_common.h"

namespace atom {

namespace {

// Security tokens.
const char* kExceptIframe = "except-iframe";
const char* kManualEnableIframe = "manual-enable-iframe";
const char* kDisable = "disable";
const char* kEnableNodeIntegration = "enable-node-integration";

// Scheme used by devtools
const char* kChromeDevToolsScheme = "chrome-devtools";

}  // namespace

AtomRendererClient::AtomRendererClient()
    : node_integration_(ALL),
      main_frame_(NULL) {
  // Translate the token.
  std::string token = CommandLine::ForCurrentProcess()->
      GetSwitchValueASCII(switches::kNodeIntegration);
  if (token == kExceptIframe)
    node_integration_ = EXCEPT_IFRAME;
  else if (token == kManualEnableIframe)
    node_integration_ = MANUAL_ENABLE_IFRAME;
  else if (token == kDisable)
    node_integration_ = DISABLE;

  if (IsNodeBindingEnabled()) {
    node_bindings_.reset(NodeBindings::Create(false));
    atom_bindings_.reset(new AtomRendererBindings);
  }
}

AtomRendererClient::~AtomRendererClient() {
}

void AtomRendererClient::RenderThreadStarted() {
  if (!IsNodeBindingEnabled())
    return;

  node_bindings_->Initialize();
  node_bindings_->PrepareMessageLoop();

  DCHECK(!global_env);

  // Create a default empty environment which would be used when we need to
  // run V8 code out of a window context (like running a uv callback).
  v8::HandleScope handle_scope(node_isolate);
  v8::Local<v8::Context> context = v8::Context::New(node_isolate);
  global_env = node::Environment::New(context);
}

void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) {
  new AtomRenderViewObserver(render_view, this);
}

void AtomRendererClient::DidCreateScriptContext(WebKit::WebFrame* frame,
                                                v8::Handle<v8::Context> context,
                                                int extension_group,
                                                int world_id) {
  // The first web frame is the main frame.
  if (main_frame_ == NULL)
    main_frame_ = frame;

  if (!IsNodeBindingEnabled(frame))
    return;

  v8::Context::Scope scope(context);

  // Check the existance of process object to prevent duplicate initialization.
  if (context->Global()->Has(v8::String::New("process")))
    return;

  // Give the node loop a run to make sure everything is ready.
  node_bindings_->RunMessageLoop();

  // Setup node environment for each window.
  node::Environment* env = node_bindings_->CreateEnvironment(context);

  // Add atom-shell extended APIs.
  atom_bindings_->BindToFrame(frame);

  // Store the created environment.
  web_page_envs_.push_back(env);

  // Make uv loop being wrapped by window context.
  if (node_bindings_->uv_env() == NULL)
    node_bindings_->set_uv_env(env);
}

void AtomRendererClient::WillReleaseScriptContext(
    WebKit::WebFrame* frame,
    v8::Handle<v8::Context> context,
    int world_id) {
  if (!IsNodeBindingEnabled(frame))
    return;

  node::Environment* env = node::Environment::GetCurrent(context);
  if (env == NULL) {
    LOG(ERROR) << "Encounter a non-node context when releasing script context";
    return;
  }

  // Clear the environment.
  web_page_envs_.erase(
      std::remove(web_page_envs_.begin(), web_page_envs_.end(), env),
      web_page_envs_.end());

  // Notice that we are not disposing the environment object here, because there
  // may still be pending uv operations in the uv loop, and when they got done
  // they would be needing the original environment.
  // So we are leaking the environment object here, just like Chrome leaking the
  // memory :) . Since it's only leaked when refreshing or unloading, so as long
  // as we make sure renderer process is restared then the memory would not be
  // leaked.
  // env->Dispose();

  // Wrap the uv loop with another environment.
  if (env == node_bindings_->uv_env()) {
    node::Environment* env = web_page_envs_.size() > 0 ? web_page_envs_[0] :
                                                         NULL;
    node_bindings_->set_uv_env(env);
  }
}

bool AtomRendererClient::ShouldFork(WebKit::WebFrame* frame,
                                    const GURL& url,
                                    const std::string& http_method,
                                    bool is_initial_navigation,
                                    bool is_server_redirect,
                                    bool* send_referrer) {
  // Handle all the navigations and reloads in browser.
  return true;
}

bool AtomRendererClient::IsNodeBindingEnabled(WebKit::WebFrame* frame) {
  if (node_integration_ == DISABLE)
    return false;
  // Do not pollute devtools.
  else if (frame != NULL &&
           GURL(frame->document().url()).SchemeIs(kChromeDevToolsScheme))
    return false;
  // Node integration is enabled in main frame unless explictly disabled.
  else if (frame == main_frame_)
    return true;
  else if (node_integration_ == MANUAL_ENABLE_IFRAME &&
           frame != NULL &&
           frame->uniqueName().utf8().find(kEnableNodeIntegration)
               == std::string::npos)
    return false;
  else if (node_integration_ == EXCEPT_IFRAME && frame != NULL)
    return false;
  else
    return true;
}

}  // namespace atom
<|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TStopwatch.cxx,v 1.1.1.1 2000/05/16 17:00:39 rdm Exp $
// Author: Fons Rademakers   11/10/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStopwatch                                                           //
//                                                                      //
// Stopwatch class. This class returns the real and cpu time between    //
// the start and stop events.                                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TStopwatch.h"
#include "TString.h"

#if defined(R__MAC)
#   include <time.h>
static clock_t gTicks = CLOCKS_PER_SEC;
#elif defined(R__UNIX)
#   include <sys/times.h>
#   include <unistd.h>
static clock_t gTicks = 0;
#elif defined(R__VMS)
#   include <time.h>
#   include <unistd.h>
static clock_t gTicks = 1000;
#elif defined(WIN32)
#include "TError.h"
    const Double_t gTicks = 1.0e-7;
#include "Windows4Root.h"
#endif

ClassImp(TStopwatch)

//______________________________________________________________________________
TStopwatch::TStopwatch()
{
   // Create a stopwatch and start it.

#ifdef R__UNIX
//printf("Tstopwatch constructor0 gTicks=%d\n",gTicks);
   if (!gTicks) gTicks = (clock_t)sysconf(_SC_CLK_TCK);
//printf("Tstopwatch constructor gTicks=%d\n",gTicks);
#endif
   fState         = kUndefined;
   fTotalCpuTime  = 0;
   fTotalRealTime = 0;
   fCounter       = 0;
   Start();
}

//______________________________________________________________________________
void TStopwatch::Start(Bool_t reset)
{
   // Start the stopwatch. If reset is kTRUE reset the stopwatch before
   // starting it (including the stopwatch counter).
   // Use kFALSE to continue timing after a Stop() without
   // resetting the stopwatch.

   if (reset) {
      fTotalCpuTime  = 0;
      fTotalRealTime = 0;
      fCounter       = 0;
   }
   if (fState != kRunning) {
#ifndef R__UNIX
      fStartRealTime = GetRealTime();
      fStartCpuTime  = GetCPUTime();
#else
      struct tms cpt;
      fStartRealTime = (Double_t)times(&cpt) / gTicks;
      fStartCpuTime  = (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#endif
   }
   fState = kRunning;
   fCounter++;
}

//______________________________________________________________________________
void TStopwatch::Stop()
{
   // Stop the stopwatch.

#ifndef R__UNIX
   fStopRealTime = GetRealTime();
   fStopCpuTime  = GetCPUTime();
#else
   struct tms cpt;
   fStopRealTime = (Double_t)times(&cpt) / gTicks;
   fStopCpuTime  = (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#endif
   if (fState == kRunning) {
      fTotalCpuTime  += fStopCpuTime  - fStartCpuTime;
      fTotalRealTime += fStopRealTime - fStartRealTime;
   }
   fState = kStopped;
}

//______________________________________________________________________________
void TStopwatch::Continue()
{
   // Resume a stopped stopwatch. The stopwatch continues counting from the last
   // Start() onwards (this is like the laptimer function).

   if (fState == kUndefined)
      Error("Continue", "stopwatch not started");

   if (fState == kStopped) {
      fTotalCpuTime  -= fStopCpuTime  - fStartCpuTime;
      fTotalRealTime -= fStopRealTime - fStartRealTime;
   }

   fState = kRunning;
}

//______________________________________________________________________________
Double_t TStopwatch::RealTime()
{
   // Return the realtime passed between the start and stop events. If the
   // stopwatch was still running stop it first.

   if (fState == kUndefined)
      Error("RealTime", "stopwatch not started");

   if (fState == kRunning)
      Stop();

   return fTotalRealTime;
}

//______________________________________________________________________________
Double_t TStopwatch::CpuTime()
{
   // Return the cputime passed between the start and stop events. If the
   // stopwatch was still running stop it first.

   if (fState == kUndefined)
      Error("RealTime", "stopwatch not started");

   if (fState == kRunning)
      Stop();

   return fTotalCpuTime;
}

//______________________________________________________________________________
Double_t TStopwatch::GetRealTime(){
#if defined(R__MAC)
   return(Double_t)clock() / gTicks;
#elif defined(R__UNIX)
   struct tms cpt;
   Double_t trt =  (Double_t)times(&cpt);
printf("GetRealTime: trt=%g, gTicks=%d\n",trt,gTicks);
   return trt / (double)gTicks;
#elif defined(R__VMS)
  return(Double_t)clock()/gTicks;
#elif defined(WIN32)
  union     {FILETIME ftFileTime;
             __int64  ftInt64;
            } ftRealTime; // time the process has spent in kernel mode
  SYSTEMTIME st;
  GetSystemTime(&st);
  SystemTimeToFileTime(&st,&ftRealTime.ftFileTime);
  return (Double_t)ftRealTime.ftInt64 * gTicks;
#endif
}

//______________________________________________________________________________
Double_t TStopwatch::GetCPUTime(){
#if defined(R__MAC)
   return(Double_t)clock() / gTicks;
#elif defined(R__UNIX)
   struct tms cpt;
   times(&cpt);
   return (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#elif defined(R__VMS)
   return(Double_t)clock()/gTicks;
#elif defined(WIN32)

  OSVERSIONINFO OsVersionInfo;

//*-*         Value                      Platform
//*-*  ----------------------------------------------------
//*-*  VER_PLATFORM_WIN32s          Win32s on Windows 3.1
//*-*  VER_PLATFORM_WIN32_WINDOWS       Win32 on Windows 95
//*-*  VER_PLATFORM_WIN32_NT            Windows NT
//*-*
  OsVersionInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
  GetVersionEx(&OsVersionInfo);
  if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
    DWORD       ret;
    FILETIME    ftCreate,       // when the process was created
                ftExit;         // when the process exited

    union     {FILETIME ftFileTime;
               __int64  ftInt64;
              } ftKernel; // time the process has spent in kernel mode

    union     {FILETIME ftFileTime;
               __int64  ftInt64;
              } ftUser;   // time the process has spent in user mode

    HANDLE hProcess = GetCurrentProcess();
    ret = GetProcessTimes (hProcess, &ftCreate, &ftExit,
                                     &ftKernel.ftFileTime,
                                     &ftUser.ftFileTime);
    if (ret != TRUE){
      ret = GetLastError ();
      ::Error ("GetCPUTime", " Error on GetProcessTimes 0x%lx", (int)ret);
    }

    /*
     * Process times are returned in a 64-bit structure, as the number of
     * 100 nanosecond ticks since 1 January 1601.  User mode and kernel mode
     * times for this process are in separate 64-bit structures.
     * To convert to floating point seconds, we will:
     *
     *          Convert sum of high 32-bit quantities to 64-bit int
     */

      return (Double_t) (ftKernel.ftInt64 + ftUser.ftInt64) * gTicks;
  }
  else
      return GetRealTime();

#endif
}

//______________________________________________________________________________
void TStopwatch::Print(Option_t *)
{
   // Print the real and cpu time passed between the start and stop events.
   // and the number of times (slices) this TStopwatch was called
   // (if this number > 1)

   Double_t  realt = RealTime();

   Int_t  hours = Int_t(realt / 3600);
   realt -= hours * 3600;
   Int_t  min   = Int_t(realt / 60);
   realt -= min * 60;
   Int_t  sec   = Int_t(realt);
   Int_t counter = Counter();
   if (counter <= 1 )
      Printf("Real time %d:%d:%d, CP time %.3f", hours, min, sec, CpuTime());
   else
      Printf("Real time %d:%d:%d, CP time %.3f, %d slices", hours, min, sec, CpuTime(),counter);
}

<commit_msg>Remove a printf statement in GetRealTime<commit_after>// @(#)root/base:$Name:  $:$Id: TStopwatch.cxx,v 1.2 2000/06/22 14:34:08 brun Exp $
// Author: Fons Rademakers   11/10/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStopwatch                                                           //
//                                                                      //
// Stopwatch class. This class returns the real and cpu time between    //
// the start and stop events.                                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TStopwatch.h"
#include "TString.h"

#if defined(R__MAC)
#   include <time.h>
static clock_t gTicks = CLOCKS_PER_SEC;
#elif defined(R__UNIX)
#   include <sys/times.h>
#   include <unistd.h>
static clock_t gTicks = 0;
#elif defined(R__VMS)
#   include <time.h>
#   include <unistd.h>
static clock_t gTicks = 1000;
#elif defined(WIN32)
#include "TError.h"
    const Double_t gTicks = 1.0e-7;
#include "Windows4Root.h"
#endif

ClassImp(TStopwatch)

//______________________________________________________________________________
TStopwatch::TStopwatch()
{
   // Create a stopwatch and start it.

#ifdef R__UNIX
   if (!gTicks) gTicks = (clock_t)sysconf(_SC_CLK_TCK);
#endif
   fState         = kUndefined;
   fTotalCpuTime  = 0;
   fTotalRealTime = 0;
   fCounter       = 0;
   Start();
}

//______________________________________________________________________________
void TStopwatch::Start(Bool_t reset)
{
   // Start the stopwatch. If reset is kTRUE reset the stopwatch before
   // starting it (including the stopwatch counter).
   // Use kFALSE to continue timing after a Stop() without
   // resetting the stopwatch.

   if (reset) {
      fTotalCpuTime  = 0;
      fTotalRealTime = 0;
      fCounter       = 0;
   }
   if (fState != kRunning) {
#ifndef R__UNIX
      fStartRealTime = GetRealTime();
      fStartCpuTime  = GetCPUTime();
#else
      struct tms cpt;
      fStartRealTime = (Double_t)times(&cpt) / gTicks;
      fStartCpuTime  = (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#endif
   }
   fState = kRunning;
   fCounter++;
}

//______________________________________________________________________________
void TStopwatch::Stop()
{
   // Stop the stopwatch.

#ifndef R__UNIX
   fStopRealTime = GetRealTime();
   fStopCpuTime  = GetCPUTime();
#else
   struct tms cpt;
   fStopRealTime = (Double_t)times(&cpt) / gTicks;
   fStopCpuTime  = (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#endif
   if (fState == kRunning) {
      fTotalCpuTime  += fStopCpuTime  - fStartCpuTime;
      fTotalRealTime += fStopRealTime - fStartRealTime;
   }
   fState = kStopped;
}

//______________________________________________________________________________
void TStopwatch::Continue()
{
   // Resume a stopped stopwatch. The stopwatch continues counting from the last
   // Start() onwards (this is like the laptimer function).

   if (fState == kUndefined)
      Error("Continue", "stopwatch not started");

   if (fState == kStopped) {
      fTotalCpuTime  -= fStopCpuTime  - fStartCpuTime;
      fTotalRealTime -= fStopRealTime - fStartRealTime;
   }

   fState = kRunning;
}

//______________________________________________________________________________
Double_t TStopwatch::RealTime()
{
   // Return the realtime passed between the start and stop events. If the
   // stopwatch was still running stop it first.

   if (fState == kUndefined)
      Error("RealTime", "stopwatch not started");

   if (fState == kRunning)
      Stop();

   return fTotalRealTime;
}

//______________________________________________________________________________
Double_t TStopwatch::CpuTime()
{
   // Return the cputime passed between the start and stop events. If the
   // stopwatch was still running stop it first.

   if (fState == kUndefined)
      Error("RealTime", "stopwatch not started");

   if (fState == kRunning)
      Stop();

   return fTotalCpuTime;
}

//______________________________________________________________________________
Double_t TStopwatch::GetRealTime(){
#if defined(R__MAC)
   return(Double_t)clock() / gTicks;
#elif defined(R__UNIX)
   struct tms cpt;
   Double_t trt =  (Double_t)times(&cpt);
   return trt / (double)gTicks;
#elif defined(R__VMS)
  return(Double_t)clock()/gTicks;
#elif defined(WIN32)
  union     {FILETIME ftFileTime;
             __int64  ftInt64;
            } ftRealTime; // time the process has spent in kernel mode
  SYSTEMTIME st;
  GetSystemTime(&st);
  SystemTimeToFileTime(&st,&ftRealTime.ftFileTime);
  return (Double_t)ftRealTime.ftInt64 * gTicks;
#endif
}

//______________________________________________________________________________
Double_t TStopwatch::GetCPUTime(){
#if defined(R__MAC)
   return(Double_t)clock() / gTicks;
#elif defined(R__UNIX)
   struct tms cpt;
   times(&cpt);
   return (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#elif defined(R__VMS)
   return(Double_t)clock()/gTicks;
#elif defined(WIN32)

  OSVERSIONINFO OsVersionInfo;

//*-*         Value                      Platform
//*-*  ----------------------------------------------------
//*-*  VER_PLATFORM_WIN32s          Win32s on Windows 3.1
//*-*  VER_PLATFORM_WIN32_WINDOWS       Win32 on Windows 95
//*-*  VER_PLATFORM_WIN32_NT            Windows NT
//*-*
  OsVersionInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
  GetVersionEx(&OsVersionInfo);
  if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
    DWORD       ret;
    FILETIME    ftCreate,       // when the process was created
                ftExit;         // when the process exited

    union     {FILETIME ftFileTime;
               __int64  ftInt64;
              } ftKernel; // time the process has spent in kernel mode

    union     {FILETIME ftFileTime;
               __int64  ftInt64;
              } ftUser;   // time the process has spent in user mode

    HANDLE hProcess = GetCurrentProcess();
    ret = GetProcessTimes (hProcess, &ftCreate, &ftExit,
                                     &ftKernel.ftFileTime,
                                     &ftUser.ftFileTime);
    if (ret != TRUE){
      ret = GetLastError ();
      ::Error ("GetCPUTime", " Error on GetProcessTimes 0x%lx", (int)ret);
    }

    /*
     * Process times are returned in a 64-bit structure, as the number of
     * 100 nanosecond ticks since 1 January 1601.  User mode and kernel mode
     * times for this process are in separate 64-bit structures.
     * To convert to floating point seconds, we will:
     *
     *          Convert sum of high 32-bit quantities to 64-bit int
     */

      return (Double_t) (ftKernel.ftInt64 + ftUser.ftInt64) * gTicks;
  }
  else
      return GetRealTime();

#endif
}

//______________________________________________________________________________
void TStopwatch::Print(Option_t *)
{
   // Print the real and cpu time passed between the start and stop events.
   // and the number of times (slices) this TStopwatch was called
   // (if this number > 1)

   Double_t  realt = RealTime();

   Int_t  hours = Int_t(realt / 3600);
   realt -= hours * 3600;
   Int_t  min   = Int_t(realt / 60);
   realt -= min * 60;
   Int_t  sec   = Int_t(realt);
   Int_t counter = Counter();
   if (counter <= 1 )
      Printf("Real time %d:%d:%d, CP time %.3f", hours, min, sec, CpuTime());
   else
      Printf("Real time %d:%d:%d, CP time %.3f, %d slices", hours, min, sec, CpuTime(),counter);
}

<|endoftext|>


<commit_before>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of 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 "base/string_util.h"

#include <windows.h>
#include <string>
#include "unicode/numfmt.h"
#include "base/logging.h"

// See WideToUTF8.
static std::string WideToMultiByte(const std::wstring& wide, UINT code_page) {
  int wide_length = static_cast<int>(wide.length());
  if (wide_length == 0)
    return std::string();

  // compute the length of the buffer we'll need
  int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
                                      NULL, 0, NULL, NULL);
  if (charcount == 0)
    return std::string();

  // convert
  std::string mb;
  WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
                      WriteInto(&mb, charcount + 1), charcount, NULL, NULL);

  return mb;
}

// Converts the given 8-bit string into a wide string, using the given
// code page. The code page identifier is one accepted by MultiByteToWideChar()
//
// Danger: do not assert in this function, as it is used by the assertion code.
// Doing so will cause an infinite loop.
static std::wstring MultiByteToWide(const std::string& mb, UINT code_page) {
  if (mb.length() == 0)
    return std::wstring();

  // compute the length of the buffer
  int charcount = MultiByteToWideChar(code_page, 0, mb.c_str(), -1, NULL, 0);
  if (charcount == 0)
    return std::wstring();

  // convert
  std::wstring wide;
  MultiByteToWideChar(code_page, 0, mb.c_str(), -1,
                      WriteInto(&wide, charcount), charcount);

  return wide;
}

// Wide <--> UTF-8
std::string WideToUTF8(const std::wstring& wide) {

  return WideToMultiByte(wide, CP_UTF8);
}

std::wstring UTF8ToWide(const std::string& utf8) {
  return MultiByteToWide(utf8, CP_UTF8);
}

// Wide <--> native multibyte
std::string WideToNativeMB(const std::wstring& wide) {
  return WideToMultiByte(wide, CP_ACP);
}

std::wstring NativeMBToWide(const std::string& native_mb) {
  return MultiByteToWide(native_mb, CP_ACP);
}

NumberFormat* NumberFormatSingleton() {
  static NumberFormat* number_format = NULL;
  if (!number_format) {
    // Make sure we are thread-safe.
    UErrorCode status = U_ZERO_ERROR;
    NumberFormat* new_number_format = NumberFormat::createInstance(status);
    if (U_FAILURE(status)) {
      NOTREACHED();
    }
    if (InterlockedCompareExchangePointer(
        reinterpret_cast<PVOID*>(&number_format), new_number_format, NULL)) {
      // The old value was non-NULL, so no replacement was done. Another
      // thread did the initialization out from under us.
      if (new_number_format)
        delete new_number_format;
    }
  }
  return number_format;
}
<commit_msg>We were passing -1 (indicating NULL terminated) to the UTF8->wide conversion function. The wide->UTF8 version is fine.<commit_after>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of 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 "base/string_util.h"

#include <windows.h>
#include <string>
#include "unicode/numfmt.h"
#include "base/logging.h"

// See WideToUTF8.
static std::string WideToMultiByte(const std::wstring& wide, UINT code_page) {
  int wide_length = static_cast<int>(wide.length());
  if (wide_length == 0)
    return std::string();

  // compute the length of the buffer we'll need
  int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
                                      NULL, 0, NULL, NULL);
  if (charcount == 0)
    return std::string();

  // convert
  std::string mb;
  WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
                      WriteInto(&mb, charcount + 1), charcount, NULL, NULL);

  return mb;
}

// Converts the given 8-bit string into a wide string, using the given
// code page. The code page identifier is one accepted by MultiByteToWideChar()
//
// Danger: do not assert in this function, as it is used by the assertion code.
// Doing so will cause an infinite loop.
static std::wstring MultiByteToWide(const std::string& mb, UINT code_page) {
  int mb_length = static_cast<int>(mb.length());
  if (mb_length == 0)
    return std::wstring();

  // compute the length of the buffer
  int charcount = MultiByteToWideChar(code_page, 0, mb.c_str(), mb_length,
                                      NULL, 0);
  if (charcount == 0)
    return std::wstring();

  // convert
  std::wstring wide;
  MultiByteToWideChar(code_page, 0, mb.c_str(), mb_length,
                      WriteInto(&wide, charcount + 1), charcount);

  return wide;
}

// Wide <--> UTF-8
std::string WideToUTF8(const std::wstring& wide) {

  return WideToMultiByte(wide, CP_UTF8);
}

std::wstring UTF8ToWide(const std::string& utf8) {
  return MultiByteToWide(utf8, CP_UTF8);
}

// Wide <--> native multibyte
std::string WideToNativeMB(const std::wstring& wide) {
  return WideToMultiByte(wide, CP_ACP);
}

std::wstring NativeMBToWide(const std::string& native_mb) {
  return MultiByteToWide(native_mb, CP_ACP);
}

NumberFormat* NumberFormatSingleton() {
  static NumberFormat* number_format = NULL;
  if (!number_format) {
    // Make sure we are thread-safe.
    UErrorCode status = U_ZERO_ERROR;
    NumberFormat* new_number_format = NumberFormat::createInstance(status);
    if (U_FAILURE(status)) {
      NOTREACHED();
    }
    if (InterlockedCompareExchangePointer(
        reinterpret_cast<PVOID*>(&number_format), new_number_format, NULL)) {
      // The old value was non-NULL, so no replacement was done. Another
      // thread did the initialization out from under us.
      if (new_number_format)
        delete new_number_format;
    }
  }
  return number_format;
}
<|endoftext|>