<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "journaldwatcher.h"

#include <utils/algorithm.h>
#include <utils/qtcassert.h>

#include <QSocketNotifier>

#include <systemd/sd-journal.h>

namespace ProjectExplorer {

JournaldWatcher *JournaldWatcher::m_instance = 0;

namespace Internal {

class JournaldWatcherPrivate
{
public:
    JournaldWatcherPrivate() :
        m_journalContext(0),
        m_notifier(0)
    { }

    ~JournaldWatcherPrivate()
    {
        teardown();
    }

    bool setup();
    void teardown();

    JournaldWatcher::LogEntry retrieveEntry();

    class SubscriberInformation {
    public:
        SubscriberInformation(QObject *sr, const JournaldWatcher::Subscription &sn) :
            subscriber(sr), subscription(sn)
        { }

        QObject *subscriber;
        JournaldWatcher::Subscription subscription;
    };
    QList<SubscriberInformation> m_subscriptions;

    sd_journal *m_journalContext;
    QSocketNotifier *m_notifier;
};

bool JournaldWatcherPrivate::setup()
{
    QTC_ASSERT(!m_journalContext, return false);
    int r = sd_journal_open(&m_journalContext, 0);
    if (r != 0)
        return false;

    r = sd_journal_seek_tail(m_journalContext);
    if (r != 0)
        return false;

    // Work around https://bugs.freedesktop.org/show_bug.cgi?id=64614
    sd_journal_previous(m_journalContext);

    int fd = sd_journal_get_fd(m_journalContext);
    if (fd < 0)
        return false;

    m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read);
    return true;
}

void JournaldWatcherPrivate::teardown()
{
    delete m_notifier;
    m_notifier = 0;

    if (m_journalContext) {
        sd_journal_close(m_journalContext);
        m_journalContext = 0;
    }
}

JournaldWatcher::LogEntry JournaldWatcherPrivate::retrieveEntry()
{
    JournaldWatcher::LogEntry result;

    // Advance:
    int r = sd_journal_next(m_journalContext);
    if (r == 0)
        return result;

    const void *rawData;
    size_t length;
    SD_JOURNAL_FOREACH_DATA(m_journalContext, rawData, length) {
        QByteArray tmp = QByteArray::fromRawData(static_cast<const char *>(rawData), length);
        int offset = tmp.indexOf('=');
        if (offset < 0)
            continue;
        result.insert(tmp.left(offset), tmp.mid(offset + 1));
    }

    return result;
}

} // namespace Internal

using namespace Internal;

static JournaldWatcherPrivate *d = 0;

JournaldWatcher::~JournaldWatcher()
{
    d->teardown();

    m_instance = 0;

    delete d;
    d = 0;
}

JournaldWatcher *JournaldWatcher::instance()
{
    return m_instance;
}

const QByteArray &JournaldWatcher::machineId()
{
    static QByteArray id;
    if (id.isEmpty()) {
        sd_id128 sdId;
        if (sd_id128_get_machine(&sdId) == 0)
            id = QByteArray(reinterpret_cast<char *>(sdId.bytes), 16);
    }
    return id;
}

bool JournaldWatcher::subscribe(QObject *subscriber, const Subscription &subscription)
{
    // Check that we do not have that subscriber yet:
    int pos = Utils::indexOf(d->m_subscriptions,
                             [subscriber](const JournaldWatcherPrivate::SubscriberInformation &info) {
                                 return info.subscriber == subscriber;
                             });
    QTC_ASSERT(pos >= 0, return false);

    d->m_subscriptions.append(JournaldWatcherPrivate::SubscriberInformation(subscriber, subscription));
    connect(subscriber, &QObject::destroyed, m_instance, &JournaldWatcher::unsubscribe);

    return true;
}

void JournaldWatcher::unsubscribe(QObject *subscriber)
{
    int pos = Utils::indexOf(d->m_subscriptions,
                            [subscriber](const JournaldWatcherPrivate::SubscriberInformation &info) {
                                return info.subscriber == subscriber;
                            });
    if (pos < 0)
        return;

    d->m_subscriptions.removeAt(pos);
}

JournaldWatcher::JournaldWatcher()
{
    QTC_ASSERT(!m_instance, return);

    d = new JournaldWatcherPrivate;
    m_instance = this;

    if (!d->setup())
        d->teardown();
    else
        connect(d->m_notifier, &QSocketNotifier::activated, m_instance, &JournaldWatcher::handleEntry);
    m_instance->handleEntry(); // advance to the end of file...
}

void JournaldWatcher::handleEntry()
{
    if (!d->m_notifier)
        return;

    LogEntry logEntry;
    forever {
        logEntry = d->retrieveEntry();
        if (logEntry.isEmpty())
            break;

        foreach (const JournaldWatcherPrivate::SubscriberInformation &info, d->m_subscriptions)
            info.subscription(logEntry);

        if (logEntry.value(QByteArrayLiteral("_MACHINE_ID")) != machineId())
            continue;

        const QByteArray pid = logEntry.value(QByteArrayLiteral("_PID"));
        quint64 pidNum = pid.isEmpty() ? 0 : QString::fromLatin1(pid).toInt();

        QString message = QString::fromUtf8(logEntry.value(QByteArrayLiteral("MESSAGE")));

        emit journaldOutput(pidNum, message);
    }
}

} // namespace ProjectExplorer
<commit_msg>Journald: Fix reading of entries logged into journald<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "journaldwatcher.h"

#include <utils/algorithm.h>
#include <utils/qtcassert.h>

#include <QSocketNotifier>

#include <systemd/sd-journal.h>

namespace ProjectExplorer {

JournaldWatcher *JournaldWatcher::m_instance = 0;

namespace Internal {

class JournaldWatcherPrivate
{
public:
    JournaldWatcherPrivate() :
        m_journalContext(0),
        m_notifier(0)
    { }

    ~JournaldWatcherPrivate()
    {
        teardown();
    }

    bool setup();
    void teardown();

    JournaldWatcher::LogEntry retrieveEntry();

    class SubscriberInformation {
    public:
        SubscriberInformation(QObject *sr, const JournaldWatcher::Subscription &sn) :
            subscriber(sr), subscription(sn)
        { }

        QObject *subscriber;
        JournaldWatcher::Subscription subscription;
    };
    QList<SubscriberInformation> m_subscriptions;

    sd_journal *m_journalContext;
    QSocketNotifier *m_notifier;
};

bool JournaldWatcherPrivate::setup()
{
    QTC_ASSERT(!m_journalContext, return false);
    int r = sd_journal_open(&m_journalContext, 0);
    if (r != 0)
        return false;

    r = sd_journal_seek_tail(m_journalContext);
    if (r != 0)
        return false;

    // Work around https://bugs.freedesktop.org/show_bug.cgi?id=64614
    sd_journal_previous(m_journalContext);

    int fd = sd_journal_get_fd(m_journalContext);
    if (fd < 0)
        return false;

    m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read);
    return true;
}

void JournaldWatcherPrivate::teardown()
{
    delete m_notifier;
    m_notifier = 0;

    if (m_journalContext) {
        sd_journal_close(m_journalContext);
        m_journalContext = 0;
    }
}

JournaldWatcher::LogEntry JournaldWatcherPrivate::retrieveEntry()
{
    JournaldWatcher::LogEntry result;

    // Advance:
    int r = sd_journal_next(m_journalContext);
    if (r == 0)
        return result;

    const void *rawData;
    size_t length;
    SD_JOURNAL_FOREACH_DATA(m_journalContext, rawData, length) {
        QByteArray tmp = QByteArray::fromRawData(static_cast<const char *>(rawData), length);
        int offset = tmp.indexOf('=');
        if (offset < 0)
            continue;
        result.insert(tmp.left(offset), tmp.mid(offset + 1));
    }

    return result;
}

} // namespace Internal

using namespace Internal;

static JournaldWatcherPrivate *d = 0;

JournaldWatcher::~JournaldWatcher()
{
    d->teardown();

    m_instance = 0;

    delete d;
    d = 0;
}

JournaldWatcher *JournaldWatcher::instance()
{
    return m_instance;
}

const QByteArray &JournaldWatcher::machineId()
{
    static QByteArray id;
    if (id.isEmpty()) {
        sd_id128 sdId;
        if (sd_id128_get_machine(&sdId) == 0) {
            id.resize(32);
            sd_id128_to_string(sdId, id.data());
        }
    }
    return id;
}

bool JournaldWatcher::subscribe(QObject *subscriber, const Subscription &subscription)
{
    // Check that we do not have that subscriber yet:
    int pos = Utils::indexOf(d->m_subscriptions,
                             [subscriber](const JournaldWatcherPrivate::SubscriberInformation &info) {
                                 return info.subscriber == subscriber;
                             });
    QTC_ASSERT(pos >= 0, return false);

    d->m_subscriptions.append(JournaldWatcherPrivate::SubscriberInformation(subscriber, subscription));
    connect(subscriber, &QObject::destroyed, m_instance, &JournaldWatcher::unsubscribe);

    return true;
}

void JournaldWatcher::unsubscribe(QObject *subscriber)
{
    int pos = Utils::indexOf(d->m_subscriptions,
                            [subscriber](const JournaldWatcherPrivate::SubscriberInformation &info) {
                                return info.subscriber == subscriber;
                            });
    if (pos < 0)
        return;

    d->m_subscriptions.removeAt(pos);
}

JournaldWatcher::JournaldWatcher()
{
    QTC_ASSERT(!m_instance, return);

    d = new JournaldWatcherPrivate;
    m_instance = this;

    if (!d->setup())
        d->teardown();
    else
        connect(d->m_notifier, &QSocketNotifier::activated, m_instance, &JournaldWatcher::handleEntry);
    m_instance->handleEntry(); // advance to the end of file...
}

