<commit_before>/*
 *   Copyright 2011 Marco Martin <mart@kde.org>
 *   Copyright 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "desktopicon.h"

#include <QSGSimpleTextureNode>
#include <qquickwindow.h>
#include <QIcon>
#include <QBitmap>
#include <QSGTexture>
#include <QDebug>
#include <QSGSimpleTextureNode>
#include <QSGTexture>
#include <QSharedPointer>
#include <QtQml>
#include <QQuickImageProvider>
#include <QGuiApplication>
#include <QPointer>

class ManagedTextureNode : public QSGSimpleTextureNode
{
Q_DISABLE_COPY(ManagedTextureNode)
public:
    ManagedTextureNode();

    void setTexture(QSharedPointer<QSGTexture> texture);

private:
    QSharedPointer<QSGTexture> m_texture;
};

ManagedTextureNode::ManagedTextureNode()
{}

void ManagedTextureNode::setTexture(QSharedPointer<QSGTexture> texture)
{
    m_texture = texture;
    QSGSimpleTextureNode::setTexture(texture.data());
}

typedef QHash<qint64, QHash<QWindow*, QWeakPointer<QSGTexture> > > TexturesCache;

struct ImageTexturesCachePrivate
{
    TexturesCache cache;
};

class ImageTexturesCache
{
public:
    ImageTexturesCache();
    ~ImageTexturesCache();

    /**
     * @returns the texture for a given @p window and @p image.
     *
     * If an @p image id is the same as one already provided before, we won't create
     * a new texture and return a shared pointer to the existing texture.
     */
    QSharedPointer<QSGTexture> loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options);

    QSharedPointer<QSGTexture> loadTexture(QQuickWindow *window, const QImage &image);

private:
    QScopedPointer<ImageTexturesCachePrivate> d;
};

ImageTexturesCache::ImageTexturesCache()
    : d(new ImageTexturesCachePrivate)
{
}

ImageTexturesCache::~ImageTexturesCache()
{
}

QSharedPointer<QSGTexture> ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options)
{
    qint64 id = image.cacheKey();
    QSharedPointer<QSGTexture> texture = d->cache.value(id).value(window).toStrongRef();

    if (!texture) {
        auto cleanAndDelete = [this, window, id](QSGTexture* texture) {
            QHash<QWindow*, QWeakPointer<QSGTexture> >& textures = (d->cache)[id];
            textures.remove(window);
            if (textures.isEmpty())
                d->cache.remove(id);
            delete texture;
        };
        texture = QSharedPointer<QSGTexture>(window->createTextureFromImage(image, options), cleanAndDelete);
        (d->cache)[id][window] = texture.toWeakRef();
    }

    //if we have a cache in an atlas but our request cannot use an atlassed texture
    //create a new texture and use that
    //don't use removedFromAtlas() as that requires keeping a reference to the non atlased version
    if (!(options & QQuickWindow::TextureCanUseAtlas) && texture->isAtlasTexture()) {
        texture = QSharedPointer<QSGTexture>(window->createTextureFromImage(image, options));
    }

    return texture;
}

QSharedPointer<QSGTexture> ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image)
{
    return loadTexture(window, image, 0);
}

Q_GLOBAL_STATIC(ImageTexturesCache, s_iconImageCache)

DesktopIcon::DesktopIcon(QQuickItem *parent)
    : QQuickItem(parent),
      m_smooth(false),
      m_changed(false),
      m_active(false),
      m_selected(false)
{
    setFlag(ItemHasContents, true);
    connect(qApp, &QGuiApplication::paletteChanged, this, [this]() {
        m_changed = true;
        update();
    });
}

DesktopIcon::~DesktopIcon()
{
}

void DesktopIcon::setSource(const QVariant &icon)
{
    if (m_source == icon) {
        return;
    }
    m_source = icon;
    m_changed = true;
    update();
    emit sourceChanged();
}

QVariant DesktopIcon::source() const
{
    return m_source;
}

void DesktopIcon::setEnabled(const bool enabled)
{
    if (enabled == QQuickItem::isEnabled()) {
        return;
    }
    QQuickItem::setEnabled(enabled);
    m_changed = true;
    update();
    emit enabledChanged();
}

void DesktopIcon::setActive(const bool active)
{
    if (active == m_active) {
        return;
    }
    m_active = active;
    m_changed = true;
    update();
    emit activeChanged();
}

bool DesktopIcon::active() const
{
    return m_active;
}

bool DesktopIcon::valid() const
{
    return !m_source.isNull();
}

void DesktopIcon::setSelected(const bool selected)
{
    if (selected == m_selected) {
        return;
    }
    m_selected = selected;
    m_changed = true;
    update();
    emit selectedChanged();
}

bool DesktopIcon::selected() const
{
    return m_selected;
}

int DesktopIcon::implicitWidth() const
{
    return 32;
}

int DesktopIcon::implicitHeight() const
{
    return 32;
}

void DesktopIcon::setSmooth(const bool smooth)
{
    if (smooth == m_smooth) {
        return;
    }
    m_smooth = smooth;
    m_changed = true;
    update();
    emit smoothChanged();
}

bool DesktopIcon::smooth() const
{
    return m_smooth;
}

QSGNode* DesktopIcon::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/)
{
    if (m_source.isNull()) {
        delete node;
        return Q_NULLPTR;
    }

    if (m_changed || node == 0) {
        QImage img;
        const QSize size = QSize(width(), height()) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());

        switch(m_source.type()){
        case QVariant::Pixmap:
            img = m_source.value<QPixmap>().toImage();
            break;
        case QVariant::Image:
            img = m_source.value<QImage>();
            break;
        case QVariant::Bitmap:
            img = m_source.value<QBitmap>().toImage();
            break;
        case QVariant::Icon:
            img = m_source.value<QIcon>().pixmap(size, iconMode(), QIcon::On).toImage();
            break;
        case QVariant::String:
            img = findIcon(size);
            break;
        case QVariant::Brush:
        case QVariant::Color:
            //perhaps fill image instead?
        default:
            break;
        }

        if (img.isNull()){
            img = QImage(size, QImage::Format_Alpha8);
            img.fill(Qt::transparent);
        }
        if (img.size() != size){
            img = img.scaled(size, Qt::KeepAspectRatioByExpanding, m_smooth ? Qt::SmoothTransformation : Qt::FastTransformation );
        }
        m_changed = false;

        ManagedTextureNode* mNode = dynamic_cast<ManagedTextureNode*>(node);
        if (!mNode) {
            delete node;
            mNode = new ManagedTextureNode;
        }

        mNode->setTexture(s_iconImageCache->loadTexture(window(), img));
        mNode->setRect(QRect(QPoint(0,0), QSize(width(), height())));
        node = mNode;
    }

    return node;
}

void DesktopIcon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
    if (newGeometry.size() != oldGeometry.size()) {
        m_changed = true;
        update();
    }
    QQuickItem::geometryChanged(newGeometry, oldGeometry);
}

void DesktopIcon::handleFinished(QNetworkAccessManager* qnam, QNetworkReply* reply) {
    if (reply->error() == QNetworkReply::NoError) {
        const QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
        if (!possibleRedirectUrl.isEmpty()) {
            const QUrl redirectUrl = reply->url().resolved(possibleRedirectUrl);
            if (redirectUrl == reply->url()) {
                // no infinite redirections thank you very much
                reply->deleteLater();
                return;
            }
            reply->deleteLater();
            QNetworkRequest request(possibleRedirectUrl);
            request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
            QNetworkReply* newReply = qnam->get(request);
            connect(newReply, &QNetworkReply::readyRead, this, [this, newReply](){ handleReadyRead(newReply); });
            connect(newReply, &QNetworkReply::finished, this, [this, qnam, newReply](){ handleFinished(qnam, newReply); });
            return;
        }
    }
}

void DesktopIcon::handleReadyRead(QNetworkReply* reply)
{
    if (reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isNull()) {
        // We're handing the event loop back while doing network work, and it turns out
        // this fairly regularly results in things being deleted under us. So, just
        // handle that and crash less :)
        QPointer<DesktopIcon> me(this);
        QByteArray data;
        do {
            data.append(reply->read(32768));
            // Because we are in the main thread, this could be potentially very expensive, so let's not block
            qApp->processEvents();
            if(!me) {
                return;
            }
        } while(!reply->atEnd());
        m_loadedImage = QImage::fromData(data);
        if (m_loadedImage.isNull()) {
            // broken image from data, inform the user of this with some useful broken-image thing...
            const QSize size = QSize(width(), height()) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());
            m_loadedImage = QIcon::fromTheme("unknown").pixmap(size, iconMode(), QIcon::On).toImage();
        }
        m_changed = true;
        update();
    }
}