void JournaldWatcher::handleEntry()
{
    if (!d->m_notifier)
        return;

    if (sd_journal_process(d->m_journalContext) != SD_JOURNAL_APPEND)
        return;

    LogEntry logEntry;
    forever {
        logEntry = d->retrieveEntry();
        if (logEntry.isEmpty())
            break;

        foreach (const JournaldWatcherPrivate::SubscriberInformation &info, d->m_subscriptions)
            info.subscription(logEntry);

        if (logEntry.value(QByteArrayLiteral("_MACHINE_ID")) != machineId())
            continue;

        const QByteArray pid = logEntry.value(QByteArrayLiteral("_PID"));
        quint64 pidNum = pid.isEmpty() ? 0 : QString::fromLatin1(pid).toInt();

        QString message = QString::fromUtf8(logEntry.value(QByteArrayLiteral("MESSAGE")));
        message.append(QLatin1Char('\n')); // Add newline.

        emit journaldOutput(pidNum, message);
    }
}

} // namespace ProjectExplorer
<|endoftext|>


<commit_before>#include <cstdlib>
#include <iostream>

#include "complex.hpp"

#include "lodepng.h"

using std::cout;
using std::vector;

unsigned eval(const complex comp, unsigned max,
              const complex arg)
{
    complex c = comp;
    for (unsigned i = 0; i < max; i++)
    {
        if (c.abs() > 2)
            return i;
        c = c * c + arg;
    }
    return max;
}

void set_pixel(unsigned char r, unsigned char g, unsigned char b,
               unsigned x, unsigned y, vector<unsigned char> &vec,
               unsigned height)
{
    unsigned index = (x + y * height) * 4;
    vec.at(index + 0) = r;
    vec.at(index + 1) = g;
    vec.at(index + 2) = b;
    vec.at(index + 3) = 0xff;
}

int main(int argc, char** argv)
{
    if (argc < 4) {
        cout << "too few arguments!\n";
        cout << "usage: mandelbrot <width> <height> <scale>\n";
        cout << "                  ";
        cout << "[cr + ci] [color depth] [offx] [offy]\n";
        return -1;
    }

    unsigned width = atoi(argv[1]);
    unsigned height = atoi(argv[2]);
    double size = atof(argv[3]);
    unsigned color_depth = 255;
    double offx = -0.5;
    double offy = 0.0;
    bool mandel = true;
    complex c_arg(0, 0);
    auto file = "fractal.png";

    if (argc > 4 && std::string(argv[4]) != "mandelbrot") {
        mandel = false;
        offx = 0;
        offy = 0;
        std::string str(argv[4]);
        unsigned pos = 0;
        for (unsigned i = 0; i < str.size(); i++)
        {
            if (str.at(i) == '+') {
                pos = i + 1;
                break;
            }
        }
        if (pos == 0) {
            cout << "invalid complex value!\n";
            return -1;
        }
        double real = atof(str.substr(0, pos - 1).c_str());
        double imag = atof(str.substr(pos, str.size() - pos).c_str());
        c_arg = complex(real, imag);
    }

    if (argc > 5)
        color_depth = atof(argv[5]);
    if (argc > 6)
        offx = atof(argv[6]);
    if (argc > 7)
        offy = atof(argv[7]);
    if (argc > 8)
        cout << "warning -- extra arguments, ignoring them.\n";

    vector<unsigned char> image(width * height * 4);

    auto lerp = [&] (double x0, double y0,
                    double x1, double y1,
                    double t)
    {
        double m = (y1 - y0) / (x1 - x0);
        return y0 + t * m;
    };

    const auto A_R = 67;
    const auto A_G = 10;
    const auto A_B = 42;

    const auto B_R = 232;
    const auto B_G = 56;
    const auto B_B = 56;

    const auto D_R = 21;
    const auto D_G = 21;
    const auto D_B = 21;

    auto comp_color_r = [&] (unsigned val)
    {
        if (val == color_depth)
            return D_R;
        double rat = (double) val / color_depth;
        double dc = lerp(0, A_R, 1, B_R, rat);
        return (int) dc;
    };

    auto comp_color_g = [&] (unsigned val)
    {
        if (val == color_depth)
            return D_G;
        double rat = (double) val / color_depth;
        double dc = lerp(0, A_G, 1, B_G, rat);
        return (int) dc;
    };

    auto comp_color_b = [&] (unsigned val)
    {
        if (val == color_depth)
            return D_B;
        double rat = (double) val / color_depth;
        double dc = lerp(0, A_B, 1, B_B, rat);
        return (int) dc;
    };

    double r;
    double i;
    complex c;
    unsigned color;
    for (unsigned x = 0; x < width; x++)
    {
        for (unsigned y = 0; y < height; y++)
        {
            r = offx - size / 2 + size * x / width;
            i = offy - size / 2 + size * y / height;
            c = complex(r, i);
            if (mandel)
                color = eval(c, color_depth, c);
            else
                color = eval(c, color_depth, c_arg);
            set_pixel(comp_color_r(color),
                      comp_color_g(color),
                      comp_color_b(color),
                      x, y, image, height);
        }
    }

    unsigned error = lodepng::encode(file, image, width, height);
    if (error)
        cout << "error -- " << lodepng_error_text(error) << std::endl;

    return 0;
}
<commit_msg>add color parsing<commit_after>#include <cstdlib>
#include <iostream>

#include "complex.hpp"

#include "lodepng.h"

using std::cout;
using std::vector;

unsigned eval(const complex comp, unsigned max,
              const complex arg)
{
    complex c = comp;
    for (unsigned i = 0; i < max; i++)
    {
        if (c.abs() > 2)
            return i;
        c = c * c + arg;
    }
    return max;
}

void set_pixel(unsigned char r, unsigned char g, unsigned char b,
               unsigned x, unsigned y, vector<unsigned char> &vec,
               unsigned height)
{
    unsigned index = (x + y * height) * 4;
    vec.at(index + 0) = r;
    vec.at(index + 1) = g;
    vec.at(index + 2) = b;
    vec.at(index + 3) = 0xff;
}

unsigned char htoi(std::string str)
{
    if (str.size() != 2)
        return 0;
    unsigned char res = 0;
    unsigned char c = str.at(0);
    if (c >= '0' && c <= '9')
        res += (c - 0x30) * 16;
    else if (c >= 'a' && c <= 'f')
        res += (c - 'a' + 10) * 16;
    else if (c >= 'A' && c <= 'F')
        res += (c - 'A' + 10) * 16;
    else
        cout << "unknown hex char '" << c << "'.\n";

    c = str.at(1);
    if (c >= '0' && c <= '9')
        res += (c - 0x30) * 1;
    else if (c >= 'a' && c <= 'f')
        res += (c - 'a' + 10) * 1;
    else if (c >= 'A' && c <= 'F')
        res += (c - 'A' + 10) * 1;
    else
        cout << "unknown hex char '" << c << "'.\n";

    return res;
}

int main(int argc, char** argv)
{
    if (argc < 4) {
        cout << "too few arguments!\n";
        cout << "usage: fractal-gen <width> <height> <scale>\n";
        cout << "                   ";
        cout << "[color A] [color B] [color C]\n";
        cout << "                   ";
        cout << "[cr+ci] [color depth] [offx] [offy]\n";
        return -1;
    }

    unsigned width = atoi(argv[1]);
    unsigned height = atoi(argv[2]);
    double size = atof(argv[3]);
    unsigned color_depth = 255;
    double offx = -0.5;
    double offy = 0.0;
    bool mandel = true;
    complex c_arg(0, 0);
    auto file = "fractal.png";

    auto A_R = 0;
    auto A_G = 0;
    auto A_B = 0;

    auto B_R = 255;
    auto B_G = 255;
    auto B_B = 255;

    auto D_R = 0;
    auto D_G = 0;
    auto D_B = 0;

    if (argc > 4) {
        std::string str(argv[4]);
        if (str.at(0) == '#')
            str = str.substr(1, str.size() - 1);
        if (str.size() != 6) {
            cout << "error -- invalid color!\n";
            cout << "express colors as '#RRGGBB'.\n";
            return -1;
        }

        std::string sub_str = str.substr(0, 2);
        A_R = htoi(sub_str);

        sub_str = str.substr(2, 2);
        A_G = htoi(sub_str);

        sub_str = str.substr(4, 2);
        A_B = htoi(sub_str);
    }

    if (argc > 5) {
        std::string str(argv[5]);
        if (str.at(0) == '#')
            str = str.substr(1, str.size() - 1);
        if (str.size() != 6) {
            cout << "error -- invalid color!\n";
            cout << "express colors as '#RRGGBB'.\n";
            return -1;
        }

        std::string sub_str = str.substr(0, 2);
        B_R = htoi(sub_str);

        sub_str = str.substr(2, 2);
        B_G = htoi(sub_str);

        sub_str = str.substr(4, 2);
        B_B = htoi(sub_str);
    }

    if (argc > 6) {
        std::string str(argv[6]);
        if (str.at(0) == '#')
            str = str.substr(1, str.size() - 1);
        if (str.size() != 6) {
            cout << "error -- invalid color!\n";
            cout << "express colors as '#RRGGBB'.\n";
            return -1;
        }

        std::string sub_str = str.substr(0, 2);
        D_R = htoi(sub_str);

        sub_str = str.substr(2, 2);
        D_G = htoi(sub_str);

        sub_str = str.substr(4, 2);
        D_B = htoi(sub_str);
    }

    if (argc > 7 && std::string(argv[7]) != "mandelbrot") {
        mandel = false;
        offx = 0;
        offy = 0;
        std::string str(argv[7]);
        unsigned pos = 0;
        for (unsigned i = 0; i < str.size(); i++)
        {
            if (str.at(i) == '+') {
                pos = i + 1;
                break;
            }
        }
        if (pos == 0) {
            cout << "invalid complex argument!\n";
            return -1;
        }
        double real = atof(str.substr(0, pos - 1).c_str());
        double imag = atof(str.substr(pos, str.size() - pos).c_str());
        c_arg = complex(real, imag);
    }

    if (argc > 8)
        color_depth = atof(argv[8]);
    if (argc > 9)
        offx = atof(argv[9]);
    if (argc > 10)
        offy = atof(argv[10]);
    if (argc > 11)
        cout << "warning -- extra arguments, ignoring them.\n";

    cout << "fractal information:\n\n";

    if (mandel) {
        cout << "fractal type -- mandelbrot\n";
    } else {
        cout << "fractal type -- julia\n";
        cout << "complex argument -- " << c_arg.to_str() << "\n";
    }

    cout << "\n";
    cout << "width       -- " << width << "\n";
    cout << "height      -- " << height << "\n";
    cout << "pixels      -- " << (width * height * 4) << "\n";
    cout << "scale       -- " << size << "\n";
    cout << "color A     -- (";
    cout << A_R << ", " << A_G << ", " << A_B << ")\n";
    cout << "color B     -- (";
    cout << B_R << ", " << B_G << ", " << B_B << ")\n";
    cout << "color C     -- (";
    cout << D_R << ", " << D_G << ", " << D_B << ")\n";
    cout << "color depth -- " << color_depth << "\n";
    cout << "offx        -- " << offx << "\n";
    cout << "offy        -- " << offy << "\n";

    vector<unsigned char> image(width * height * 4);

    auto lerp = [&] (double x0, double y0,
                    double x1, double y1,
                    double t)
    {
        double m = (y1 - y0) / (x1 - x0);
        return y0 + t * m;
    };

    auto comp_color_r = [&] (unsigned val)
    {
        if (val == color_depth)
            return D_R;
        double rat = (double) val / color_depth;
        double dc = lerp(0, A_R, 1, B_R, rat);
        return (int) dc;
    };

    auto comp_color_g = [&] (unsigned val)
    {
        if (val == color_depth)
            return D_G;
        double rat = (double) val / color_depth;
        double dc = lerp(0, A_G, 1, B_G, rat);
        return (int) dc;
    };

    auto comp_color_b = [&] (unsigned val)
    {
        if (val == color_depth)
            return D_B;
        double rat = (double) val / color_depth;
        double dc = lerp(0, A_B, 1, B_B, rat);
        return (int) dc;
    };

    double r;
    double i;
    complex c;
    unsigned color;
    for (unsigned x = 0; x < width; x++)
    {
        for (unsigned y = 0; y < height; y++)
        {
            r = offx - size / 2 + size * x / width;
            i = offy - size / 2 + size * y / height;
            c = complex(r, i);
            if (mandel)
                color = eval(c, color_depth, c);
            else
                color = eval(c, color_depth, c_arg);
            set_pixel(comp_color_r(color),
                      comp_color_g(color),
                      comp_color_b(color),
                      x, y, image, height);
        }
    }

    unsigned error = lodepng::encode(file, image, width, height);
    if (error)
        cout << "error -- " << lodepng_error_text(error) << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************************[Matching.C]
Copyright (c) 2007, Niklas Sorensson

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 "circ/Circ.h"
#include "circ/Matching.h"

using namespace Minisat;

//=================================================================================================
// Circuit pattern matching functions:
//

bool Minisat::matchMuxParts(const Circ& c, Gate g, Gate h, Sig& x, Sig& y, Sig& z)
{
    Sig ll = c.lchild(g);
    Sig lr = c.rchild(g);
    Sig rl = c.lchild(h);
    Sig rr = c.rchild(h);

    assert(ll < lr);
    assert(rl < rr);

    // Find condition signal:
    bool is_mux = true;
    if      (ll == ~rl){ x = ll; y = ~lr; z = ~rr; }
    else if (lr == ~rl){ x = lr; y = ~ll; z = ~rr; }
    else if (ll == ~rr){ x = ll; y = ~lr; z = ~rl; }
    else if (lr == ~rr){ x = lr; y = ~ll; z = ~rl; }
    else is_mux = false;

    // Normalize:
    if (is_mux && sign(x)){ Sig tmp = y; y = z; z = tmp; x = ~x; }

    return is_mux;

}

bool Minisat::matchMux(const Circ& c, Gate g, Sig& x, Sig& y, Sig& z)
{
    if (type(g) != gtype_And) return false;

    Sig left  = c.lchild(g);
    Sig right = c.rchild(g);

    if (!sign(left) || !sign(right) || type(left) != gtype_And || type(right) != gtype_And || c.nFanouts(gate(left)) != 1 || c.nFanouts(gate(right)) != 1) return false;

    return matchMuxParts(c, gate(left), gate(right), x, y, z);
}

bool Minisat::matchXor(const Circ& c, Gate g, Sig& x, Sig& y)
{
    Sig z;

    if (!matchMux(c, g, x, y, z) || y != ~z) return false;

    y = ~y;

    // fprintf(stderr, " >>> NODE (%d) MATCHED XOR: %s%s%d, %s%s%d\n",
    //         index(g),
    //         sign(x)?"-":"", type(x) == gtype_Inp ? "$" : "@", index(gate(x)),
    //         sign(y)?"-":"", type(y) == gtype_Inp ? "$" : "@", index(gate(y))
    //         );

    return true;
}

// NOTE: Not sure what to do about sharing within an xor expression. Just match trees for now.
bool Minisat::matchXors(const Circ& c, Gate g, vec<Sig>& tmp_stack, vec<Sig>& xs)
{

    Sig x, y;
    if (!matchXor(c, g, x, y)) return false;

    assert(!sign(x));
    bool pol = sign(y);
    y = mkSig(gate(y));

    tmp_stack.clear();
    tmp_stack.push(x);
    tmp_stack.push(y);

    while (tmp_stack.size() > 0){
        Sig sig = tmp_stack.last(); tmp_stack.pop();
        assert(!sign(sig));

        //if (matchXor(c, gate(sig), x, y))
        //fprintf(stderr, "nFanouts = %d\n", c.nFanouts(gate(sig)));

        if (c.nFanouts(gate(sig)) != 2 || !matchXor(c, gate(sig), x, y))
            xs.push(sig);
        else {
            pol = pol ^ sign(y);
            y   = mkSig(gate(y));
            tmp_stack.push(x);
            tmp_stack.push(y);
        }
    }
    assert(xs.size() > 0);
    xs.last() = xs.last() ^ pol;
    normalizeXors(xs);

    // fprintf(stderr, "Matched an Xor chain: ");
    // for (int i = 0; i < xs.size(); i++)
    //     fprintf(stderr, "%s%d ", sign(xs[i])?"-":"", index(gate(xs[i])));
    // fprintf(stderr, "\n");

    // if (xs.size() == 2 && matchXor(c, gate(xs[0]), x, y))
    //     fprintf(stderr, " >>> OOPS! %s%s%d\\%d\n", sign(xs[0])?"-":"", type(xs[0]) == gtype_Inp ? "$":"@", index(gate(xs[0])), c.nFanouts(gate(xs[0])));
    // if (xs.size() == 2 && matchXor(c, gate(xs[1]), x, y))
    //     fprintf(stderr, " >>> OOPS! %s%s%d\\%d\n", sign(xs[1])?"-":"", type(xs[1]) == gtype_Inp ? "$":"@", index(gate(xs[1])), c.nFanouts(gate(xs[1])));
    //
    // if (xs.size() > 2){
    //     fprintf(stderr, "Matched an Xor chain: ");
    //     for (int i = 0; i < xs.size(); i++)
    //         fprintf(stderr, "%s%d ", sign(xs[i])?"-":"", index(gate(xs[i])));
    //     fprintf(stderr, "\n");
    // }

    return true;
}

void Minisat::matchAnds(const Circ& c, Gate g, GSet& tmp_set, vec<Sig>& tmp_stack, GMap<int>& tmp_fanouts, vec<Sig>& xs, bool match_muxes)
{
    assert(g != gate_Undef);
    assert(g != gate_True);

    c.adjustMapSize(tmp_fanouts, 0);
    tmp_set.clear();
    tmp_set.insert(g);
    tmp_stack.clear();
    tmp_stack.push(c.lchild(g));
    tmp_stack.push(c.rchild(g));

    int queue_head = 0;

    while (queue_head < tmp_stack.size()){
        Sig x = tmp_stack[queue_head++];

        // fprintf(stderr, " >>> matching %d: %s%s%d\\[%d, %d]\n", queue_head,
        //         sign(x)?"-":"", type(x) == gtype_Inp ? "$":"@",
        //         index(gate(x)),
        //         tmp_fanouts[gate(x)],
        //         c.nFanouts(gate(x))
        //         );

        assert(gate(x) != gate_Undef);
        assert(gate(x) != gate_True);

        Sig tmp_x, tmp_y, tmp_z;
        if (type(x) != gtype_And || sign(x) || !match_muxes && matchMux(c, gate(x), tmp_x, tmp_y, tmp_z))
            continue;

        g = gate(x);
        if (tmp_fanouts[g] < 255)
            tmp_fanouts[g]++;

        if (tmp_fanouts[g] < c.nFanouts(g))
            continue;

        // fprintf(stderr, " >>> recurse !!\n");

        tmp_set.insert(g);
        tmp_stack.push(c.lchild(g));
        tmp_stack.push(c.rchild(g));
    }

    // Clear tmp_fanouts:
    for (int i = 0; i < tmp_stack.size(); i++)
        tmp_fanouts[gate(tmp_stack[i])] = 0;

    // Debug:
    // for (Gate i = c.firstGate(); i != gate_Undef; i = c.nextGate(i))
    //     assert(tmp_fanouts[g] == 0);

    // Add nodes from the 'fringe' of the MFFC:
    xs.clear();
    for (int i = 0; i < tmp_set.size(); i++){
        assert(type(tmp_set[i]) == gtype_And);

        if (!tmp_set.has(gate(c.lchild(tmp_set[i])))) xs.push(c.lchild(tmp_set[i]));
        if (!tmp_set.has(gate(c.rchild(tmp_set[i])))) xs.push(c.rchild(tmp_set[i]));
    }

    normalizeAnds(xs);

    // fprintf(stderr, "Matched a Big-and: ");
    // for (int i = 0; i < xs.size(); i++)
    //     fprintf(stderr, "%s%d ", sign(xs[i])?"-":"", index(gate(xs[i])));
    // fprintf(stderr, "\n");
}

static inline void printSigs(const vec<Sig>& xs)
{
    fprintf(stderr, "{ ");
    for (int i = 0; i < xs.size(); i++)
        fprintf(stderr, "%s%s%d ", sign(xs[i])?"-":"", type(xs[i]) == gtype_Inp ? "$" : "@", index(gate(xs[i])));
    fprintf(stderr, "}");
}

void Minisat::matchTwoLevel(const Circ& c, Gate g, GSet& tmp_set, vec<Sig>& tmp_stack, GMap<int>& tmp_fanouts, vec<vec<Sig> >& xss, bool match_muxes)
{
    vec<Sig> top;
    matchAnds(c, g, tmp_set, tmp_stack, tmp_fanouts, top, match_muxes);

    for (int i = 0; i < top.size(); i++){
        xss.push();

        if (type(top[i]) == gtype_Inp || !sign(top[i]) || c.nFanouts(gate(top[i])) > 1)
            xss.last().push(top[i]);
        else {
            matchAnds(c, gate(top[i]), tmp_set, tmp_stack, tmp_fanouts, xss.last(), match_muxes);
            for (int j = 0; j < xss.last().size(); j++)
                xss.last()[j] = ~xss.last()[j];
        }
    }

    // fprintf(stderr, " --- MATCHED (%s%d):\n", type(g) == gtype_Inp ? "$" : "@", index(g));
    // for (int i = 0; i < xss.size(); i++){
    //     fprintf(stderr, " --- (%s%s%d)", sign(top[i]) ? "-": "", type(top[i]) == gtype_Inp ? "$" : "@", index(gate(top[i])));
    //     printSigs(xss[i]);
    //     fprintf(stderr, "\n");
    // }

    // vec<vec<Sig> > xss_before;
    // for (int i = 0; i < xss.size(); i++){
    //     xss_before.push();
    //     xss[i].copyTo(xss_before.last());
    // }
    // int size_before = 0;
    // for (int i = 0; i < xss.size(); i++)
    //     size_before += xss[i].size();

    vec<vec<Sig> > tmp_context;

    for (int i = 0; i < top.size(); i++)
        if (type(top[i]) == gtype_And && sign(top[i]) && c.nFanouts(gate(top[i])) > 1){
            tmp_context.push();
            matchAnds(c, gate(top[i]), tmp_set, tmp_stack, tmp_fanouts, tmp_context.last(), match_muxes);
            for (int j = 0; j < tmp_context.last().size(); j++)
                tmp_context.last()[j] = ~tmp_context.last()[j];
        }

    normalizeTwoLevel(xss, tmp_context);

    // int size_after = 0;
    // for (int i = 0; i < xss.size(); i++)
    //     size_after += xss[i].size();
    //
    //
    // if (size_after != size_before){
    //     fprintf(stderr, " <<< gate @%d with %d fanouts matched Two-level:\n", index(g), c.nFanouts(g));
    //     for (int i = 0; i < xss_before.size(); i++){
    //         fprintf(stderr, " >>> "); printSigs(c, xss_before[i]); fprintf(stderr, "\n");
    //     }
    //
    //     fprintf(stderr, " <<< gate @%d with %d fanouts normalized to:\n", index(g), c.nFanouts(g));
    //     for (int i = 0; i < xss.size(); i++){
    //         fprintf(stderr, " >>> "); printSigs(c, xss[i]); fprintf(stderr, "\n");
    //     }
    // }

}
<commit_msg>Bug fix: handle occurences of constant false in matchTwoLevel.<commit_after>/**************************************************************************************[Matching.C]
Copyright (c) 2007, Niklas Sorensson

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 "circ/Circ.h"
#include "circ/Matching.h"

using namespace Minisat;

//=================================================================================================
// Circuit pattern matching functions:
//

bool Minisat::matchMuxParts(const Circ& c, Gate g, Gate h, Sig& x, Sig& y, Sig& z)
{
    Sig ll = c.lchild(g);
    Sig lr = c.rchild(g);
    Sig rl = c.lchild(h);
    Sig rr = c.rchild(h);

    assert(ll < lr);
    assert(rl < rr);

    // Find condition signal:
    bool is_mux = true;
    if      (ll == ~rl){ x = ll; y = ~lr; z = ~rr; }
    else if (lr == ~rl){ x = lr; y = ~ll; z = ~rr; }
    else if (ll == ~rr){ x = ll; y = ~lr; z = ~rl; }
    else if (lr == ~rr){ x = lr; y = ~ll; z = ~rl; }
    else is_mux = false;

    // Normalize:
    if (is_mux && sign(x)){ Sig tmp = y; y = z; z = tmp; x = ~x; }

    return is_mux;

}

bool Minisat::matchMux(const Circ& c, Gate g, Sig& x, Sig& y, Sig& z)
{
    if (type(g) != gtype_And) return false;

    Sig left  = c.lchild(g);
    Sig right = c.rchild(g);

    if (!sign(left) || !sign(right) || type(left) != gtype_And || type(right) != gtype_And || c.nFanouts(gate(left)) != 1 || c.nFanouts(gate(right)) != 1) return false;

    return matchMuxParts(c, gate(left), gate(right), x, y, z);
}

bool Minisat::matchXor(const Circ& c, Gate g, Sig& x, Sig& y)
{
    Sig z;

    if (!matchMux(c, g, x, y, z) || y != ~z) return false;

    y = ~y;

    // fprintf(stderr, " >>> NODE (%d) MATCHED XOR: %s%s%d, %s%s%d\n",
    //         index(g),
    //         sign(x)?"-":"", type(x) == gtype_Inp ? "$" : "@", index(gate(x)),
    //         sign(y)?"-":"", type(y) == gtype_Inp ? "$" : "@", index(gate(y))
    //         );

    return true;
}

// NOTE: Not sure what to do about sharing within an xor expression. Just match trees for now.
bool Minisat::matchXors(const Circ& c, Gate g, vec<Sig>& tmp_stack, vec<Sig>& xs)
{

    Sig x, y;
    if (!matchXor(c, g, x, y)) return false;

    assert(!sign(x));
    bool pol = sign(y);
    y = mkSig(gate(y));

    tmp_stack.clear();
    tmp_stack.push(x);
    tmp_stack.push(y);

    while (tmp_stack.size() > 0){
        Sig sig = tmp_stack.last(); tmp_stack.pop();
        assert(!sign(sig));

        //if (matchXor(c, gate(sig), x, y))
        //fprintf(stderr, "nFanouts = %d\n", c.nFanouts(gate(sig)));

        if (c.nFanouts(gate(sig)) != 2 || !matchXor(c, gate(sig), x, y))
            xs.push(sig);
        else {
            pol = pol ^ sign(y);
            y   = mkSig(gate(y));
            tmp_stack.push(x);
            tmp_stack.push(y);
        }
    }
    assert(xs.size() > 0);
    xs.last() = xs.last() ^ pol;
    normalizeXors(xs);

    // fprintf(stderr, "Matched an Xor chain: ");
    // for (int i = 0; i < xs.size(); i++)
    //     fprintf(stderr, "%s%d ", sign(xs[i])?"-":"", index(gate(xs[i])));
    // fprintf(stderr, "\n");

    // if (xs.size() == 2 && matchXor(c, gate(xs[0]), x, y))
    //     fprintf(stderr, " >>> OOPS! %s%s%d\\%d\n", sign(xs[0])?"-":"", type(xs[0]) == gtype_Inp ? "$":"@", index(gate(xs[0])), c.nFanouts(gate(xs[0])));
    // if (xs.size() == 2 && matchXor(c, gate(xs[1]), x, y))
    //     fprintf(stderr, " >>> OOPS! %s%s%d\\%d\n", sign(xs[1])?"-":"", type(xs[1]) == gtype_Inp ? "$":"@", index(gate(xs[1])), c.nFanouts(gate(xs[1])));
    //
    // if (xs.size() > 2){
    //     fprintf(stderr, "Matched an Xor chain: ");
    //     for (int i = 0; i < xs.size(); i++)
    //         fprintf(stderr, "%s%d ", sign(xs[i])?"-":"", index(gate(xs[i])));
    //     fprintf(stderr, "\n");
    // }

    return true;
}

void Minisat::matchAnds(const Circ& c, Gate g, GSet& tmp_set, vec<Sig>& tmp_stack, GMap<int>& tmp_fanouts, vec<Sig>& xs, bool match_muxes)
{
    assert(g != gate_Undef);
    assert(g != gate_True);

    c.adjustMapSize(tmp_fanouts, 0);
    tmp_set.clear();
    tmp_set.insert(g);
    tmp_stack.clear();
    tmp_stack.push(c.lchild(g));
    tmp_stack.push(c.rchild(g));

    int queue_head = 0;

    while (queue_head < tmp_stack.size()){
        Sig x = tmp_stack[queue_head++];

        // fprintf(stderr, " >>> matching %d: %s%s%d\\[%d, %d]\n", queue_head,
        //         sign(x)?"-":"", type(x) == gtype_Inp ? "$":"@",
        //         index(gate(x)),
        //         tmp_fanouts[gate(x)],
        //         c.nFanouts(gate(x))
        //         );

        assert(gate(x) != gate_Undef);
        assert(gate(x) != gate_True);

        Sig tmp_x, tmp_y, tmp_z;
        if (type(x) != gtype_And || sign(x) || !match_muxes && matchMux(c, gate(x), tmp_x, tmp_y, tmp_z))
            continue;

        g = gate(x);
        if (tmp_fanouts[g] < 255)
            tmp_fanouts[g]++;

        if (tmp_fanouts[g] < c.nFanouts(g))
            continue;

        // fprintf(stderr, " >>> recurse !!\n");

        tmp_set.insert(g);
        tmp_stack.push(c.lchild(g));
        tmp_stack.push(c.rchild(g));
    }

    // Clear tmp_fanouts:
    for (int i = 0; i < tmp_stack.size(); i++)
        tmp_fanouts[gate(tmp_stack[i])] = 0;

    // Debug:
    // for (Gate i = c.firstGate(); i != gate_Undef; i = c.nextGate(i))
    //     assert(tmp_fanouts[g] == 0);

    // Add nodes from the 'fringe' of the MFFC:
    xs.clear();
    for (int i = 0; i < tmp_set.size(); i++){
        assert(type(tmp_set[i]) == gtype_And);

        if (!tmp_set.has(gate(c.lchild(tmp_set[i])))) xs.push(c.lchild(tmp_set[i]));
        if (!tmp_set.has(gate(c.rchild(tmp_set[i])))) xs.push(c.rchild(tmp_set[i]));
    }

    normalizeAnds(xs);

    // fprintf(stderr, "Matched a Big-and: ");
    // for (int i = 0; i < xs.size(); i++)
    //     fprintf(stderr, "%s%d ", sign(xs[i])?"-":"", index(gate(xs[i])));
    // fprintf(stderr, "\n");
}

static inline void printSigs(const vec<Sig>& xs)
{
    fprintf(stderr, "{ ");
    for (int i = 0; i < xs.size(); i++)
        fprintf(stderr, "%s%s%d ", sign(xs[i])?"-":"", type(xs[i]) == gtype_Inp ? "$" : "@", index(gate(xs[i])));
    fprintf(stderr, "}");
}

void Minisat::matchTwoLevel(const Circ& c, Gate g, GSet& tmp_set, vec<Sig>& tmp_stack, GMap<int>& tmp_fanouts, vec<vec<Sig> >& xss, bool match_muxes)
{
    vec<Sig> top;
    matchAnds(c, g, tmp_set, tmp_stack, tmp_fanouts, top, match_muxes);

    xss.clear();
    if (top.size() == 1 && top[0] == sig_False) {
        // Handle constant false:
        xss.push();
        return; }

    for (int i = 0; i < top.size(); i++){
        xss.push();

        if (type(top[i]) == gtype_Inp || !sign(top[i]) || c.nFanouts(gate(top[i])) > 1)
            xss.last().push(top[i]);
        else {
            assert(type(top[i]) == gtype_And);
            matchAnds(c, gate(top[i]), tmp_set, tmp_stack, tmp_fanouts, xss.last(), match_muxes);
            for (int j = 0; j < xss.last().size(); j++)
                xss.last()[j] = ~xss.last()[j];
        }
    }

    // fprintf(stderr, " --- MATCHED (%s%d):\n", type(g) == gtype_Inp ? "$" : "@", index(g));
    // for (int i = 0; i < xss.size(); i++){
    //     fprintf(stderr, " --- (%s%s%d)", sign(top[i]) ? "-": "", type(top[i]) == gtype_Inp ? "$" : "@", index(gate(top[i])));
    //     printSigs(xss[i]);
    //     fprintf(stderr, "\n");
    // }

    // vec<vec<Sig> > xss_before;
    // for (int i = 0; i < xss.size(); i++){
    //     xss_before.push();
    //     xss[i].copyTo(xss_before.last());
    // }
    // int size_before = 0;
    // for (int i = 0; i < xss.size(); i++)
    //     size_before += xss[i].size();

    vec<vec<Sig> > tmp_context;

    for (int i = 0; i < top.size(); i++)
        if (type(top[i]) == gtype_And && sign(top[i]) && c.nFanouts(gate(top[i])) > 1){
            tmp_context.push();
            matchAnds(c, gate(top[i]), tmp_set, tmp_stack, tmp_fanouts, tmp_context.last(), match_muxes);
            for (int j = 0; j < tmp_context.last().size(); j++)
                tmp_context.last()[j] = ~tmp_context.last()[j];
        }

    normalizeTwoLevel(xss, tmp_context);

    // int size_after = 0;
    // for (int i = 0; i < xss.size(); i++)
    //     size_after += xss[i].size();
    //
    //
    // if (size_after != size_before){
    //     fprintf(stderr, " <<< gate @%d with %d fanouts matched Two-level:\n", index(g), c.nFanouts(g));
    //     for (int i = 0; i < xss_before.size(); i++){
    //         fprintf(stderr, " >>> "); printSigs(c, xss_before[i]); fprintf(stderr, "\n");
    //     }
    //
    //     fprintf(stderr, " <<< gate @%d with %d fanouts normalized to:\n", index(g), c.nFanouts(g));
    //     for (int i = 0; i < xss.size(); i++){
    //         fprintf(stderr, " >>> "); printSigs(c, xss[i]); fprintf(stderr, "\n");
    //     }
    // }

}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2014 Rapptz

// 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.

#ifndef JSONPP_VALUE_HPP
#define JSONPP_VALUE_HPP

#include "type_traits.hpp"
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <cassert>
#include <memory>

namespace json {
inline namespace v1 {
struct value {
public:
    using object = std::map<std::string, value>;
    using array  = std::vector<value>;
private:
    union storage_t {
        double number;
        bool boolean;
        std::string* str;
        array* arr;
        object* obj;
    } storage;
    type storage_type;

    void copy(const value& other) {
        switch(other.storage_type) {
        case type::array:
            storage.arr = new array(*(other.storage.arr));
            break;
        case type::string:
            storage.str = new std::string(*(other.storage.str));
            break;
        case type::object:
            storage.obj = new object(*(other.storage.obj));
            break;
        case type::number:
            storage.number = other.storage.number;
            break;
        case type::boolean:
            storage.boolean = other.storage.boolean;
            break;
        default:
            break;
        }
        storage_type = other.storage_type;
    }
public:
    value() noexcept: storage_type(type::null) {}
    value(null) noexcept: storage_type(type::null) {}

    ~value() {
        clear();
    }

    value(double v) noexcept: storage_type(type::number) {
        storage.number = v;
    }

    template<typename T, EnableIf<is_bool<T>> = 0>
    value(const T& b) noexcept: storage_type(type::boolean) {
        storage.boolean = b;
    }

    template<typename T, EnableIf<is_string<T>> = 0>
    value(const T& str): storage_type(type::string) {
        storage.str = new std::string(str);
    }

    value(const array& arr): storage_type(type::array) {
        storage.arr = new array(arr);
    }

    value(const object& obj): storage_type(type::object) {
        storage.obj = new object(obj);
    }

    value(std::initializer_list<array::value_type> l): storage_type(type::array) {
        storage.arr = new array(l.begin(), l.end());
    }

    value(const value& other) {
        copy(other);
    }

    value(value&& other) noexcept {
        switch(other.storage_type) {
        case type::array:
            storage.arr = other.storage.arr;
            other.storage.arr = nullptr;
            break;
        case type::string:
            storage.str = other.storage.str;
            other.storage.str = nullptr;
            break;
        case type::object:
            storage.obj = other.storage.obj;
            other.storage.obj = nullptr;
            break;
        case type::boolean:
            storage.boolean = other.storage.boolean;
            break;
        case type::number:
            storage.number = other.storage.number;
            break;
        default:
            break;
        }

        storage_type = other.storage_type;
        other.storage_type = type::null;
    }

    value& operator=(const value& other) noexcept {
        if(this != &other) {
            clear();
            copy(other);
        }
        return *this;
    }

    value& operator=(value&& other) {
        if(this != &other) {
            clear();
            switch(other.storage_type) {
            case type::array:
                storage.arr = other.storage.arr;
                other.storage.arr = nullptr;
                break;
            case type::string:
                storage.str = other.storage.str;
                other.storage.str = nullptr;
                break;
            case type::object:
                storage.obj = other.storage.obj;
                other.storage.obj = nullptr;
                break;
            case type::boolean:
                storage.boolean = other.storage.boolean;
                break;
            case type::number:
                storage.number = other.storage.number;
                break;
            default:
                break;
            }

            storage_type = other.storage_type;
            other.storage_type = type::null;
        }
        return *this;
    }

    void clear() noexcept {
        switch(storage_type) {
        case type::array:
            delete storage.arr;
            break;
        case type::string:
            delete storage.str;
            break;
        case type::object:
            delete storage.obj;
            break;
        default:
            break;
        }
        storage_type = type::null;
    }

    std::string to_string(unsigned precision = 6) const {
        switch(storage_type) {
        case type::null:
            return "null";
        case type::number: {
            char buffer[328];
            std::snprintf(buffer, 328, "%.*g", precision, storage.number);
            return buffer;
        }
        case type::boolean:
            return storage.boolean ? "true" : "false";
        case type::string:
            return '"' + *(storage.str) + '"';
        case type::array: {
            std::ostringstream ss;
            ss.precision(precision);
            ss << "[";
            auto first = storage.arr->begin();
            auto last = storage.arr->end();
            if(first != last) {
                ss << first->to_string(precision);
                ++first;
            }
            while(first != last) {
                ss << ',' << first->to_string(precision);
                ++first;
            }
            ss << "]";
            return ss.str();
        }
        case type::object: {
            std::ostringstream ss;
            ss.precision(precision);
            ss << "{";
            auto begin = storage.obj->begin();
            auto end = storage.obj->end();
            if(begin != end) {
                ss << '"' << begin->first << "\":" << begin->second.to_string(precision);
                ++begin;
            }

            while(begin != end) {
                ss << ",\"" << begin->first << "\":" << begin->second.to_string(precision);
                ++begin;
            }
            ss << "}";
            return ss.str();
        }
        }
        return "";
    }

    template<typename T, EnableIf<is_string<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::string;
    }

    template<typename T, EnableIf<is_null<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::null;
    }

    template<typename T, EnableIf<is_number<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::number;
    }

    template<typename T, EnableIf<is_bool<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::boolean;
    }

    template<typename T, EnableIf<std::is_same<T, object>> = 0>
    bool is() const noexcept {
        return storage_type == type::object;
    }

    template<typename T, EnableIf<std::is_same<T, array>> = 0>
    bool is() const noexcept {
        return storage_type == type::array;
    }

    template<typename T, EnableIf<std::is_same<T, const char*>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return storage.str->c_str();
    }

    template<typename T, EnableIf<std::is_same<T, std::string>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return *(storage.str);
    }

    template<typename T, EnableIf<is_null<T>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return {};
    }

    template<typename T, EnableIf<is_bool<T>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return storage.boolean;
    }

    template<typename T, EnableIf<is_number<T>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return storage.number;
    }

    template<typename T, EnableIf<std::is_same<T, object>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return *(storage.obj);
    }

    template<typename T, EnableIf<std::is_same<T, array>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return *(storage.arr);
    }

    template<typename T>
    T as(T&& def) const noexcept {
        return is<T>() ? as<T>() : std::forward<T>(def);
    }
};

using array  = value::array;
using object = value::object;
} // v1
} // json

#endif // JSONPP_VALUE_HPP
<commit_msg>Use identity metafunction so you still have to specify template parameter for default values<commit_after>// The MIT License (MIT)

// Copyright (c) 2014 Rapptz

// 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.

#ifndef JSONPP_VALUE_HPP
#define JSONPP_VALUE_HPP

#include "type_traits.hpp"
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <cassert>
#include <memory>

namespace json {
inline namespace v1 {
struct value {
public:
    using object = std::map<std::string, value>;
    using array  = std::vector<value>;
private:
    union storage_t {
        double number;
        bool boolean;
        std::string* str;
        array* arr;
        object* obj;
    } storage;
    type storage_type;

    void copy(const value& other) {
        switch(other.storage_type) {
        case type::array:
            storage.arr = new array(*(other.storage.arr));
            break;
        case type::string:
            storage.str = new std::string(*(other.storage.str));
            break;
        case type::object:
            storage.obj = new object(*(other.storage.obj));
            break;
        case type::number:
            storage.number = other.storage.number;
            break;
        case type::boolean:
            storage.boolean = other.storage.boolean;
            break;
        default:
            break;
        }
        storage_type = other.storage_type;
    }
public:
    value() noexcept: storage_type(type::null) {}
    value(null) noexcept: storage_type(type::null) {}

    ~value() {
        clear();
    }

    value(double v) noexcept: storage_type(type::number) {
        storage.number = v;
    }

    template<typename T, EnableIf<is_bool<T>> = 0>
    value(const T& b) noexcept: storage_type(type::boolean) {
        storage.boolean = b;
    }

    template<typename T, EnableIf<is_string<T>> = 0>
    value(const T& str): storage_type(type::string) {
        storage.str = new std::string(str);
    }

    value(const array& arr): storage_type(type::array) {
        storage.arr = new array(arr);
    }

    value(const object& obj): storage_type(type::object) {
        storage.obj = new object(obj);
    }

    value(std::initializer_list<array::value_type> l): storage_type(type::array) {
        storage.arr = new array(l.begin(), l.end());
    }

    value(const value& other) {
        copy(other);
    }

    value(value&& other) noexcept {
        switch(other.storage_type) {
        case type::array:
            storage.arr = other.storage.arr;
            other.storage.arr = nullptr;
            break;
        case type::string:
            storage.str = other.storage.str;
            other.storage.str = nullptr;
            break;
        case type::object:
            storage.obj = other.storage.obj;
            other.storage.obj = nullptr;
            break;
        case type::boolean:
            storage.boolean = other.storage.boolean;
            break;
        case type::number:
            storage.number = other.storage.number;
            break;
        default:
            break;
        }

        storage_type = other.storage_type;
        other.storage_type = type::null;
    }

    value& operator=(const value& other) noexcept {
        if(this != &other) {
            clear();
            copy(other);
        }
        return *this;
    }

    value& operator=(value&& other) {
        if(this != &other) {
            clear();
            switch(other.storage_type) {
            case type::array:
                storage.arr = other.storage.arr;
                other.storage.arr = nullptr;
                break;
            case type::string:
                storage.str = other.storage.str;
                other.storage.str = nullptr;
                break;
            case type::object:
                storage.obj = other.storage.obj;
                other.storage.obj = nullptr;
                break;
            case type::boolean:
                storage.boolean = other.storage.boolean;
                break;
            case type::number:
                storage.number = other.storage.number;
                break;
            default:
                break;
            }

            storage_type = other.storage_type;
            other.storage_type = type::null;
        }
        return *this;
    }

    void clear() noexcept {
        switch(storage_type) {
        case type::array:
            delete storage.arr;
            break;
        case type::string:
            delete storage.str;
            break;
        case type::object:
            delete storage.obj;
            break;
        default:
            break;
        }
        storage_type = type::null;
    }

    std::string to_string(unsigned precision = 6) const {
        switch(storage_type) {
        case type::null:
            return "null";
        case type::number: {
            char buffer[328];
            std::snprintf(buffer, 328, "%.*g", precision, storage.number);
            return buffer;
        }
        case type::boolean:
            return storage.boolean ? "true" : "false";
        case type::string:
            return '"' + *(storage.str) + '"';
        case type::array: {
            std::ostringstream ss;
            ss.precision(precision);
            ss << "[";
            auto first = storage.arr->begin();
            auto last = storage.arr->end();
            if(first != last) {
                ss << first->to_string(precision);
                ++first;
            }
            while(first != last) {
                ss << ',' << first->to_string(precision);
                ++first;
            }
            ss << "]";
            return ss.str();
        }
        case type::object: {
            std::ostringstream ss;
            ss.precision(precision);
            ss << "{";
            auto begin = storage.obj->begin();
            auto end = storage.obj->end();
            if(begin != end) {
                ss << '"' << begin->first << "\":" << begin->second.to_string(precision);
                ++begin;
            }

            while(begin != end) {
                ss << ",\"" << begin->first << "\":" << begin->second.to_string(precision);
                ++begin;
            }
            ss << "}";
            return ss.str();
        }
        }
        return "";
    }

    template<typename T, EnableIf<is_string<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::string;
    }

    template<typename T, EnableIf<is_null<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::null;
    }

    template<typename T, EnableIf<is_number<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::number;
    }

    template<typename T, EnableIf<is_bool<T>> = 0>
    bool is() const noexcept {
        return storage_type == type::boolean;
    }

    template<typename T, EnableIf<std::is_same<T, object>> = 0>
    bool is() const noexcept {
        return storage_type == type::object;
    }

    template<typename T, EnableIf<std::is_same<T, array>> = 0>
    bool is() const noexcept {
        return storage_type == type::array;
    }

    template<typename T, EnableIf<std::is_same<T, const char*>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return storage.str->c_str();
    }

    template<typename T, EnableIf<std::is_same<T, std::string>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return *(storage.str);
    }

    template<typename T, EnableIf<is_null<T>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return {};
    }

    template<typename T, EnableIf<is_bool<T>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return storage.boolean;
    }

    template<typename T, EnableIf<is_number<T>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return storage.number;
    }

    template<typename T, EnableIf<std::is_same<T, object>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return *(storage.obj);
    }

    template<typename T, EnableIf<std::is_same<T, array>> = 0>
    T as() const noexcept {
        assert(is<T>());
        return *(storage.arr);
    }

    template<typename T>
    T as(Identity<T>&& def) const noexcept {
        return is<T>() ? as<T>() : std::forward<T>(def);
    }
};

using array  = value::array;
using object = value::object;

namespace impl {
inline std::string prettify(const value& v, unsigned spaces, unsigned precision, unsigned current_indent);

inline void indent(std::ostringstream& ss, unsigned& current_indent) {
    for(unsigned i = 0; i < current_indent; ++i) {
        ss << ' ';
    }
}

inline std::string prettify_object(const value& v, unsigned spaces, unsigned precision, unsigned& current_indent)  {
    std::ostringstream ss;
    current_indent += spaces;
    auto&& obj = v.as<object>();
    auto begin = obj.begin();
    auto end = obj.end();
    ss << '{';
    if(begin != end) {
        ss << '\n';
        indent(ss, current_indent);
        ss << '"' << begin->first << "\": " << prettify(begin->second, spaces, precision, current_indent);
        ++begin;
    }

    while(begin != end) {
        ss << ",\n";
        indent(ss, current_indent);
        ss << '"' << begin->first << "\": " << prettify(begin->second, spaces, precision, current_indent);
        ++begin;
    }
    current_indent -= spaces;
    ss << "\n}";
    return ss.str();
}

inline std::string prettify_array(const value& v, unsigned /*spaces*/, unsigned precision) {
    std::ostringstream ss;
    ss.precision(precision);
    ss << "[";
    auto&& arr = v.as<array>();
    auto first = arr.begin();
    auto last = arr.end();
    if(first != last) {
        ss << first->to_string(precision);
        ++first;
    }
    while(first != last) {
        ss << ", " << first->to_string(precision);
        ++first;
    }
    ss << "]";
    return ss.str();
}