QImage DesktopIcon::findIcon(const QSize &size)
{
    QImage img;
    QString iconSource = m_source.toString();
    if (iconSource.startsWith("image://")){
        QUrl iconUrl(iconSource);
        QString iconProviderId = iconUrl.host();
        QString iconId = iconUrl.path();
        QSize actualSize;
        QQuickImageProvider* imageProvider = dynamic_cast<QQuickImageProvider*>(
                    qmlEngine(this)->imageProvider(iconProviderId));
        if (!imageProvider)
            return img;
        switch(imageProvider->imageType()){
        case QQmlImageProviderBase::Image:
            img = imageProvider->requestImage(iconId, &actualSize, size);
            break;
        case QQmlImageProviderBase::Pixmap:
            img = imageProvider->requestPixmap(iconId, &actualSize, size).toImage();
            break;
        case QQmlImageProviderBase::Texture:
        case QQmlImageProviderBase::Invalid:
        case QQmlImageProviderBase::ImageResponse:
            //will have to investigate this more
            break;
        }
    } else if(iconSource.startsWith("http://") || iconSource.startsWith("https://")) {
        if(!m_loadedImage.isNull()) {
            return m_loadedImage.scaled(size, Qt::KeepAspectRatio, m_smooth ? Qt::SmoothTransformation : Qt::FastTransformation );
        }
        QQmlEngine* engine = qmlEngine(this);
        QNetworkAccessManager* qnam;
        if (engine && (qnam = qmlEngine(this)->networkAccessManager())) {
            QNetworkRequest request(m_source.toUrl());
            request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
            QNetworkReply* reply = qnam->get(request);
            connect(reply, &QNetworkReply::readyRead, this, [this, reply](){ handleReadyRead(reply); });
            connect(reply, &QNetworkReply::finished, this, [this, qnam, reply](){ handleFinished(qnam, reply); });
        }
        // Temporary icon while we wait for the real image to load...
        img = QIcon::fromTheme("image-x-icon").pixmap(size, iconMode(), QIcon::On).toImage();
    } else {
        if (iconSource.startsWith("qrc:/")){
            iconSource = iconSource.mid(3);
        }
        QIcon icon(iconSource);
        if (icon.availableSizes().isEmpty()) {
            icon = QIcon::fromTheme(iconSource);
        }
        if (!icon.availableSizes().isEmpty()){
            img = icon.pixmap(size, iconMode(), QIcon::On).toImage();
        }
    }
    return img;
}

QIcon::Mode DesktopIcon::iconMode() const
{
    if (!isEnabled()) {
        return QIcon::Disabled;
    } else if (m_selected) {
        return QIcon::Selected;
    } else if (m_active) {
        return QIcon::Active;
    }
    return QIcon::Normal;
}
<commit_msg>Add a check for whether the item isn't actually visible<commit_after>/*
 *   Copyright 2011 Marco Martin <mart@kde.org>
 *   Copyright 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "desktopicon.h"

#include <QSGSimpleTextureNode>
#include <qquickwindow.h>
#include <QIcon>
#include <QBitmap>
#include <QSGTexture>
#include <QDebug>
#include <QSGSimpleTextureNode>
#include <QSGTexture>
#include <QSharedPointer>
#include <QtQml>
#include <QQuickImageProvider>
#include <QGuiApplication>
#include <QPointer>

class ManagedTextureNode : public QSGSimpleTextureNode
{
Q_DISABLE_COPY(ManagedTextureNode)
public:
    ManagedTextureNode();

    void setTexture(QSharedPointer<QSGTexture> texture);

private:
    QSharedPointer<QSGTexture> m_texture;
};

ManagedTextureNode::ManagedTextureNode()
{}

void ManagedTextureNode::setTexture(QSharedPointer<QSGTexture> texture)
{
    m_texture = texture;
    QSGSimpleTextureNode::setTexture(texture.data());
}

typedef QHash<qint64, QHash<QWindow*, QWeakPointer<QSGTexture> > > TexturesCache;

struct ImageTexturesCachePrivate
{
    TexturesCache cache;
};

class ImageTexturesCache
{
public:
    ImageTexturesCache();
    ~ImageTexturesCache();

    /**
     * @returns the texture for a given @p window and @p image.
     *
     * If an @p image id is the same as one already provided before, we won't create
     * a new texture and return a shared pointer to the existing texture.
     */
    QSharedPointer<QSGTexture> loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options);

    QSharedPointer<QSGTexture> loadTexture(QQuickWindow *window, const QImage &image);

private:
    QScopedPointer<ImageTexturesCachePrivate> d;
};

ImageTexturesCache::ImageTexturesCache()
    : d(new ImageTexturesCachePrivate)
{
}

ImageTexturesCache::~ImageTexturesCache()
{
}

QSharedPointer<QSGTexture> ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options)
{
    qint64 id = image.cacheKey();
    QSharedPointer<QSGTexture> texture = d->cache.value(id).value(window).toStrongRef();

    if (!texture) {
        auto cleanAndDelete = [this, window, id](QSGTexture* texture) {
            QHash<QWindow*, QWeakPointer<QSGTexture> >& textures = (d->cache)[id];
            textures.remove(window);
            if (textures.isEmpty())
                d->cache.remove(id);
            delete texture;
        };
        texture = QSharedPointer<QSGTexture>(window->createTextureFromImage(image, options), cleanAndDelete);
        (d->cache)[id][window] = texture.toWeakRef();
    }

    //if we have a cache in an atlas but our request cannot use an atlassed texture
    //create a new texture and use that
    //don't use removedFromAtlas() as that requires keeping a reference to the non atlased version
    if (!(options & QQuickWindow::TextureCanUseAtlas) && texture->isAtlasTexture()) {
        texture = QSharedPointer<QSGTexture>(window->createTextureFromImage(image, options));
    }

    return texture;
}

QSharedPointer<QSGTexture> ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image)
{
    return loadTexture(window, image, 0);
}

Q_GLOBAL_STATIC(ImageTexturesCache, s_iconImageCache)

DesktopIcon::DesktopIcon(QQuickItem *parent)
    : QQuickItem(parent),
      m_smooth(false),
      m_changed(false),
      m_active(false),
      m_selected(false)
{
    setFlag(ItemHasContents, true);
    connect(qApp, &QGuiApplication::paletteChanged, this, [this]() {
        m_changed = true;
        update();
    });
}

DesktopIcon::~DesktopIcon()
{
}

void DesktopIcon::setSource(const QVariant &icon)
{
    if (m_source == icon) {
        return;
    }
    m_source = icon;
    m_changed = true;
    update();
    emit sourceChanged();
}

QVariant DesktopIcon::source() const
{
    return m_source;
}

void DesktopIcon::setEnabled(const bool enabled)
{
    if (enabled == QQuickItem::isEnabled()) {
        return;
    }
    QQuickItem::setEnabled(enabled);
    m_changed = true;
    update();
    emit enabledChanged();
}

void DesktopIcon::setActive(const bool active)
{
    if (active == m_active) {
        return;
    }
    m_active = active;
    m_changed = true;
    update();
    emit activeChanged();
}

bool DesktopIcon::active() const
{
    return m_active;
}

bool DesktopIcon::valid() const
{
    return !m_source.isNull();
}

void DesktopIcon::setSelected(const bool selected)
{
    if (selected == m_selected) {
        return;
    }
    m_selected = selected;
    m_changed = true;
    update();
    emit selectedChanged();
}

bool DesktopIcon::selected() const
{
    return m_selected;
}

int DesktopIcon::implicitWidth() const
{
    return 32;
}

int DesktopIcon::implicitHeight() const
{
    return 32;
}

void DesktopIcon::setSmooth(const bool smooth)
{
    if (smooth == m_smooth) {
        return;
    }
    m_smooth = smooth;
    m_changed = true;
    update();
    emit smoothChanged();
}

bool DesktopIcon::smooth() const
{
    return m_smooth;
}

QSGNode* DesktopIcon::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* /*data*/)
{
    if (m_source.isNull()) {
        delete node;
        return Q_NULLPTR;
    }

    if (m_changed || node == 0) {
        QImage img;
        const QSize itemSize(width(), height());

        if (itemSize.width() != 0 && itemSize.height() != 0) {
            const QSize size = itemSize * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());

            switch(m_source.type()){
            case QVariant::Pixmap:
                img = m_source.value<QPixmap>().toImage();
                break;
            case QVariant::Image:
                img = m_source.value<QImage>();
                break;
            case QVariant::Bitmap:
                img = m_source.value<QBitmap>().toImage();
                break;
            case QVariant::Icon:
                img = m_source.value<QIcon>().pixmap(size, iconMode(), QIcon::On).toImage();
                break;
            case QVariant::String:
                img = findIcon(size);
                break;
            case QVariant::Brush:
            case QVariant::Color:
                //perhaps fill image instead?
            default:
                break;
            }

            if (img.isNull()){
                img = QImage(size, QImage::Format_Alpha8);
                img.fill(Qt::transparent);
            }
            if (img.size() != size){
                img = img.scaled(size, Qt::KeepAspectRatioByExpanding, m_smooth ? Qt::SmoothTransformation : Qt::FastTransformation );
            }
        }
        m_changed = false;

        ManagedTextureNode* mNode = dynamic_cast<ManagedTextureNode*>(node);
        if (!mNode) {
            delete node;
            mNode = new ManagedTextureNode;
        }
        mNode->setTexture(s_iconImageCache->loadTexture(window(), img));
        mNode->setRect(QRect(QPoint(0,0), itemSize));
        node = mNode;
    }

    return node;
}

void DesktopIcon::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
    if (newGeometry.size() != oldGeometry.size()) {
        m_changed = true;
        update();
    }
    QQuickItem::geometryChanged(newGeometry, oldGeometry);
}

void DesktopIcon::handleFinished(QNetworkAccessManager* qnam, QNetworkReply* reply) {
    if (reply->error() == QNetworkReply::NoError) {
        const QUrl possibleRedirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
        if (!possibleRedirectUrl.isEmpty()) {
            const QUrl redirectUrl = reply->url().resolved(possibleRedirectUrl);
            if (redirectUrl == reply->url()) {
                // no infinite redirections thank you very much
                reply->deleteLater();
                return;
            }
            reply->deleteLater();
            QNetworkRequest request(possibleRedirectUrl);
            request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
            QNetworkReply* newReply = qnam->get(request);
            connect(newReply, &QNetworkReply::readyRead, this, [this, newReply](){ handleReadyRead(newReply); });
            connect(newReply, &QNetworkReply::finished, this, [this, qnam, newReply](){ handleFinished(qnam, newReply); });
            return;
        }
    }
}