inline std::string prettify(const value& v, unsigned spaces, unsigned precision, unsigned current_indent) {
    if(v.is<double>() || v.is<std::string>() || v.is<bool>() || v.is<null>()) {
        return v.to_string(precision);
    }

    if(v.is<object>()) {
        return prettify_object(v, spaces, precision, current_indent);
    }
    else if(v.is<array>()) {
        return prettify_array(v, spaces, precision);
    }
    throw std::runtime_error("invalid value passed");
}
} // impl

inline std::string prettify(const value& v, unsigned spaces = 4, unsigned precision = 6) {
    return impl::prettify(v, spaces, precision, 0);
}
} // v1
} // json

#endif // JSONPP_VALUE_HPP
<|endoftext|>


<commit_before>#include "logging.h"
#include "task.h"
#include "preferences.h"
#include <qdatetime.h>
#include <qstring.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qregexp.h>
#include <iostream>

#define QS(c) QString::fromLatin1(c)

//
//                            L O G    E V E N T S
//
QString KarmLogEvent::escapeXML( QString string )
{
  QString result = QString(string);
  result.replace( QRegExp(QS("&")),  QS("&")  );
  result.replace( QRegExp(QS("<")),  QS("<")   );
  result.replace( QRegExp(QS(">")),  QS(">")   );
  result.replace( QRegExp(QS("'")),  QS("'") );
  result.replace( QRegExp(QS("\"")), QS(""") );
  // protect also our task-separator
  result.replace( QRegExp(QS("/")),  QS("&slash;") );

  return result;
}

// Common LogEvent stuff
//
void KarmLogEvent::loadCommonFields( Task *task)
{
  eventTime =  QDateTime::currentDateTime();

  QListViewItem *item = task;
  fullName = escapeXML(task->name());
  while( ( item = item->parent() ) )
  {
    fullName = escapeXML(((Task *)item)->name()) + fullName.prepend('/');
  }
}

// Start LogEvent
//
StartLogEvent::StartLogEvent( Task *task )
{
  loadCommonFields(task);
}

QString StartLogEvent::toXML()
{
  return   QS("<starting")
         + QS(" date=\"") + eventTime.toString() + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" />\n");
}

// Stop LogEvent
//
StopLogEvent::StopLogEvent( Task *task )
{
  loadCommonFields(task);
}

QString StopLogEvent::toXML()
{
  return   QS("<stopping")
         + QS(" date=\"") + eventTime.toString()+ QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" />\n");
}

// Rename LogEvent
//
RenameLogEvent::RenameLogEvent( Task *task, QString& old )
{
  loadCommonFields(task);
  oldName = old;
}

QString RenameLogEvent::toXML()
{
  return   QS("<renaming")
         + QS(" date=\"") + eventTime.toString() + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" old_name=\"") + oldName + QS("\"")
         + QS(" />\n");
}

// Set Session Time LogEvent
//
SessionTimeLogEvent::SessionTimeLogEvent( Task *task, long total, long change)
{
  loadCommonFields(task);
  delta = change;
  newTotal = total;
}

QString SessionTimeLogEvent::toXML()
{
  return   QS("<new_session_time")
         + QS(" date=\"") + QString(eventTime.toString()) + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" new_total=\"") + newTotal + QS("\"")
         + QS(" change=\"") + delta + QS("\"")
         + QS(" />\n");
}

// Set Total Time LogEvent
//
TotalTimeLogEvent::TotalTimeLogEvent( Task *task, long total, long change)
{
  loadCommonFields(task);
  delta = change;
  newTotal = total;
}

QString TotalTimeLogEvent::toXML()
{
        std::cout << "pre\n";
  return   QS("<new_total_time")
         + QS(" date=\"") + QString(eventTime.toString()) + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" new_total=\"") + newTotal + QS("\"")
         + QS(" change=\"") + delta + QS("\"")
         + QS(" />\n");
}

//
//                              L O G G I N G
//
Logging *Logging::_instance = 0;

Logging::Logging()
{
  _preferences = Preferences::instance();
}

void Logging::start( Task *task)
{
  KarmLogEvent* event = new StartLogEvent(task);
  log(event);
}

void Logging::stop( Task *task)
{
  KarmLogEvent* event = new StopLogEvent(task);
  log(event);
}

void Logging::newTotalTime( Task *task, long minutes, long change)
{
  KarmLogEvent* event = new TotalTimeLogEvent(task, minutes, change);
  log(event);
}

void Logging::newSessionTime( Task *task, long minutes, long change)
{
  KarmLogEvent* event = new SessionTimeLogEvent(task, minutes, change);
  log(event);
}

void Logging::rename( Task *task, QString& oldName)
{
  KarmLogEvent* event = new RenameLogEvent(task, oldName);
  log(event);
}

void Logging::log( KarmLogEvent* event)
{
  if(_preferences->timeLogging()) {
    QFile f(_preferences->timeLog());

    if ( f.open( IO_WriteOnly | IO_Append) ) {
      QTextStream out( &f );        // use a text stream
      out << event->toXML();
      f.close();
    } else {
      std::cerr << "Couldn't write to time-log file";
    }
  }
}

Logging *Logging::instance()
{
  if (_instance == 0) {
    _instance = new Logging();
  }
  return _instance;
}

Logging::~Logging()
{
}

<commit_msg>removed debugging stuff - thanks Brad Hards<commit_after>#include "logging.h"
#include "task.h"
#include "preferences.h"
#include <qdatetime.h>
#include <qstring.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qregexp.h>
#include <iostream>

#define QS(c) QString::fromLatin1(c)

//
//                            L O G    E V E N T S
//
QString KarmLogEvent::escapeXML( QString string )
{
  QString result = QString(string);
  result.replace( QRegExp(QS("&")),  QS("&")  );
  result.replace( QRegExp(QS("<")),  QS("<")   );
  result.replace( QRegExp(QS(">")),  QS(">")   );
  result.replace( QRegExp(QS("'")),  QS("'") );
  result.replace( QRegExp(QS("\"")), QS(""") );
  // protect also our task-separator
  result.replace( QRegExp(QS("/")),  QS("&slash;") );

  return result;
}

// Common LogEvent stuff
//
void KarmLogEvent::loadCommonFields( Task *task)
{
  eventTime =  QDateTime::currentDateTime();

  QListViewItem *item = task;
  fullName = escapeXML(task->name());
  while( ( item = item->parent() ) )
  {
    fullName = escapeXML(((Task *)item)->name()) + fullName.prepend('/');
  }
}

// Start LogEvent
//
StartLogEvent::StartLogEvent( Task *task )
{
  loadCommonFields(task);
}

QString StartLogEvent::toXML()
{
  return   QS("<starting")
         + QS(" date=\"") + eventTime.toString() + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" />\n");
}

// Stop LogEvent
//
StopLogEvent::StopLogEvent( Task *task )
{
  loadCommonFields(task);
}

QString StopLogEvent::toXML()
{
  return   QS("<stopping")
         + QS(" date=\"") + eventTime.toString()+ QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" />\n");
}

// Rename LogEvent
//
RenameLogEvent::RenameLogEvent( Task *task, QString& old )
{
  loadCommonFields(task);
  oldName = old;
}

QString RenameLogEvent::toXML()
{
  return   QS("<renaming")
         + QS(" date=\"") + eventTime.toString() + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" old_name=\"") + oldName + QS("\"")
         + QS(" />\n");
}