void DesktopIcon::handleReadyRead(QNetworkReply* reply)
{
    if (reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isNull()) {
        // We're handing the event loop back while doing network work, and it turns out
        // this fairly regularly results in things being deleted under us. So, just
        // handle that and crash less :)
        QPointer<DesktopIcon> me(this);
        QByteArray data;
        do {
            data.append(reply->read(32768));
            // Because we are in the main thread, this could be potentially very expensive, so let's not block
            qApp->processEvents();
            if(!me) {
                return;
            }
        } while(!reply->atEnd());
        m_loadedImage = QImage::fromData(data);
        if (m_loadedImage.isNull()) {
            // broken image from data, inform the user of this with some useful broken-image thing...
            const QSize size = QSize(width(), height()) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());
            m_loadedImage = QIcon::fromTheme("unknown").pixmap(size, iconMode(), QIcon::On).toImage();
        }
        m_changed = true;
        update();
    }
}

QImage DesktopIcon::findIcon(const QSize &size)
{
    QImage img;
    QString iconSource = m_source.toString();
    if (iconSource.startsWith("image://")){
        QUrl iconUrl(iconSource);
        QString iconProviderId = iconUrl.host();
        QString iconId = iconUrl.path();
        QSize actualSize;
        QQuickImageProvider* imageProvider = dynamic_cast<QQuickImageProvider*>(
                    qmlEngine(this)->imageProvider(iconProviderId));
        if (!imageProvider)
            return img;
        switch(imageProvider->imageType()){
        case QQmlImageProviderBase::Image:
            img = imageProvider->requestImage(iconId, &actualSize, size);
            break;
        case QQmlImageProviderBase::Pixmap:
            img = imageProvider->requestPixmap(iconId, &actualSize, size).toImage();
            break;
        case QQmlImageProviderBase::Texture:
        case QQmlImageProviderBase::Invalid:
        case QQmlImageProviderBase::ImageResponse:
            //will have to investigate this more
            break;
        }
    } else if(iconSource.startsWith("http://") || iconSource.startsWith("https://")) {
        if(!m_loadedImage.isNull()) {
            return m_loadedImage.scaled(size, Qt::KeepAspectRatio, m_smooth ? Qt::SmoothTransformation : Qt::FastTransformation );
        }
        QQmlEngine* engine = qmlEngine(this);
        QNetworkAccessManager* qnam;
        if (engine && (qnam = qmlEngine(this)->networkAccessManager())) {
            QNetworkRequest request(m_source.toUrl());
            request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
            QNetworkReply* reply = qnam->get(request);
            connect(reply, &QNetworkReply::readyRead, this, [this, reply](){ handleReadyRead(reply); });
            connect(reply, &QNetworkReply::finished, this, [this, qnam, reply](){ handleFinished(qnam, reply); });
        }
        // Temporary icon while we wait for the real image to load...
        img = QIcon::fromTheme("image-x-icon").pixmap(size, iconMode(), QIcon::On).toImage();
    } else {
        if (iconSource.startsWith("qrc:/")){
            iconSource = iconSource.mid(3);
        }
        QIcon icon(iconSource);
        if (icon.availableSizes().isEmpty()) {
            icon = QIcon::fromTheme(iconSource);
        }
        if (!icon.availableSizes().isEmpty()){
            img = icon.pixmap(size, iconMode(), QIcon::On).toImage();
        }
    }
    return img;
}

QIcon::Mode DesktopIcon::iconMode() const
{
    if (!isEnabled()) {
        return QIcon::Disabled;
    } else if (m_selected) {
        return QIcon::Selected;
    } else if (m_active) {
        return QIcon::Active;
    }
    return QIcon::Normal;
}
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include "TCanvas.h"
#include "TFile.h"
#include "TH2.h"
#include "TStyle.h"

#include "core/utils/unit.h"
#include "tools/field_parser.h"

using namespace allpix;
int main(int argc, char** argv) {
    // Set ROOT params
    gStyle->SetOptStat(0);
    gStyle->SetNumberContours(999);

    bool print_help = false;
    int return_code = 0;
    if(argc == 1) {
        print_help = true;
        return_code = 1;
    }

    // Read parameters
    std::string file_name;
    std::string output_file_name;
    std::string output_name_log;
    std::string plane = "yz";
    std::string units;
    bool flag_cut = false;
    size_t slice_cut = 0;
    bool log_scale = false;
    for(int i = 1; i < argc; i++) {
        if(strcmp(argv[i], "-h") == 0) {
            print_help = true;
        } else if(strcmp(argv[i], "-f") == 0 && (i + 1 < argc)) {
            file_name = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-o") == 0 && (i + 1 < argc)) {
            output_file_name = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) {
            plane = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-u") == 0 && (i + 1 < argc)) {
            units = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) {
            slice_cut = static_cast<size_t>(std::atoi(argv[++i]));
            flag_cut = true;
        } else if(strcmp(argv[i], "-l") == 0) {
            log_scale = true;
        } else {
            std::cout << "Unrecognized command line argument or missing value\"" << argv[i] << std::endl;
            print_help = true;
            return_code = 1;
        }
    }

    if(file_name.empty()) {
        print_help = true;
        return_code = 1;
    }

    if(print_help) {
        std::cerr << "Usage: mesh_plotter -f <file_name> [<options>]" << std::endl;
        std::cout << "Required parameters:" << std::endl;
        std::cout << "\t -f <file_name>         name of the interpolated file in INIT or APF format" << std::endl;
        std::cout << "Optional parameters:" << std::endl;
        std::cout << "\t -c <cut>               projection height index (default is mesh_pitch / 2)" << std::endl;
        std::cout << "\t -h                     display this help text" << std::endl;
        std::cout << "\t -l                     plot with logarithmic scale if set" << std::endl;
        std::cout << "\t -o <output_file_name>  name of the file to output (default is efield.png)" << std::endl;
        std::cout << "\t -p <plane>             plane to be ploted. xy, yz or zx (default is yz)" << std::endl;
        std::cout << "\t -u <units>             units to interpret the field data in" << std::endl;
        return return_code;
    }

    // Read file
    std::cout << "Welcome to the Mesh Plotter Tool of Allpix^2 " << ALLPIX_PROJECT_VERSION << std::endl;
    std::cout << "Reading file: " << file_name;

    size_t firstindex = file_name.find_last_of('_');
    size_t lastindex = file_name.find_last_of('.');
    std::string observable = file_name.substr(firstindex + 1, lastindex - (firstindex + 1));
    std::string extension = file_name.substr(lastindex + 1, file_name.size() - lastindex);

    // FIXME this should be done in a more elegant way
    FieldQuantity quantity = (observable == "ElectricField" ? FieldQuantity::VECTOR : FieldQuantity::SCALAR);
    FileType type = (extension == "apf" ? FileType::APF : FileType::INIT);

    FieldParser<double> field_parser(quantity);
    auto field_data = field_parser.get_by_file_name(file_name, type, units);
    size_t xdiv = field_data.getDimensions()[0], ydiv = field_data.getDimensions()[1], zdiv = field_data.getDimensions()[2];

    std::cout << "Number of divisions in x/y/z: " << xdiv << "/" << ydiv << "/" << zdiv << std::endl;

    // Find plotting indices
    int x_bin = 0;
    int y_bin = 0;
    size_t start_x = 0, start_y = 0, start_z = 0;
    size_t stop_x = xdiv, stop_y = ydiv, stop_z = zdiv;
    if(plane == "xy") {
        if(!flag_cut) {
            slice_cut = (zdiv + 1) / 2;
        }

        // z is the slice:
        start_z = slice_cut;
        stop_z = start_z + 1;

        // scale the plot axes:
        x_bin = static_cast<int>(xdiv);
        y_bin = static_cast<int>(ydiv);
    } else if(plane == "yz") {
        if(!flag_cut) {
            slice_cut = (xdiv + 1) / 2;
        }

        // x is the slice:
        start_x = slice_cut;
        stop_x = start_x + 1;

        x_bin = static_cast<int>(ydiv);
        y_bin = static_cast<int>(zdiv);
    } else {
        if(!flag_cut) {
            slice_cut = (ydiv + 1) / 2;
        }

        // y is the slice:
        start_y = slice_cut;
        stop_y = start_y + 1;

        x_bin = static_cast<int>(zdiv);
        y_bin = static_cast<int>(xdiv);
    }

    // Create and fill histogram
    auto efield_map =
        new TH2D(Form("%s", observable.c_str()), Form("%s", observable.c_str()), x_bin, 1, x_bin + 1, y_bin, 1, y_bin + 1);
    auto exfield_map = new TH2D(Form("%s X component", observable.c_str()),
                                Form("%s X component", observable.c_str()),
                                x_bin + 1,
                                1,
                                x_bin + 1,
                                y_bin + 1,
                                1,
                                y_bin + 1);
    auto eyfield_map = new TH2D(Form("%s Y component", observable.c_str()),
                                Form("%s Y component", observable.c_str()),
                                x_bin + 1,
                                1,
                                x_bin + 1,
                                y_bin + 1,
                                1,
                                y_bin + 1);
    auto ezfield_map = new TH2D(Form("%s Z component", observable.c_str()),
                                Form("%s Z component", observable.c_str()),
                                x_bin + 1,
                                1,
                                x_bin + 1,
                                y_bin + 1,
                                1,
                                y_bin + 1);

    auto c1 = new TCanvas();

    if(log_scale) {
        c1->SetLogz();
        output_name_log = "_log";
    }

    int plot_x, plot_y;
    auto data = field_data.getData();
    for(size_t x = start_x; x < stop_x; x++) {
        for(size_t y = start_y; y < stop_y; y++) {
            for(size_t z = start_z; z < stop_z; z++) {
                // Select the indices for plotting:
                if(plane == "xy") {
                    plot_x = static_cast<int>(x);
                    plot_y = static_cast<int>(y);
                } else if(plane == "yz") {
                    plot_x = static_cast<int>(y);
                    plot_y = static_cast<int>(z);
                } else {
                    plot_x = static_cast<int>(z);
                    plot_y = static_cast<int>(x);
                }

                if(quantity == FieldQuantity::VECTOR) {
                    // Fill field maps for the individual vector components as well as the magnitude
                    auto base = x * ydiv * zdiv * 3 + y * zdiv * 3 + z * 3;
                    efield_map->Fill(
                        plot_x,
                        plot_y,
                        sqrt(pow(data->at(base + 0), 2) + pow(data->at(base + 1), 2) + pow(data->at(base + 2), 2)));
                    exfield_map->Fill(plot_x, plot_y, data->at(base + 0));
                    eyfield_map->Fill(plot_x, plot_y, data->at(base + 1));
                    ezfield_map->Fill(plot_x, plot_y, data->at(base + 2));

                } else {
                    // Fill one map with the scalar quantity
                    efield_map->Fill(plot_x, plot_y, data->at(x * ydiv * zdiv + y * zdiv + z));
                }
            }
        }
    }

    if(output_file_name.empty()) {
        output_file_name = file_name.substr(0, lastindex);
        output_file_name = output_file_name + "_" + plane + "_" + std::to_string(slice_cut) + output_name_log + ".png";
    }

    std::string root_file_name = file_name.substr(0, lastindex);
    root_file_name = root_file_name + "_Interpolation_plots_" + plane + "_" + std::to_string(slice_cut) + ".root";
    auto* tf = new TFile(root_file_name.c_str(), "RECREATE");

    if(quantity == FieldQuantity::VECTOR) {
        exfield_map->Write(Form("%s X component", observable.c_str()));
        eyfield_map->Write(Form("%s Y component", observable.c_str()));
        ezfield_map->Write(Form("%s Z component", observable.c_str()));
    }

    efield_map->Write(Form("%s Norm", observable.c_str()));
    c1->cd();
    efield_map->Draw("colz");
    c1->SaveAs(output_file_name.c_str());
    tf->Close();
    return 0;
}
<commit_msg>MeshPlotter: register units<commit_after>#include <cmath>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include "TCanvas.h"
#include "TFile.h"
#include "TH2.h"
#include "TStyle.h"