// Set Session Time LogEvent
//
SessionTimeLogEvent::SessionTimeLogEvent( Task *task, long total, long change)
{
  loadCommonFields(task);
  delta = change;
  newTotal = total;
}

QString SessionTimeLogEvent::toXML()
{
  return   QS("<new_session_time")
         + QS(" date=\"") + QString(eventTime.toString()) + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" new_total=\"") + newTotal + QS("\"")
         + QS(" change=\"") + delta + QS("\"")
         + QS(" />\n");
}

// Set Total Time LogEvent
//
TotalTimeLogEvent::TotalTimeLogEvent( Task *task, long total, long change)
{
  loadCommonFields(task);
  delta = change;
  newTotal = total;
}

QString TotalTimeLogEvent::toXML()
{
  return   QS("<new_total_time")
         + QS(" date=\"") + QString(eventTime.toString()) + QS("\"")
         + QS(" task=\"") + fullName + QS("\"")
         + QS(" new_total=\"") + newTotal + QS("\"")
         + QS(" change=\"") + delta + QS("\"")
         + QS(" />\n");
}

//
//                              L O G G I N G
//
Logging *Logging::_instance = 0;

Logging::Logging()
{
  _preferences = Preferences::instance();
}

void Logging::start( Task *task)
{
  KarmLogEvent* event = new StartLogEvent(task);
  log(event);
}