#include "core/utils/unit.h"
#include "tools/field_parser.h"
#include "tools/units.h"

using namespace allpix;
int main(int argc, char** argv) {

    // Register the default set of units with this executable:
    allpix::register_units();

    // Set ROOT params
    gStyle->SetOptStat(0);
    gStyle->SetNumberContours(999);

    bool print_help = false;
    int return_code = 0;
    if(argc == 1) {
        print_help = true;
        return_code = 1;
    }

    // Read parameters
    std::string file_name;
    std::string output_file_name;
    std::string output_name_log;
    std::string plane = "yz";
    std::string units;
    bool flag_cut = false;
    size_t slice_cut = 0;
    bool log_scale = false;
    for(int i = 1; i < argc; i++) {
        if(strcmp(argv[i], "-h") == 0) {
            print_help = true;
        } else if(strcmp(argv[i], "-f") == 0 && (i + 1 < argc)) {
            file_name = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-o") == 0 && (i + 1 < argc)) {
            output_file_name = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-p") == 0 && (i + 1 < argc)) {
            plane = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-u") == 0 && (i + 1 < argc)) {
            units = std::string(argv[++i]);
        } else if(strcmp(argv[i], "-c") == 0 && (i + 1 < argc)) {
            slice_cut = static_cast<size_t>(std::atoi(argv[++i]));
            flag_cut = true;
        } else if(strcmp(argv[i], "-l") == 0) {
            log_scale = true;
        } else {
            std::cout << "Unrecognized command line argument or missing value\"" << argv[i] << std::endl;
            print_help = true;
            return_code = 1;
        }
    }

    if(file_name.empty()) {
        print_help = true;
        return_code = 1;
    }

    if(print_help) {
        std::cerr << "Usage: mesh_plotter -f <file_name> [<options>]" << std::endl;
        std::cout << "Required parameters:" << std::endl;
        std::cout << "\t -f <file_name>         name of the interpolated file in INIT or APF format" << std::endl;
        std::cout << "Optional parameters:" << std::endl;
        std::cout << "\t -c <cut>               projection height index (default is mesh_pitch / 2)" << std::endl;
        std::cout << "\t -h                     display this help text" << std::endl;
        std::cout << "\t -l                     plot with logarithmic scale if set" << std::endl;
        std::cout << "\t -o <output_file_name>  name of the file to output (default is efield.png)" << std::endl;
        std::cout << "\t -p <plane>             plane to be ploted. xy, yz or zx (default is yz)" << std::endl;
        std::cout << "\t -u <units>             units to interpret the field data in" << std::endl;
        return return_code;
    }

    // Read file
    std::cout << "Welcome to the Mesh Plotter Tool of Allpix^2 " << ALLPIX_PROJECT_VERSION << std::endl;
    std::cout << "Reading file: " << file_name;

    size_t firstindex = file_name.find_last_of('_');
    size_t lastindex = file_name.find_last_of('.');
    std::string observable = file_name.substr(firstindex + 1, lastindex - (firstindex + 1));
    std::string extension = file_name.substr(lastindex + 1, file_name.size() - lastindex);

    // FIXME this should be done in a more elegant way
    FieldQuantity quantity = (observable == "ElectricField" ? FieldQuantity::VECTOR : FieldQuantity::SCALAR);
    FileType type = (extension == "apf" ? FileType::APF : FileType::INIT);

    FieldParser<double> field_parser(quantity);
    auto field_data = field_parser.get_by_file_name(file_name, type, units);
    size_t xdiv = field_data.getDimensions()[0], ydiv = field_data.getDimensions()[1], zdiv = field_data.getDimensions()[2];

    std::cout << "Number of divisions in x/y/z: " << xdiv << "/" << ydiv << "/" << zdiv << std::endl;

    // Find plotting indices
    int x_bin = 0;
    int y_bin = 0;
    size_t start_x = 0, start_y = 0, start_z = 0;
    size_t stop_x = xdiv, stop_y = ydiv, stop_z = zdiv;
    if(plane == "xy") {
        if(!flag_cut) {
            slice_cut = (zdiv + 1) / 2;
        }

        // z is the slice:
        start_z = slice_cut;
        stop_z = start_z + 1;

        // scale the plot axes:
        x_bin = static_cast<int>(xdiv);
        y_bin = static_cast<int>(ydiv);
    } else if(plane == "yz") {
        if(!flag_cut) {
            slice_cut = (xdiv + 1) / 2;
        }

        // x is the slice:
        start_x = slice_cut;
        stop_x = start_x + 1;

        x_bin = static_cast<int>(ydiv);
        y_bin = static_cast<int>(zdiv);
    } else {
        if(!flag_cut) {
            slice_cut = (ydiv + 1) / 2;
        }

        // y is the slice:
        start_y = slice_cut;
        stop_y = start_y + 1;

        x_bin = static_cast<int>(zdiv);
        y_bin = static_cast<int>(xdiv);
    }

    // Create and fill histogram
    auto efield_map =
        new TH2D(Form("%s", observable.c_str()), Form("%s", observable.c_str()), x_bin, 1, x_bin + 1, y_bin, 1, y_bin + 1);
    auto exfield_map = new TH2D(Form("%s X component", observable.c_str()),
                                Form("%s X component", observable.c_str()),
                                x_bin + 1,
                                1,
                                x_bin + 1,
                                y_bin + 1,
                                1,
                                y_bin + 1);
    auto eyfield_map = new TH2D(Form("%s Y component", observable.c_str()),
                                Form("%s Y component", observable.c_str()),
                                x_bin + 1,
                                1,
                                x_bin + 1,
                                y_bin + 1,
                                1,
                                y_bin + 1);
    auto ezfield_map = new TH2D(Form("%s Z component", observable.c_str()),
                                Form("%s Z component", observable.c_str()),
                                x_bin + 1,
                                1,
                                x_bin + 1,
                                y_bin + 1,
                                1,
                                y_bin + 1);

    auto c1 = new TCanvas();

    if(log_scale) {
        c1->SetLogz();
        output_name_log = "_log";
    }

    int plot_x, plot_y;
    auto data = field_data.getData();
    for(size_t x = start_x; x < stop_x; x++) {
        for(size_t y = start_y; y < stop_y; y++) {
            for(size_t z = start_z; z < stop_z; z++) {
                // Select the indices for plotting:
                if(plane == "xy") {
                    plot_x = static_cast<int>(x);
                    plot_y = static_cast<int>(y);
                } else if(plane == "yz") {
                    plot_x = static_cast<int>(y);
                    plot_y = static_cast<int>(z);
                } else {
                    plot_x = static_cast<int>(z);
                    plot_y = static_cast<int>(x);
                }

                if(quantity == FieldQuantity::VECTOR) {
                    // Fill field maps for the individual vector components as well as the magnitude
                    auto base = x * ydiv * zdiv * 3 + y * zdiv * 3 + z * 3;
                    efield_map->Fill(
                        plot_x,
                        plot_y,
                        sqrt(pow(data->at(base + 0), 2) + pow(data->at(base + 1), 2) + pow(data->at(base + 2), 2)));
                    exfield_map->Fill(plot_x, plot_y, data->at(base + 0));
                    eyfield_map->Fill(plot_x, plot_y, data->at(base + 1));
                    ezfield_map->Fill(plot_x, plot_y, data->at(base + 2));

                } else {
                    // Fill one map with the scalar quantity
                    efield_map->Fill(plot_x, plot_y, data->at(x * ydiv * zdiv + y * zdiv + z));
                }
            }
        }
    }

    if(output_file_name.empty()) {
        output_file_name = file_name.substr(0, lastindex);
        output_file_name = output_file_name + "_" + plane + "_" + std::to_string(slice_cut) + output_name_log + ".png";
    }

    std::string root_file_name = file_name.substr(0, lastindex);
    root_file_name = root_file_name + "_Interpolation_plots_" + plane + "_" + std::to_string(slice_cut) + ".root";
    auto* tf = new TFile(root_file_name.c_str(), "RECREATE");

    if(quantity == FieldQuantity::VECTOR) {
        exfield_map->Write(Form("%s X component", observable.c_str()));
        eyfield_map->Write(Form("%s Y component", observable.c_str()));
        ezfield_map->Write(Form("%s Z component", observable.c_str()));
    }

    efield_map->Write(Form("%s Norm", observable.c_str()));
    c1->cd();
    efield_map->Draw("colz");
    c1->SaveAs(output_file_name.c_str());
    tf->Close();
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>added informative error dialogs.<commit_after><|endoftext|>


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

#include "SkImageDecoder.h"
#include "SkMovie.h"
#include "SkStream.h"
#include "SkTRegistry.h"

typedef SkTRegistry<SkImageDecoder*, SkStream*> DecodeReg;

template<> DecodeReg* DecodeReg::gHead;

#ifdef SK_ENABLE_LIBPNG
    extern SkImageDecoder* sk_libpng_dfactory(SkStream*);
#endif

SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
    SkImageDecoder* codec = NULL;
    const DecodeReg* curr = DecodeReg::Head();
    while (curr) {
        codec = curr->factory()(stream);
        // we rewind here, because we promise later when we call "decode", that
        // the stream will be at its beginning.
        stream->rewind();
        if (codec) {
            return codec;
        }
        curr = curr->next();
    }
#ifdef SK_ENABLE_LIBPNG
    codec = sk_libpng_dfactory(stream);
    stream->rewind();
    if (codec) {
        return codec;
    }
#endif
    return NULL;
}

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

typedef SkTRegistry<SkMovie*, SkStream*> MovieReg;

SkMovie* SkMovie::DecodeStream(SkStream* stream) {
    const MovieReg* curr = MovieReg::Head();
    while (curr) {
        SkMovie* movie = curr->factory()(stream);
        if (movie) {
            return movie;
        }
        // we must rewind only if we got NULL, since we gave the stream to the
        // movie, who may have already started reading from it
        stream->rewind();
        curr = curr->next();
    }
    return NULL;
}

<commit_msg>Compile fix for shared library builds.<commit_after>/* libs/graphics/ports/SkImageDecoder_Factory.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include "SkImageDecoder.h"
#include "SkMovie.h"
#include "SkStream.h"
#include "SkTRegistry.h"

typedef SkTRegistry<SkImageDecoder*, SkStream*> DecodeReg;

// N.B. You can't use "DecodeReg::gHead here" due to complex C++
// corner cases.
template DecodeReg* SkTRegistry<SkImageDecoder*, SkStream*>::gHead;

#ifdef SK_ENABLE_LIBPNG
    extern SkImageDecoder* sk_libpng_dfactory(SkStream*);
#endif

SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
    SkImageDecoder* codec = NULL;
    const DecodeReg* curr = DecodeReg::Head();
    while (curr) {
        codec = curr->factory()(stream);
        // we rewind here, because we promise later when we call "decode", that
        // the stream will be at its beginning.
        stream->rewind();
        if (codec) {
            return codec;
        }
        curr = curr->next();
    }
#ifdef SK_ENABLE_LIBPNG
    codec = sk_libpng_dfactory(stream);
    stream->rewind();
    if (codec) {
        return codec;
    }
#endif
    return NULL;
}

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

typedef SkTRegistry<SkMovie*, SkStream*> MovieReg;

SkMovie* SkMovie::DecodeStream(SkStream* stream) {
    const MovieReg* curr = MovieReg::Head();
    while (curr) {
        SkMovie* movie = curr->factory()(stream);
        if (movie) {
            return movie;
        }
        // we must rewind only if we got NULL, since we gave the stream to the
        // movie, who may have already started reading from it
        stream->rewind();
        curr = curr->next();
    }
    return NULL;
}

<|endoftext|>


<commit_before>
#ifndef __MIRRORED_CACHE_HPP__
#define __MIRRORED_CACHE_HPP__

#include "event_queue.hpp"
#include "cpu_context.hpp"
#include "concurrency/access.hpp"
#include "concurrency/rwi_lock.hpp"
#include "buffer_cache/callbacks.hpp"

// This cache doesn't actually do any operations itself. Instead, it
// provides a framework that collects all components of the cache
// (memory allocation, page lookup, page replacement, writeback, etc.)
// into a coherent whole. This allows easily experimenting with
// various components of the cache to improve performance.

/* Buffer class. */
// TODO: make sure we use small object allocator for buf_t
template <class config_t>
class buf : public iocallback_t,
            public config_t::writeback_t::local_buf_t,
            public config_t::concurrency_t::local_buf_t,
            public alloc_mixin_t<tls_small_obj_alloc_accessor<alloc_t>, buf<config_t> >
{
public:
    typedef typename config_t::serializer_t serializer_t;
    typedef typename config_t::transaction_t transaction_t;
    typedef typename config_t::concurrency_t concurrency_t;
    typedef typename config_t::cache_t cache_t;
    typedef typename config_t::node_t node_t;
    typedef block_available_callback<config_t> block_available_callback_t;

    buf(cache_t *cache, block_id_t block_id);
    ~buf();

    void release();

	// This function is called by the code that loads the data into the block. Other users, which
	// expect the block to already contain valid data, should call ptr().
	void *ptr_possibly_uncached() {
		// The buf should not be accessed unless it is locked. In fact, pointers to the buf should
    	// not exist, except in the page map, unless the block is locked, because any unlocked and
    	// non-dirty block is in danger of being swapped out by the page replacement system.
    	assert(concurrency_t::local_buf_t::lock.locked());
    	return data;
    }

    // TODO(NNW) We may want a const version of ptr() as well so the non-const
    // version can verify that the buf is writable; requires pushing const
    // through a bunch of other places (such as array_node also, however.
    void *ptr() {
    	assert(cached);
    	return ptr_possibly_uncached();
    }

    block_id_t get_block_id() const { return block_id; }

    void set_cached(bool _cached) { cached = _cached; }
    bool is_cached() const { return cached; }

    void set_dirty() { config_t::writeback_t::local_buf_t::set_dirty(this); }

    // Callback API
    void add_load_callback(block_available_callback_t *callback);

    void notify_on_load();

    virtual void on_io_complete(event_t *event);

private:
    cache_t *cache;
    block_id_t block_id;
    bool cached; /* Is data valid, or are we waiting for a read? */
    void *data;

    typedef intrusive_list_t<block_available_callback_t> callbacks_t;
    callbacks_t load_callbacks;

    // Incidentally, buf_t holds a redundant pointer to the cache object, because in addition to
    // the "cache_t *cache" declared in buf, writeback_t::local_buf_t declares its own
    // "writeback_tmpl_t *writeback". Each of these pointers will point to a different part of the
    // same cache object, because mirrored_cache_t is subclassed from writeback_t.

    // It also has a redundant pointer to itself, because concurrency_t::local_buf_t has a field
    // "buf_t *gbuf".
};

/* Transaction class. */
template <class config_t>
class transaction : public lock_available_callback_t,
                    public alloc_mixin_t<tls_small_obj_alloc_accessor<alloc_t>, transaction<config_t> >
{
public:
    typedef typename config_t::serializer_t serializer_t;
    typedef typename config_t::concurrency_t concurrency_t;
    typedef typename config_t::cache_t cache_t;
    typedef typename config_t::buf_t buf_t;
    typedef block_available_callback<config_t> block_available_callback_t;
    typedef transaction_begin_callback<config_t> transaction_begin_callback_t;
    typedef transaction_commit_callback<config_t> transaction_commit_callback_t;

    explicit transaction(cache_t *cache, access_t access,
        transaction_begin_callback_t *callback);
    ~transaction();

    cache_t *get_cache() const { return cache; }
    access_t get_access() const { return access; }

    bool commit(transaction_commit_callback_t *callback);

    buf_t *acquire(block_id_t block_id, access_t mode,
                   block_available_callback_t *callback);
    buf_t *allocate(block_id_t *new_block_id);

    /* The below function should *only* be called from writeback. */
    void committed(transaction_commit_callback_t *callback);

private:
    virtual void on_lock_available() { begin_callback->on_txn_begin(this); }

    cache_t *cache;
    access_t access;
    transaction_begin_callback_t *begin_callback;
    enum { state_open, state_committing, state_committed } state;

public:
#ifndef NDEBUG
    event_queue_t *event_queue; // For asserts that we haven't changed CPU.
#endif
};