void Logging::stop( Task *task)
{
  KarmLogEvent* event = new StopLogEvent(task);
  log(event);
}

void Logging::newTotalTime( Task *task, long minutes, long change)
{
  KarmLogEvent* event = new TotalTimeLogEvent(task, minutes, change);
  log(event);
}

void Logging::newSessionTime( Task *task, long minutes, long change)
{
  KarmLogEvent* event = new SessionTimeLogEvent(task, minutes, change);
  log(event);
}

void Logging::rename( Task *task, QString& oldName)
{
  KarmLogEvent* event = new RenameLogEvent(task, oldName);
  log(event);
}

void Logging::log( KarmLogEvent* event)
{
  if(_preferences->timeLogging()) {
    QFile f(_preferences->timeLog());

    if ( f.open( IO_WriteOnly | IO_Append) ) {
      QTextStream out( &f );        // use a text stream
      out << event->toXML();
      f.close();
    } else {
      std::cerr << "Couldn't write to time-log file";
    }
  }
}

Logging *Logging::instance()
{
  if (_instance == 0) {
    _instance = new Logging();
  }
  return _instance;
}

Logging::~Logging()
{
}

<|endoftext|>


<commit_before><commit_msg>Fix #1207: Fix generate_complete.py<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// 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 "paddle/fluid/framework/framework.pb.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
#include "paddle/fluid/operators/detail/safe_ref.h"
#include "paddle/fluid/platform/profiler.h"

namespace paddle {
namespace operators {

// Returns true if the two dimensions are compatible.
// A dimension is compatible with the other if:
// 1. The length of the dimensions are same.
// 2. Each non-negative number of the two dimensions are same.
// 3. For negative number in a dimension, it means unknown so it is compatible
//    with any number.
bool DimensionIsCompatibleWith(const framework::DDim& first,
                               const framework::DDim& second) {
  int dim_size = first.size();
  if (dim_size != second.size()) {
    return false;
  }
  for (int i = 0; i < dim_size; ++i) {
    if (first[i] >= 0 && second[i] >= 0 && first[i] != second[i]) {
      return false;
    }
  }
  return true;
}

class ReadInferShape : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("Reader"),
                   "The ReadOp must take a reader as input.");
    PADDLE_ENFORCE(ctx->HasOutputs("Out"),
                   "The ReadOp should be assigned with output.");
    if (!ctx->IsRuntime() && ctx->Attrs().Get<bool>("infer_out")) {
      std::vector<framework::DDim> reader_dims = ctx->GetReaderDims("Reader");
      std::vector<std::string> out_names = ctx->Outputs("Out");
      PADDLE_ENFORCE_EQ(
          reader_dims.size(), out_names.size(),
          "The reader's dim number doesn't match the output number.");
      ctx->SetOutputsDim("Out", reader_dims);
      auto in_desc =
          boost::get<framework::VarDesc*>(ctx->GetInputVarPtrs("Reader")[0]);
      auto in_lod_levels = in_desc->GetLoDLevels();
      auto out_var_ptrs = ctx->GetOutputVarPtrs("Out");
      PADDLE_ENFORCE_EQ(in_lod_levels.size(), out_var_ptrs.size(),
                        "LoDLevels of Input(Reader) must be the same as the "
                        "number of Outputs(Out).");
      for (size_t i = 0; i < out_var_ptrs.size(); ++i) {
        auto* out_desc = boost::get<framework::VarDesc*>(out_var_ptrs[i]);
        out_desc->SetLoDLevel(in_lod_levels[i]);
      }
    }
  }
};

class ReadInferVarType : public framework::VarTypeInference {
 public:
  void operator()(framework::InferVarTypeContext* ctx) const override {
    bool infer_out = boost::get<bool>(ctx->GetAttr("infer_out"));
    if (infer_out) {
      std::string reader_name = ctx->Input("Reader")[0];
      std::vector<std::string> out_names = ctx->Output("Out");
      auto dtypes = ctx->GetDataTypes(reader_name);
      PADDLE_ENFORCE_EQ(dtypes.size(), out_names.size());
      for (size_t i = 0; i < dtypes.size(); ++i) {
        ctx->SetType(out_names[i], framework::proto::VarType::LOD_TENSOR);
        ctx->SetDataType(out_names[i], dtypes[i]);
      }
    }
  }
};