template <class config_t>
struct mirrored_cache_t : public config_t::serializer_t,
                          public config_t::page_map_t,
                          public config_t::page_repl_t,
                          public config_t::writeback_t,
                          public buffer_alloc_t
{
public:
    typedef typename config_t::serializer_t serializer_t;
    typedef typename config_t::page_repl_t page_repl_t;
    typedef typename config_t::writeback_t writeback_t;
    typedef typename config_t::transaction_t transaction_t;
    typedef typename config_t::concurrency_t concurrency_t;
    typedef typename config_t::page_map_t page_map_t;
    typedef typename config_t::buf_t buf_t;

public:
    // TODO: how do we design communication between cache policies?
    // Should they all have access to the cache, or should they only
    // be given access to each other as necessary? The first is more
    // flexible as anyone can access anyone else, but encourages too
    // many dependencies. The second is more strict, but might not be
    // extensible when some policy implementation requires access to
    // components it wasn't originally given.
    mirrored_cache_t(size_t _block_size, size_t _max_size, bool wait_for_flush,
            unsigned int flush_interval_ms) :
        serializer_t(_block_size),
        page_repl_t(_block_size, _max_size, this, this, this),
        writeback_t(this, wait_for_flush, flush_interval_ms)
#ifndef NDEBUG
        , n_trans_created(0), n_trans_freed(0),
        n_blocks_acquired(0), n_blocks_released(0)
#endif
        {}
    ~mirrored_cache_t();

    void start() {
    	writeback_t::start();
    	page_repl_t::start();
    }
    void shutdown(sync_callback<config_t> *cb) {
    	writeback_t::shutdown(cb);
    	page_repl_t::shutdown(cb);
    }

    // Transaction API
    transaction_t *begin_transaction(access_t access,
        transaction_begin_callback<config_t> *callback);

    void aio_complete(buf_t *buf, bool written);

	/* do_unload_buf unloads a buf from memory, freeing the buf_t object. It should only be called
    on a buf that is not in use and not dirty. It is called by the cache's destructor and by the
    page replacement policy. */
    void do_unload_buf(buf_t *buf);

private:
	// TODO: This is boundary-crossing abstraction-breaking treachery. mirrored_cache_t should not
	// mess with the internals of the page map.
    using page_map_t::ft_map;

#ifndef NDEBUG
public:
    int n_trans_created, n_trans_freed;
    int n_blocks_acquired, n_blocks_released;
#endif
};

#include "buffer_cache/mirrored_impl.hpp"

#endif // __MIRRORED_CACHE_HPP__

<commit_msg>Removing old todo item<commit_after>
#ifndef __MIRRORED_CACHE_HPP__
#define __MIRRORED_CACHE_HPP__

#include "event_queue.hpp"
#include "cpu_context.hpp"
#include "concurrency/access.hpp"
#include "concurrency/rwi_lock.hpp"
#include "buffer_cache/callbacks.hpp"

// This cache doesn't actually do any operations itself. Instead, it
// provides a framework that collects all components of the cache
// (memory allocation, page lookup, page replacement, writeback, etc.)
// into a coherent whole. This allows easily experimenting with
// various components of the cache to improve performance.

/* Buffer class. */
template <class config_t>
class buf : public iocallback_t,
            public config_t::writeback_t::local_buf_t,
            public config_t::concurrency_t::local_buf_t,
            public alloc_mixin_t<tls_small_obj_alloc_accessor<alloc_t>, buf<config_t> >
{
public:
    typedef typename config_t::serializer_t serializer_t;
    typedef typename config_t::transaction_t transaction_t;
    typedef typename config_t::concurrency_t concurrency_t;
    typedef typename config_t::cache_t cache_t;
    typedef typename config_t::node_t node_t;
    typedef block_available_callback<config_t> block_available_callback_t;

    buf(cache_t *cache, block_id_t block_id);
    ~buf();

    void release();

	// This function is called by the code that loads the data into the block. Other users, which
	// expect the block to already contain valid data, should call ptr().
	void *ptr_possibly_uncached() {
		// The buf should not be accessed unless it is locked. In fact, pointers to the buf should
    	// not exist, except in the page map, unless the block is locked, because any unlocked and
    	// non-dirty block is in danger of being swapped out by the page replacement system.
    	assert(concurrency_t::local_buf_t::lock.locked());
    	return data;
    }

    // TODO(NNW) We may want a const version of ptr() as well so the non-const
    // version can verify that the buf is writable; requires pushing const
    // through a bunch of other places (such as array_node also, however.
    void *ptr() {
    	assert(cached);
    	return ptr_possibly_uncached();
    }

    block_id_t get_block_id() const { return block_id; }

    void set_cached(bool _cached) { cached = _cached; }
    bool is_cached() const { return cached; }

    void set_dirty() { config_t::writeback_t::local_buf_t::set_dirty(this); }

    // Callback API
    void add_load_callback(block_available_callback_t *callback);

    void notify_on_load();

    virtual void on_io_complete(event_t *event);

private:
    cache_t *cache;
    block_id_t block_id;
    bool cached; /* Is data valid, or are we waiting for a read? */
    void *data;

    typedef intrusive_list_t<block_available_callback_t> callbacks_t;
    callbacks_t load_callbacks;

    // Incidentally, buf_t holds a redundant pointer to the cache object, because in addition to
    // the "cache_t *cache" declared in buf, writeback_t::local_buf_t declares its own
    // "writeback_tmpl_t *writeback". Each of these pointers will point to a different part of the
    // same cache object, because mirrored_cache_t is subclassed from writeback_t.

    // It also has a redundant pointer to itself, because concurrency_t::local_buf_t has a field
    // "buf_t *gbuf".
};

/* Transaction class. */
template <class config_t>
class transaction : public lock_available_callback_t,
                    public alloc_mixin_t<tls_small_obj_alloc_accessor<alloc_t>, transaction<config_t> >
{
public:
    typedef typename config_t::serializer_t serializer_t;
    typedef typename config_t::concurrency_t concurrency_t;
    typedef typename config_t::cache_t cache_t;
    typedef typename config_t::buf_t buf_t;
    typedef block_available_callback<config_t> block_available_callback_t;
    typedef transaction_begin_callback<config_t> transaction_begin_callback_t;
    typedef transaction_commit_callback<config_t> transaction_commit_callback_t;

    explicit transaction(cache_t *cache, access_t access,
        transaction_begin_callback_t *callback);
    ~transaction();

    cache_t *get_cache() const { return cache; }
    access_t get_access() const { return access; }

    bool commit(transaction_commit_callback_t *callback);

    buf_t *acquire(block_id_t block_id, access_t mode,
                   block_available_callback_t *callback);
    buf_t *allocate(block_id_t *new_block_id);

    /* The below function should *only* be called from writeback. */
    void committed(transaction_commit_callback_t *callback);

private:
    virtual void on_lock_available() { begin_callback->on_txn_begin(this); }

    cache_t *cache;
    access_t access;
    transaction_begin_callback_t *begin_callback;
    enum { state_open, state_committing, state_committed } state;

public:
#ifndef NDEBUG
    event_queue_t *event_queue; // For asserts that we haven't changed CPU.
#endif
};

template <class config_t>
struct mirrored_cache_t : public config_t::serializer_t,
                          public config_t::page_map_t,
                          public config_t::page_repl_t,
                          public config_t::writeback_t,
                          public buffer_alloc_t
{
public:
    typedef typename config_t::serializer_t serializer_t;
    typedef typename config_t::page_repl_t page_repl_t;
    typedef typename config_t::writeback_t writeback_t;
    typedef typename config_t::transaction_t transaction_t;
    typedef typename config_t::concurrency_t concurrency_t;
    typedef typename config_t::page_map_t page_map_t;
    typedef typename config_t::buf_t buf_t;

public:
    // TODO: how do we design communication between cache policies?
    // Should they all have access to the cache, or should they only
    // be given access to each other as necessary? The first is more
    // flexible as anyone can access anyone else, but encourages too
    // many dependencies. The second is more strict, but might not be
    // extensible when some policy implementation requires access to
    // components it wasn't originally given.
    mirrored_cache_t(size_t _block_size, size_t _max_size, bool wait_for_flush,
            unsigned int flush_interval_ms) :
        serializer_t(_block_size),
        page_repl_t(_block_size, _max_size, this, this, this),
        writeback_t(this, wait_for_flush, flush_interval_ms)
#ifndef NDEBUG
        , n_trans_created(0), n_trans_freed(0),
        n_blocks_acquired(0), n_blocks_released(0)
#endif
        {}
    ~mirrored_cache_t();

    void start() {
    	writeback_t::start();
    	page_repl_t::start();
    }
    void shutdown(sync_callback<config_t> *cb) {
    	writeback_t::shutdown(cb);
    	page_repl_t::shutdown(cb);
    }

    // Transaction API
    transaction_t *begin_transaction(access_t access,
        transaction_begin_callback<config_t> *callback);

    void aio_complete(buf_t *buf, bool written);

	/* do_unload_buf unloads a buf from memory, freeing the buf_t object. It should only be called
    on a buf that is not in use and not dirty. It is called by the cache's destructor and by the
    page replacement policy. */
    void do_unload_buf(buf_t *buf);

private:
	// TODO: This is boundary-crossing abstraction-breaking treachery. mirrored_cache_t should not
	// mess with the internals of the page map.
    using page_map_t::ft_map;

#ifndef NDEBUG
public:
    int n_trans_created, n_trans_freed;
    int n_blocks_acquired, n_blocks_released;
#endif
};

#include "buffer_cache/mirrored_impl.hpp"

#endif // __MIRRORED_CACHE_HPP__

<|endoftext|>


<commit_before>#include "logger.h"
#include <iomanip>
#include <string>
#include <ctime>

namespace ncv
{
        logger_t::logger_t(std::ostream& stream, const char* header, bool flush)
                :       m_stream(stream), m_flush(flush)
        {
                log_time();
                m_stream << "[" << header << "]";
        }

        logger_t::~logger_t()
        {
                m_flush ? endl() : newl();
        }

        logger_t& logger_t::operator<<(const char* str)
        {
                m_stream << str;
                return *this;
        }

        logger_t& logger_t::operator<<(std::ostream& (*pf)(std::ostream&))
        {
                (*pf)(m_stream);
                return *this;
        }

        logger_t& logger_t::operator<<(logger_t& (*pf)(logger_t&))
        {
                return (*pf)(*this);
        }

        logger_t& logger_t::newl()
        {
                m_stream << "\n";
                return *this;
        }

        logger_t& logger_t::endl()
        {
                m_stream << std::endl;
                return *this;
        }

        logger_t& logger_t::done()
        {
                m_stream << "<<< program finished correctly >>>";
                return *this;
        }

        logger_t& logger_t::flush()
        {
                m_stream.flush();
                return *this;
        }

        void logger_t::log_time()
        {
                std::time_t t = std::time(nullptr);
                {
                        //m_stream << "[" << std::put_time(std::localtime(&t), "%c %Z") << "] ";
                }
                {
                        char buffer[128];
                        strftime(buffer, 128, "%Y:%m:%d %H:%M:%S", localtime(&t));
                        m_stream << "[" << buffer << "]";
                }
        }
}
<commit_msg>improve identation<commit_after>#include "logger.h"
#include <iomanip>
#include <string>
#include <ctime>

namespace ncv
{
        logger_t::logger_t(std::ostream& stream, const char* header, bool flush)
                :       m_stream(stream), m_flush(flush)
        {
                log_time();
                m_stream << "[" << header << "] ";
        }

        logger_t::~logger_t()
        {
                m_flush ? endl() : newl();
        }

        logger_t& logger_t::operator<<(const char* str)
        {
                m_stream << str;
                return *this;
        }

        logger_t& logger_t::operator<<(std::ostream& (*pf)(std::ostream&))
        {
                (*pf)(m_stream);
                return *this;
        }

        logger_t& logger_t::operator<<(logger_t& (*pf)(logger_t&))
        {
                return (*pf)(*this);
        }

        logger_t& logger_t::newl()
        {
                m_stream << "\n";
                return *this;
        }

        logger_t& logger_t::endl()
        {
                m_stream << std::endl;
                return *this;
        }

        logger_t& logger_t::done()
        {
                m_stream << "<<< program finished correctly >>>";
                return *this;
        }

        logger_t& logger_t::flush()
        {
                m_stream.flush();
                return *this;
        }

        void logger_t::log_time()
        {
                std::time_t t = std::time(nullptr);
                {
                        //m_stream << "[" << std::put_time(std::localtime(&t), "%c %Z") << "] ";
                }
                {
                        char buffer[128];
                        strftime(buffer, 128, "%Y:%m:%d %H:%M:%S", localtime(&t));
                        m_stream << "[" << buffer << "]";
                }
        }
}
<|endoftext|>


<commit_before>// Copyright 2010-2014 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This is the skeleton for the official flatzinc interpreter.  Much
// of the funcionnalities are fixed (name of parameters, format of the
// input): see http://www.minizinc.org/downloads/doc-1.6/flatzinc-spec.pdf

#include <iostream>  // NOLINT
#include <string>
#include <vector>

#include "base/commandlineflags.h"
#include "base/stringprintf.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/threadpool.h"
#include "base/timer.h"
#include "flatzinc2/model.h"
#include "flatzinc2/parser.h"
#include "flatzinc2/presolve.h"
#include "flatzinc2/search.h"
#include "flatzinc2/solver.h"

DEFINE_int32(log_period, 10000000, "Search log period");
DEFINE_bool(all, false, "Search for all solutions");
DEFINE_bool(free, false, "Ignore search annotations");
DEFINE_int32(num_solutions, 0, "Number of solution to search for");
DEFINE_int32(time_limit, 0, "time limit in ms");
DEFINE_int32(workers, 0, "Number of workers");
DEFINE_bool(use_impact, false, "Use impact based search");
DEFINE_double(restart_log_size, -1, "Restart log size for impact search");
DEFINE_int32(luby_restart, -1, "Luby restart factor, <= 0 = no luby");
DEFINE_int32(heuristic_period, 100, "Period to call heuristics in free search");
DEFINE_bool(verbose_impact, false, "Verbose impact");
DEFINE_bool(verbose_mt, false, "Verbose Multi-Thread");
DEFINE_bool(presolve, true, "Use presolve.");

DECLARE_bool(fz_logging);
DECLARE_bool(log_prefix);
DECLARE_bool(use_sat);

using operations_research::ThreadPool;

namespace operations_research {
void Run(const std::string& filename, const FzSolverParameters& parameters,
         FzParallelSupportInterface* parallel_support) {
  WallTimer timer;
  timer.Start();
  std::string problem_name(filename);
  problem_name.resize(problem_name.size() - 4);
  size_t found = problem_name.find_last_of("/\\");
  if (found != std::string::npos) {
    problem_name = problem_name.substr(found + 1);
  }
  FzModel model(problem_name);
  CHECK(ParseFlatzincFile(filename, &model));
  FZLOG << "File " << filename << " parsed in " << timer.GetInMs() << " ms"
        << FZENDL;
  FzPresolver presolve;
  presolve.CleanUpModelForTheCpSolver(&model, FLAGS_use_sat);
  if (FLAGS_presolve) {
    FZLOG << "Presolve model" << FZENDL;
    timer.Reset();
    timer.Start();
    presolve.Run(&model);
    FZLOG << "  - done in " << timer.GetInMs() << " ms" << FZENDL;
  }
  FzModelStatistics stats(model);
  stats.PrintStatistics();
  FzSolver solver(model);
  CHECK(solver.Extract());
  solver.Solve(parameters, parallel_support);
}

void SequentialRun(const std::string& filename) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.free_search = FLAGS_free;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = FLAGS_log_period;
  parameters.luby_restart = FLAGS_luby_restart;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.restart_log_size = FLAGS_restart_log_size;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = FLAGS_fz_logging;
  parameters.verbose_impact = FLAGS_verbose_impact;
  parameters.worker_id = -1;
  parameters.search_type =
      FLAGS_use_impact ? FzSolverParameters::IBS : FzSolverParameters::DEFAULT;

  std::unique_ptr<FzParallelSupportInterface> parallel_support(
      operations_research::MakeSequentialSupport(parameters.all_solutions,
                                                 parameters.num_solutions));
  Run(filename, parameters, parallel_support.get());
}

void ParallelRun(char* const file, int worker_id,
                 FzParallelSupportInterface* parallel_support) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = 0;
  parameters.luby_restart = -1;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.random_seed = worker_id * 10;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = false;
  parameters.verbose_impact = false;
  parameters.worker_id = worker_id;
  switch (worker_id) {
    case 0: {
      parameters.free_search = false;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 1: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::MIN_SIZE;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 2: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::IBS;
      parameters.restart_log_size = FLAGS_restart_log_size;
      break;
    }
    case 3: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::FIRST_UNBOUND;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 10000000;
      break;
    }
    case 4: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 30;
      parameters.run_all_heuristics = true;
      break;
    }
    default: {
      parameters.free_search = true;
      parameters.search_type =
          worker_id % 2 == 0
              ? operations_research::FzSolverParameters::RANDOM_MIN
              : operations_research::FzSolverParameters::RANDOM_MAX;
      parameters.restart_log_size = -1.0;
      parameters.luby_restart = 250;
    }
  }
  Run(file, parameters, parallel_support);
}

void FixAndParseParameters(int* argc, char*** argv) {
  FLAGS_log_prefix = false;
  char all_param[] = "--all";
  char free_param[] = "--free";
  char workers_param[] = "--workers";
  char solutions_param[] = "--num_solutions";
  char logging_param[] = "--fz_logging";
  char verbose_param[] = "--fz_verbose";
  char debug_param[] = "--fz_debug";
  for (int i = 1; i < *argc; ++i) {
    if (strcmp((*argv)[i], "-a") == 0) {
      (*argv)[i] = all_param;
    }
    if (strcmp((*argv)[i], "-f") == 0) {
      (*argv)[i] = free_param;
    }
    if (strcmp((*argv)[i], "-p") == 0) {
      (*argv)[i] = workers_param;
    }
    if (strcmp((*argv)[i], "-n") == 0) {
      (*argv)[i] = solutions_param;
    }
    if (strcmp((*argv)[i], "-l") == 0) {
      (*argv)[i] = logging_param;
    }
    if (strcmp((*argv)[i], "-v") == 0) {
      (*argv)[i] = verbose_param;
    }
    if (strcmp((*argv)[i], "-d") == 0) {
      (*argv)[i] = debug_param;
    }
  }
  google::ParseCommandLineFlags(argc, argv, true);
  // Fix the number of solutions.
  if (FLAGS_num_solutions == 0) {  // not specified
    FLAGS_num_solutions = FLAGS_all ? kint32max : 1;
  }
}
}  // namespace operations_research

int main(int argc, char** argv) {
  operations_research::FixAndParseParameters(&argc, &argv);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  if (FLAGS_workers == 0) {
    operations_research::SequentialRun(argv[1]);
  } else {
    std::unique_ptr<operations_research::FzParallelSupportInterface>
        parallel_support(operations_research::MakeMtSupport(
            FLAGS_all, FLAGS_num_solutions, FLAGS_verbose_mt));
    {
      ThreadPool pool("Parallel FlatZinc", FLAGS_workers);
      pool.StartWorkers();
      for (int w = 0; w < FLAGS_workers; ++w) {
        pool.Add(NewCallback(&operations_research::ParallelRun, argv[1], w,
                             parallel_support.get()));
      }
    }
  }
  return 0;
}
<commit_msg>revisit fz2's implementation of parallelism<commit_after>// Copyright 2010-2014 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This is the skeleton for the official flatzinc interpreter.  Much
// of the funcionnalities are fixed (name of parameters, format of the
// input): see http://www.minizinc.org/downloads/doc-1.6/flatzinc-spec.pdf

#include <iostream>  // NOLINT
#include <string>
#include <vector>