class ReadOp : public framework::OperatorBase {
 public:
  using framework::OperatorBase::OperatorBase;

 private:
  void RunImpl(const framework::Scope& scope,
               const platform::Place& dev_place) const override {
    VLOG(3) << "read op in";
    framework::ReaderHolder* reader =
        detail::Ref(scope.FindVar(Input("Reader")),
                    "Cannot find reader variable %s", Input("Reader"))
            .GetMutable<framework::ReaderHolder>();
    std::vector<std::string> out_arg_names = Outputs("Out");
    std::vector<framework::LoDTensor> ins;

    // For profiling
    platform::RecordEvent record_event(Type());

    reader->ReadNext(&ins);
    if (ins.empty()) {
      VLOG(3) << "throw_eof_exp";
      PADDLE_THROW_EOF();
    }
    PADDLE_ENFORCE_EQ(ins.size(), out_arg_names.size(),
                      "input size and output size of read_op do not match");

    const std::vector<framework::DDim>& shapes = reader->Shapes();
    const std::vector<framework::proto::VarType::Type>& var_types =
        reader->VarTypes();
    const std::vector<bool>& need_check_feed = reader->NeedCheckFeed();
    PADDLE_ENFORCE_EQ(out_arg_names.size(), need_check_feed.size(),
                      "output size of read_op and the number of fed "
                      "variables of reader do not match");

    for (size_t i = 0; i < out_arg_names.size(); ++i) {
      auto* out =
          scope.FindVar(out_arg_names[i])->GetMutable<framework::LoDTensor>();
      if (need_check_feed[i]) {
        auto in_dims = ins[i].dims();
        PADDLE_ENFORCE_EQ(DimensionIsCompatibleWith(shapes[i], in_dims), true,
                          "The fed Variable %s should have dimensions = %d, "
                          "shape = [%s], but received fed shape [%s]",
                          out_arg_names[i], shapes[i].size(), shapes[i],
                          in_dims);
        PADDLE_ENFORCE_EQ(
            ins[i].type(), var_types[i],
            "The data type of fed Variable %s must be %s, but received %s",
            out_arg_names[i], var_types[i], ins[i].type());
      }
      out->ShareDataWith(ins[i]);
      out->set_lod(ins[i].lod());
    }
  }
};

class ReadOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("Reader", "(ReaderHolder) The executed reader.");
    AddOutput("Out", "(LoDTensor) The output data.").AsDuplicable();
    AddAttr<bool>(
        "throw_eof_exp",
        "If set true, an exception will be thrown when the Reader "
        "yields empty (which means there is no next data).\n"
        "NOTES: This flag must be true always. It will be set to false"
        " only when the data-balance is enabled in ParallelExecutor"
        " and it is set by ParallelExecutor instance, not users.")
        .SetDefault(true);
    AddAttr<bool>("infer_out", "").SetDefault(true);
    AddAttr<bool>("drop_last",
                  "Whether to drop last batches whose number is less than CPU "
                  "cores/GPU cards number")
        .SetDefault(true);
    AddComment(R"DOC(
      Read Operator

      Execute a given reader once and output data.
    )DOC");
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(
    read, ops::ReadOp, ops::ReadInferShape, ops::ReadOpMaker,
    paddle::framework::EmptyGradOpMaker<paddle::framework::OpDesc>,
    paddle::framework::EmptyGradOpMaker<paddle::imperative::OpBase>,
    ops::ReadInferVarType);
<commit_msg>fix read op comments, test=develop, test=document_fix (#23122)<commit_after>// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// 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 "paddle/fluid/framework/framework.pb.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
#include "paddle/fluid/operators/detail/safe_ref.h"
#include "paddle/fluid/platform/profiler.h"

namespace paddle {
namespace operators {

// Returns true if the two dimensions are compatible.
// A dimension is compatible with the other if:
// 1. The length of the dimensions are same.
// 2. Each non-negative number of the two dimensions are same.
// 3. For negative number in a dimension, it means unknown so it is compatible
//    with any number.
bool DimensionIsCompatibleWith(const framework::DDim& first,
                               const framework::DDim& second) {
  int dim_size = first.size();
  if (dim_size != second.size()) {
    return false;
  }
  for (int i = 0; i < dim_size; ++i) {
    if (first[i] >= 0 && second[i] >= 0 && first[i] != second[i]) {
      return false;
    }
  }
  return true;
}

class ReadInferShape : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("Reader"),
                   "The ReadOp must take a reader as input.");
    PADDLE_ENFORCE(ctx->HasOutputs("Out"),
                   "The ReadOp should be assigned with output.");
    if (!ctx->IsRuntime() && ctx->Attrs().Get<bool>("infer_out")) {
      std::vector<framework::DDim> reader_dims = ctx->GetReaderDims("Reader");
      std::vector<std::string> out_names = ctx->Outputs("Out");
      PADDLE_ENFORCE_EQ(
          reader_dims.size(), out_names.size(),
          "The reader's dim number doesn't match the output number.");
      ctx->SetOutputsDim("Out", reader_dims);
      auto in_desc =
          boost::get<framework::VarDesc*>(ctx->GetInputVarPtrs("Reader")[0]);
      auto in_lod_levels = in_desc->GetLoDLevels();
      auto out_var_ptrs = ctx->GetOutputVarPtrs("Out");
      PADDLE_ENFORCE_EQ(in_lod_levels.size(), out_var_ptrs.size(),
                        "LoDLevels of Input(Reader) must be the same as the "
                        "number of Outputs(Out).");
      for (size_t i = 0; i < out_var_ptrs.size(); ++i) {
        auto* out_desc = boost::get<framework::VarDesc*>(out_var_ptrs[i]);
        out_desc->SetLoDLevel(in_lod_levels[i]);
      }
    }
  }
};

class ReadInferVarType : public framework::VarTypeInference {
 public:
  void operator()(framework::InferVarTypeContext* ctx) const override {
    bool infer_out = boost::get<bool>(ctx->GetAttr("infer_out"));
    if (infer_out) {
      std::string reader_name = ctx->Input("Reader")[0];
      std::vector<std::string> out_names = ctx->Output("Out");
      auto dtypes = ctx->GetDataTypes(reader_name);
      PADDLE_ENFORCE_EQ(dtypes.size(), out_names.size());
      for (size_t i = 0; i < dtypes.size(); ++i) {
        ctx->SetType(out_names[i], framework::proto::VarType::LOD_TENSOR);
        ctx->SetDataType(out_names[i], dtypes[i]);
      }
    }
  }
};

class ReadOp : public framework::OperatorBase {
 public:
  using framework::OperatorBase::OperatorBase;

 private:
  void RunImpl(const framework::Scope& scope,
               const platform::Place& dev_place) const override {
    VLOG(3) << "read op in";
    framework::ReaderHolder* reader =
        detail::Ref(scope.FindVar(Input("Reader")),
                    "Cannot find reader variable %s", Input("Reader"))
            .GetMutable<framework::ReaderHolder>();
    std::vector<std::string> out_arg_names = Outputs("Out");
    std::vector<framework::LoDTensor> ins;

    // For profiling
    platform::RecordEvent record_event(Type());

    reader->ReadNext(&ins);
    if (ins.empty()) {
      VLOG(3) << "throw_eof_exp";
      PADDLE_THROW_EOF();
    }
    PADDLE_ENFORCE_EQ(ins.size(), out_arg_names.size(),
                      "input size and output size of read_op do not match");

    const std::vector<framework::DDim>& shapes = reader->Shapes();
    const std::vector<framework::proto::VarType::Type>& var_types =
        reader->VarTypes();
    const std::vector<bool>& need_check_feed = reader->NeedCheckFeed();
    PADDLE_ENFORCE_EQ(out_arg_names.size(), need_check_feed.size(),
                      "output size of read_op and the number of fed "
                      "variables of reader do not match");

    for (size_t i = 0; i < out_arg_names.size(); ++i) {
      auto* out =
          scope.FindVar(out_arg_names[i])->GetMutable<framework::LoDTensor>();
      if (need_check_feed[i]) {
        auto in_dims = ins[i].dims();
        PADDLE_ENFORCE_EQ(DimensionIsCompatibleWith(shapes[i], in_dims), true,
                          "The fed Variable %s should have dimensions = %d, "
                          "shape = [%s], but received fed shape [%s]",
                          out_arg_names[i], shapes[i].size(), shapes[i],
                          in_dims);
        PADDLE_ENFORCE_EQ(
            ins[i].type(), var_types[i],
            "The data type of fed Variable %s must be %s, but received %s",
            out_arg_names[i], var_types[i], ins[i].type());
      }
      out->ShareDataWith(ins[i]);
      out->set_lod(ins[i].lod());
    }
  }
};

class ReadOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("Reader", "(ReaderHolder) The executed reader.");
    AddOutput("Out", "(LoDTensor) The output data.").AsDuplicable();
    AddAttr<bool>(
        "throw_eof_exp",
        "If set true, an exception will be thrown when the Reader "
        "yields empty (which means there is no next data).\n"
        "NOTES: This flag must be true always. It will be set to false"
        " only when the data-balance is enabled in ParallelExecutor"
        " and it is set by ParallelExecutor instance, not users.")
        .SetDefault(true);
    AddAttr<bool>("infer_out", "").SetDefault(true);
    AddAttr<bool>("drop_last",
                  "Whether to drop last batches whose number is less than "
                  "actual used device number.")
        .SetDefault(true);
    AddComment(R"DOC(
      Read Operator

      Execute a given reader once and output data.
    )DOC");
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(
    read, ops::ReadOp, ops::ReadInferShape, ops::ReadOpMaker,
    paddle::framework::EmptyGradOpMaker<paddle::framework::OpDesc>,
    paddle::framework::EmptyGradOpMaker<paddle::imperative::OpBase>,
    ops::ReadInferVarType);
<|endoftext|>