#include "base/commandlineflags.h"
#include "base/stringprintf.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/threadpool.h"
#include "base/timer.h"
#include "flatzinc2/model.h"
#include "flatzinc2/parser.h"
#include "flatzinc2/presolve.h"
#include "flatzinc2/search.h"
#include "flatzinc2/solver.h"

DEFINE_int32(log_period, 10000000, "Search log period");
DEFINE_bool(all, false, "Search for all solutions");
DEFINE_bool(free, false, "Ignore search annotations");
DEFINE_int32(num_solutions, 0, "Number of solution to search for");
DEFINE_int32(time_limit, 0, "time limit in ms");
DEFINE_int32(workers, 0, "Number of workers");
DEFINE_bool(use_impact, false, "Use impact based search");
DEFINE_double(restart_log_size, -1, "Restart log size for impact search");
DEFINE_int32(luby_restart, -1, "Luby restart factor, <= 0 = no luby");
DEFINE_int32(heuristic_period, 100, "Period to call heuristics in free search");
DEFINE_bool(verbose_impact, false, "Verbose impact");
DEFINE_bool(verbose_mt, false, "Verbose Multi-Thread");
DEFINE_bool(presolve, true, "Use presolve.");

DECLARE_bool(fz_logging);
DECLARE_bool(log_prefix);
DECLARE_bool(use_sat);

using operations_research::ThreadPool;

namespace operations_research {
void Solve(const FzModel* const model, const FzSolverParameters& parameters,
           FzParallelSupportInterface* parallel_support) {
  FzSolver solver(*model);
  CHECK(solver.Extract());
  solver.Solve(parameters, parallel_support);
}

void SequentialRun(const FzModel* model) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.free_search = FLAGS_free;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = FLAGS_log_period;
  parameters.luby_restart = FLAGS_luby_restart;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.restart_log_size = FLAGS_restart_log_size;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = FLAGS_fz_logging;
  parameters.verbose_impact = FLAGS_verbose_impact;
  parameters.worker_id = -1;
  parameters.search_type =
      FLAGS_use_impact ? FzSolverParameters::IBS : FzSolverParameters::DEFAULT;

  std::unique_ptr<FzParallelSupportInterface> parallel_support(
      MakeSequentialSupport(FLAGS_all, FLAGS_num_solutions));
  Solve(model, parameters, parallel_support.get());
}

void ParallelRun(const FzModel* const model, int worker_id,
                 FzParallelSupportInterface* parallel_support) {
  FzSolverParameters parameters;
  parameters.all_solutions = FLAGS_all;
  parameters.heuristic_period = FLAGS_heuristic_period;
  parameters.ignore_unknown = false;
  parameters.log_period = 0;
  parameters.luby_restart = -1;
  parameters.num_solutions = FLAGS_num_solutions;
  parameters.random_seed = worker_id * 10;
  parameters.threads = FLAGS_workers;
  parameters.time_limit_in_ms = FLAGS_time_limit;
  parameters.use_log = false;
  parameters.verbose_impact = false;
  parameters.worker_id = worker_id;
  switch (worker_id) {
    case 0: {
      parameters.free_search = false;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 1: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::MIN_SIZE;
      parameters.restart_log_size = -1.0;
      break;
    }
    case 2: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::IBS;
      parameters.restart_log_size = FLAGS_restart_log_size;
      break;
    }
    case 3: {
      parameters.free_search = true;
      parameters.search_type =
          operations_research::FzSolverParameters::FIRST_UNBOUND;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 10000000;
      break;
    }
    case 4: {
      parameters.free_search = true;
      parameters.search_type = operations_research::FzSolverParameters::DEFAULT;
      parameters.restart_log_size = -1.0;
      parameters.heuristic_period = 30;
      parameters.run_all_heuristics = true;
      break;
    }
    default: {
      parameters.free_search = true;
      parameters.search_type =
          worker_id % 2 == 0
              ? operations_research::FzSolverParameters::RANDOM_MIN
              : operations_research::FzSolverParameters::RANDOM_MAX;
      parameters.restart_log_size = -1.0;
      parameters.luby_restart = 250;
    }
  }
  Solve(model, parameters, parallel_support);
}

void FixAndParseParameters(int* argc, char*** argv) {
  FLAGS_log_prefix = false;
  char all_param[] = "--all";
  char free_param[] = "--free";
  char workers_param[] = "--workers";
  char solutions_param[] = "--num_solutions";
  char logging_param[] = "--fz_logging";
  char verbose_param[] = "--fz_verbose";
  char debug_param[] = "--fz_debug";
  for (int i = 1; i < *argc; ++i) {
    if (strcmp((*argv)[i], "-a") == 0) {
      (*argv)[i] = all_param;
    }
    if (strcmp((*argv)[i], "-f") == 0) {
      (*argv)[i] = free_param;
    }
    if (strcmp((*argv)[i], "-p") == 0) {
      (*argv)[i] = workers_param;
    }
    if (strcmp((*argv)[i], "-n") == 0) {
      (*argv)[i] = solutions_param;
    }
    if (strcmp((*argv)[i], "-l") == 0) {
      (*argv)[i] = logging_param;
    }
    if (strcmp((*argv)[i], "-v") == 0) {
      (*argv)[i] = verbose_param;
    }
    if (strcmp((*argv)[i], "-d") == 0) {
      (*argv)[i] = debug_param;
    }
  }
  google::ParseCommandLineFlags(argc, argv, true);
  // Fix the number of solutions.
  if (FLAGS_num_solutions == 0) {  // not specified
    FLAGS_num_solutions = FLAGS_all ? kint32max : 1;
  }
}

void ParseAndRun(const std::string& filename, int num_workers) {
  WallTimer timer;
  timer.Start();
  std::string problem_name(filename);
  problem_name.resize(problem_name.size() - 4);
  size_t found = problem_name.find_last_of("/\\");
  if (found != std::string::npos) {
    problem_name = problem_name.substr(found + 1);
  }
  FzModel model(problem_name);
  CHECK(ParseFlatzincFile(filename, &model));
  FZLOG << "File " << filename << " parsed in " << timer.GetInMs() << " ms"
        << FZENDL;
  FzPresolver presolve;
  presolve.CleanUpModelForTheCpSolver(&model, FLAGS_use_sat);
  if (FLAGS_presolve) {
    FZLOG << "Presolve model" << FZENDL;
    timer.Reset();
    timer.Start();
    presolve.Run(&model);
    FZLOG << "  - done in " << timer.GetInMs() << " ms" << FZENDL;
  }
  FzModelStatistics stats(model);
  stats.PrintStatistics();

  if (num_workers == 0) {
    operations_research::SequentialRun(&model);
  } else {
    std::unique_ptr<operations_research::FzParallelSupportInterface>
        parallel_support(operations_research::MakeMtSupport(
            FLAGS_all, FLAGS_num_solutions, FLAGS_verbose_mt));
    {
      ThreadPool pool("Parallel FlatZinc", num_workers);
      for (int w = 0; w < num_workers; ++w) {
        pool.Add(NewCallback(ParallelRun, &model, w, parallel_support.get()));
      }
      pool.StartWorkers();
    }
  }
}
}  // namespace operations_research

int main(int argc, char** argv) {
  operations_research::FixAndParseParameters(&argc, &argv);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  operations_research::ParseAndRun(argv[1], FLAGS_workers);
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Fix a bug about a flag to revert image.<commit_after><|endoftext|>


<commit_before>#include <ncurses.h>

#include "../../../src/contents.hh"
#include "../../../src/key_aliases.hh"
#include "../../../src/show_message.hh"
#include "../../vick-move/src/move.hh"

struct cons3_c : public change {
    std::shared_ptr< change > a, b, c;
    cons3_c(change* a, change* b, change* c) : a(a), b(b), c(c) {}

    virtual bool is_overriding() override {
        return a->is_overriding() || b->is_overriding() || c->is_overriding();
    }
    virtual void undo(contents& contents) override {
        a->undo(contents);
        b->undo(contents);
        c->undo(contents);
    }
    virtual void redo(contents& contents) override {
        c->redo(contents);
        b->redo(contents);
        a->redo(contents);
    }
    virtual std::shared_ptr< change >
    regenerate(const contents& contents) const override {
        return std::make_shared< cons3_c >(contents, *a, *b, *c);
    }
    cons3_c(const contents& contents, const change& a, const change& b,
            const change& c)
        : a(a.regenerate(contents)), b(b.regenerate(contents)),
          c(c.regenerate(contents)) {}
};

struct insert_c : public change {
    unsigned long y, x;
    insert_c() {}

    virtual bool is_overriding() override { return true; }
    virtual void undo(contents& contents) override {
        contents.y = y;
        contents.x = x;
    }
    virtual void redo(contents& contents) override {}
    virtual std::shared_ptr< change >
    regenerate(const contents& contents) const override {}
};

boost::optional< std::shared_ptr< change > >
enter_insert_mode(contents& contents, boost::optional< int >) {
    char ch;
    show_message("--INSERT--");
    contents.is_inserting = true;
    if (contents.refresh) {
        print_contents(contents);
        show_message("--INSERT--");
    }
    while ((ch = getch()) != _escape) {
        auto event = global_insert_map.find(ch);
        if (event != global_insert_map.end()) {
            event->second(contents, 0);
        } else if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
        } else {
            contents.cont[contents.y][contents.x] = ch;
            contents.x++;
        }
        if (contents.refresh) {
            print_contents(contents);
            show_message("--INSERT--");
        }
    }
    contents.is_inserting = false;
    showing_message = false;
    return boost::none;
}
<commit_msg>Remove insert_mode2.cc<commit_after><|endoftext|>


<commit_before><commit_msg>Added point sources to the new interface<commit_after><|endoftext|>