<commit_before>#ifndef POWERSET_HPP_
#define POWERSET_HPP_

#include "iterbase.hpp"
#include "combinations.hpp"
#include "enumerate.hpp"

#include <cassert>
#include <vector>
#include <initializer_list>
#include <utility>
#include <iterator>

namespace iter {
    template <typename Container,
              typename CombinatorType=
                  decltype(combinations(std::declval<Container&>(), 0))>
    class Powersetter {
        private:
            Container container;

            std::vector<CombinatorType> combinators;
        public:
            Powersetter(Container in_container)
                : container(std::forward<Container>(in_container))
            {
                combinators.push_back(combinations(this->container, 0));
                std::size_t i = 1;
                for (auto iter = std::begin(this->container),
                            end = std::end(this->container);
                        iter != end;
                        ++iter, ++i) {
                    combinators.push_back(combinations(this->container, i));
                }
            }

            class Iterator {
                private:
                    std::size_t container_size;
                    std::size_t list_size = 0;
                    bool not_done = true;

                    std::vector<CombinatorType>& combinators;
                    std::vector<iterator_type<CombinatorType>> inner_iters;
                public:
                    Iterator(std::vector<CombinatorType>& combs)
                        : container_size{combs.size() - 1},
                        combinators(combs)
                    {
                        for (auto& comb : combinators) {
                            inner_iters.push_back(std::begin(comb));
                        }
                    }

                    Iterator& operator++() {
                        ++inner_iters[list_size];
                        if (!(inner_iters[list_size] != inner_iters[list_size])) {
                            ++list_size;
                        }
                        if (container_size < list_size) {
                            not_done = false;
                        }

                        return *this;
                    }

                    auto operator*() -> decltype(*inner_iters[0]) {
                        return *(inner_iters[list_size]);
                    }

                    bool operator != (const Iterator&) {
                        return not_done;
                    }
            };

            Iterator begin() {
                return {this->combinators};
            }

            Iterator end() {
                return {this->combinators};
            }
    };

    template <typename Container>
    Powersetter<Container> powerset(Container&& container) {
        return {std::forward<Container>(container)};
    }

    template <typename T>
    Powersetter<std::initializer_list<T>> powerset(
            std::initializer_list<T> il) {
        return {il};
    }
}
#endif // #ifndef POWERSET_HPP_
<commit_msg>powerset iter inherits from std iterator<commit_after>#ifndef POWERSET_HPP_
#define POWERSET_HPP_

#include "iterbase.hpp"
#include "combinations.hpp"
#include "enumerate.hpp"

#include <cassert>
#include <vector>
#include <initializer_list>
#include <utility>
#include <iterator>

namespace iter {
    template <typename Container,
              typename CombinatorType=
                  decltype(combinations(std::declval<Container&>(), 0))>
    class Powersetter {
        private:
            Container container;

            std::vector<CombinatorType> combinators;
        public:
            Powersetter(Container in_container)
                : container(std::forward<Container>(in_container))
            {
                combinators.push_back(combinations(this->container, 0));
                std::size_t i = 1;
                for (auto iter = std::begin(this->container),
                            end = std::end(this->container);
                        iter != end;
                        ++iter, ++i) {
                    combinators.push_back(combinations(this->container, i));
                }
            }

            class Iterator
                : public std::iterator<
                      std::input_iterator_tag, iterator_deref<CombinatorType>>
            {
                private:
                    std::size_t container_size;
                    std::size_t list_size = 0;
                    bool not_done = true;

                    std::vector<CombinatorType>& combinators;
                    std::vector<iterator_type<CombinatorType>> inner_iters;
                public:
                    Iterator(std::vector<CombinatorType>& combs)
                        : container_size{combs.size() - 1},
                        combinators(combs)
                    {
                        for (auto& comb : combinators) {
                            inner_iters.push_back(std::begin(comb));
                        }
                    }

                    Iterator& operator++() {
                        ++inner_iters[list_size];
                        if (!(inner_iters[list_size] != inner_iters[list_size])) {
                            ++list_size;
                        }
                        if (container_size < list_size) {
                            not_done = false;
                        }

                        return *this;
                    }

                    iterator_deref<CombinatorType> operator*() {
                        return *(inner_iters[list_size]);
                    }

                    bool operator != (const Iterator&) {
                        return not_done;
                    }
            };

            Iterator begin() {
                return {this->combinators};
            }

            Iterator end() {
                return {this->combinators};
            }
    };

    template <typename Container>
    Powersetter<Container> powerset(Container&& container) {
        return {std::forward<Container>(container)};
    }

    template <typename T>
    Powersetter<std::initializer_list<T>> powerset(
            std::initializer_list<T> il) {
        return {il};
    }
}
#endif // #ifndef POWERSET_HPP_
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt scene graph research project.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/QString>
#include <QtTest/QtTest>

#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>

#include <QtQuick/qsgnode.h>
#include <QtQuick/private/qsgbatchrenderer_p.h>
#include <QtQuick/private/qsgnodeupdater_p.h>

#include <QtQuick/qsgsimplerectnode.h>

class NodesTest : public QObject
{
    Q_OBJECT

public:
    NodesTest();

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    // Root nodes
    void propegate();
    void propegateWithMultipleRoots();

    // Opacity nodes
    void basicOpacityNode();
    void opacityPropegation();

    void isBlockedCheck();

private:
    QOffscreenSurface *surface;
    QOpenGLContext *context;
};

void NodesTest::initTestCase()
{
    surface = new QOffscreenSurface;
    surface->create();

    context = new QOpenGLContext();
    context->create();
    context->makeCurrent(surface);
}

void NodesTest::cleanupTestCase()
{
    context->doneCurrent();
    delete context;
    delete surface;
}

class DummyRenderer : public QSGBatchRenderer::Renderer
{
public:
    DummyRenderer(QSGRootNode *root)
        : QSGBatchRenderer::Renderer(new QSGRenderContext(0))
        , changedNode(0)
        , changedState(0)
        , renderCount(0)
    {
        setRootNode(root);
    }

    void render() {
        ++renderCount;
        renderingOrder = ++globalRendereringOrder;
    }

    void nodeChanged(QSGNode *node, QSGNode::DirtyState state) {
        changedNode = node;
        changedState = state;
        QSGBatchRenderer::Renderer::nodeChanged(node, state);
    }

    QSGNode *changedNode;
    QSGNode::DirtyState changedState;

    int renderCount;
    int renderingOrder;
    static int globalRendereringOrder;
};

int DummyRenderer::globalRendereringOrder;

NodesTest::NodesTest()
{
}

void NodesTest::propegate()
{
    QSGRootNode root;
    QSGNode child; child.setFlag(QSGNode::OwnedByParent, false);
    root.appendChildNode(&child);

    DummyRenderer renderer(&root);

    child.markDirty(QSGNode::DirtyGeometry);

    QCOMPARE(&child, renderer.changedNode);
    QCOMPARE((int) renderer.changedState, (int) QSGNode::DirtyGeometry);
}

void NodesTest::propegateWithMultipleRoots()
{
    QSGRootNode root1;
    QSGNode child2; child2.setFlag(QSGNode::OwnedByParent, false);
    QSGRootNode root3; root3.setFlag(QSGNode::OwnedByParent, false);
    QSGNode child4; child4.setFlag(QSGNode::OwnedByParent, false);

    root1.appendChildNode(&child2);
    child2.appendChildNode(&root3);
    root3.appendChildNode(&child4);

    DummyRenderer ren1(&root1);
    DummyRenderer ren2(&root3);

    child4.markDirty(QSGNode::DirtyGeometry);

    QCOMPARE(ren1.changedNode, &child4);
    QCOMPARE(ren2.changedNode, &child4);

    QCOMPARE((int) ren1.changedState, (int) QSGNode::DirtyGeometry);
    QCOMPARE((int) ren2.changedState, (int) QSGNode::DirtyGeometry);
}

void NodesTest::basicOpacityNode()
{
    QSGOpacityNode n;
    QCOMPARE(n.opacity(), 1.);

    n.setOpacity(0.5);
    QCOMPARE(n.opacity(), 0.5);

    n.setOpacity(-1);
    QCOMPARE(n.opacity(), 0.);

    n.setOpacity(2);
    QCOMPARE(n.opacity(), 1.);
}

void NodesTest::opacityPropegation()
{
    QSGRootNode root;
    QSGOpacityNode *a = new QSGOpacityNode;
    QSGOpacityNode *b = new QSGOpacityNode;
    QSGOpacityNode *c = new QSGOpacityNode;

    QSGSimpleRectNode *geometry = new QSGSimpleRectNode;
    geometry->setRect(0, 0, 100, 100);

    DummyRenderer renderer(&root);

    root.appendChildNode(a);
    a->appendChildNode(b);
    b->appendChildNode(c);
    c->appendChildNode(geometry);

    a->setOpacity(0.9);
    b->setOpacity(0.8);
    c->setOpacity(0.7);

    renderer.renderScene();

    QCOMPARE(a->combinedOpacity(), 0.9);
    QCOMPARE(b->combinedOpacity(), 0.9 * 0.8);
    QCOMPARE(c->combinedOpacity(), 0.9 * 0.8 * 0.7);
    QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.8 * 0.7);

    b->setOpacity(0.1);
    renderer.renderScene();

    QCOMPARE(a->combinedOpacity(), 0.9);
    QCOMPARE(b->combinedOpacity(), 0.9 * 0.1);
    QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
    QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);

    b->setOpacity(0);
    renderer.renderScene();

    QVERIFY(b->isSubtreeBlocked());

    // Verify that geometry did not get updated as it is in a blocked
    // subtree
    QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
    QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);
}

void NodesTest::isBlockedCheck()
{
    QSGRootNode root;
    QSGOpacityNode *opacity = new QSGOpacityNode();
    QSGNode *node = new QSGNode();

    root.appendChildNode(opacity);
    opacity->appendChildNode(node);

    QSGNodeUpdater updater;

    opacity->setOpacity(0);
    QVERIFY(updater.isNodeBlocked(node, &root));

    opacity->setOpacity(1);
    QVERIFY(!updater.isNodeBlocked(node, &root));
}

QTEST_MAIN(NodesTest);

#include "tst_nodestest.moc"
<commit_msg>Make tst_nodes use QSGRenderLoop to behave more like QQuickWindow<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt scene graph research project.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/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 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/QString>
#include <QtTest/QtTest>

#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>

#include <QtQuick/qsgnode.h>
#include <QtQuick/private/qsgbatchrenderer_p.h>
#include <QtQuick/private/qsgnodeupdater_p.h>
#include <QtQuick/private/qsgrenderloop_p.h>
#include <QtQuick/private/qsgcontext_p.h>

#include <QtQuick/qsgsimplerectnode.h>

class NodesTest : public QObject
{
    Q_OBJECT

public:
    NodesTest();

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    // Root nodes
    void propegate();
    void propegateWithMultipleRoots();

    // Opacity nodes
    void basicOpacityNode();
    void opacityPropegation();

    void isBlockedCheck();

private:
    QOffscreenSurface *surface;
    QOpenGLContext *context;
    QSGRenderContext *renderContext;
};

void NodesTest::initTestCase()
{
    QSGRenderLoop *renderLoop = QSGRenderLoop::instance();

    surface = new QOffscreenSurface;
    surface->create();

    context = new QOpenGLContext();
    context->create();
    context->makeCurrent(surface);

    renderContext = renderLoop->createRenderContext(renderLoop->sceneGraphContext());
    renderContext->initialize(context);
}

void NodesTest::cleanupTestCase()
{
    context->doneCurrent();
    delete context;
    delete surface;
}

class DummyRenderer : public QSGBatchRenderer::Renderer
{
public:
    DummyRenderer(QSGRootNode *root, QSGRenderContext *renderContext)
        : QSGBatchRenderer::Renderer(renderContext)
        , changedNode(0)
        , changedState(0)
        , renderCount(0)
    {
        setRootNode(root);
    }

    void render() {
        ++renderCount;
        renderingOrder = ++globalRendereringOrder;
    }

    void nodeChanged(QSGNode *node, QSGNode::DirtyState state) {
        changedNode = node;
        changedState = state;
        QSGBatchRenderer::Renderer::nodeChanged(node, state);
    }

    QSGNode *changedNode;
    QSGNode::DirtyState changedState;

    int renderCount;
    int renderingOrder;
    static int globalRendereringOrder;
};

int DummyRenderer::globalRendereringOrder;

NodesTest::NodesTest()
{
}

void NodesTest::propegate()
{
    QSGRootNode root;
    QSGNode child; child.setFlag(QSGNode::OwnedByParent, false);
    root.appendChildNode(&child);

    DummyRenderer renderer(&root, renderContext);

    child.markDirty(QSGNode::DirtyGeometry);

    QCOMPARE(&child, renderer.changedNode);
    QCOMPARE((int) renderer.changedState, (int) QSGNode::DirtyGeometry);
}

void NodesTest::propegateWithMultipleRoots()
{
    QSGRootNode root1;
    QSGNode child2; child2.setFlag(QSGNode::OwnedByParent, false);
    QSGRootNode root3; root3.setFlag(QSGNode::OwnedByParent, false);
    QSGNode child4; child4.setFlag(QSGNode::OwnedByParent, false);

    root1.appendChildNode(&child2);
    child2.appendChildNode(&root3);
    root3.appendChildNode(&child4);

    DummyRenderer ren1(&root1, renderContext);
    DummyRenderer ren2(&root3, renderContext);

    child4.markDirty(QSGNode::DirtyGeometry);

    QCOMPARE(ren1.changedNode, &child4);
    QCOMPARE(ren2.changedNode, &child4);

    QCOMPARE((int) ren1.changedState, (int) QSGNode::DirtyGeometry);
    QCOMPARE((int) ren2.changedState, (int) QSGNode::DirtyGeometry);
}

void NodesTest::basicOpacityNode()
{
    QSGOpacityNode n;
    QCOMPARE(n.opacity(), 1.);

    n.setOpacity(0.5);
    QCOMPARE(n.opacity(), 0.5);

    n.setOpacity(-1);
    QCOMPARE(n.opacity(), 0.);

    n.setOpacity(2);
    QCOMPARE(n.opacity(), 1.);
}

void NodesTest::opacityPropegation()
{
    QSGRootNode root;
    QSGOpacityNode *a = new QSGOpacityNode;
    QSGOpacityNode *b = new QSGOpacityNode;
    QSGOpacityNode *c = new QSGOpacityNode;

    QSGSimpleRectNode *geometry = new QSGSimpleRectNode;
    geometry->setRect(0, 0, 100, 100);

    DummyRenderer renderer(&root, renderContext);

    root.appendChildNode(a);
    a->appendChildNode(b);
    b->appendChildNode(c);
    c->appendChildNode(geometry);

    a->setOpacity(0.9);
    b->setOpacity(0.8);
    c->setOpacity(0.7);

    renderer.renderScene();

    QCOMPARE(a->combinedOpacity(), 0.9);
    QCOMPARE(b->combinedOpacity(), 0.9 * 0.8);
    QCOMPARE(c->combinedOpacity(), 0.9 * 0.8 * 0.7);
    QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.8 * 0.7);

    b->setOpacity(0.1);
    renderer.renderScene();

    QCOMPARE(a->combinedOpacity(), 0.9);
    QCOMPARE(b->combinedOpacity(), 0.9 * 0.1);
    QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
    QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);

    b->setOpacity(0);
    renderer.renderScene();

    QVERIFY(b->isSubtreeBlocked());

    // Verify that geometry did not get updated as it is in a blocked
    // subtree
    QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
    QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);
}

void NodesTest::isBlockedCheck()
{
    QSGRootNode root;
    QSGOpacityNode *opacity = new QSGOpacityNode();
    QSGNode *node = new QSGNode();

    root.appendChildNode(opacity);
    opacity->appendChildNode(node);

    QSGNodeUpdater updater;

    opacity->setOpacity(0);
    QVERIFY(updater.isNodeBlocked(node, &root));

    opacity->setOpacity(1);
    QVERIFY(!updater.isNodeBlocked(node, &root));
}

QTEST_MAIN(NodesTest);

#include "tst_nodestest.moc"
<|endoftext|>


<commit_before>/*
 * SocketPerformanceTester
 * Copyright (2016) Daniel Bonrath, Michael Baer, All rights reserved.
 *
 * This file is part of SocketPerformanceTester; SocketPerformanceTester is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "widgets/MainWindow.h"

#include <thread>

#include "spcBuildSettings.h"

#include "MessageStructs.h"

#include "plugins/SocketPluginInterface.h"

#include "clockUtils/sockets/TcpSocket.h"

#include <QCheckBox>
#include <QCloseEvent>
#include <QDir>
#include <QMessageBox>
#include <QPluginLoader>
#include <QStandardItemModel>

#ifdef max
	#undef max
#endif

namespace spc {
namespace widgets {

	class QNumberStandardItem : public QStandardItem {
	public:
		QNumberStandardItem(QString text) : QStandardItem(text) {
		}

		bool operator<(const QStandardItem & other) const override {
			return text().toInt() < other.text().toInt();
		}

		int type() const override {
			return UserType;
		}
	};

	MainWindow::MainWindow(QMainWindow * par) : QMainWindow(par), _socketPlugins(), _completeMessageAmount(), _processedMessageAmount(0), _triggerUpdateThreshold(1), _controlSocket(nullptr) {
		setupUi(this);

		setWindowIcon(QIcon(":/icon.png"));

		setWindowTitle(QString("SocketPerformanceChecker (v ") + QString::number(SPC_VERSION_MAJOR) + QString(".") + QString::number(SPC_VERSION_MINOR) + QString(".") + QString::number(SPC_VERSION_PATCH) + QString(")"));

		progressBar->hide();

		QHeaderView * header = new QHeaderView(Qt::Orientation::Horizontal, resultTableView);
		QStandardItemModel * model = new QStandardItemModel(header);
		QStringList horizontalHeader;
		horizontalHeader.append("Socket implementation");
		horizontalHeader.append("Complete Duration in ms");
		horizontalHeader.append("Avg. Duration in ms");
		horizontalHeader.append("Min. Duration in ms");
		horizontalHeader.append("Max. Duration in ms");
		horizontalHeader.append("Runs");
		horizontalHeader.append("Message Count");
		horizontalHeader.append("Payload Size in Bytes");
		model->setHorizontalHeaderLabels(horizontalHeader);
		header->setModel(model);
		resultTableView->setHorizontalHeader(header);
		resultTableView->resizeRowsToContents();
		resultTableView->resizeColumnsToContents();

		resultTableView->setModel(model);

		loadPlugins();

		addSocketCheckboxes();

		qRegisterMetaType<std::vector<uint64_t>>("std::vector<uint64_t>");

		connect(this, SIGNAL(finishedSocket(QString, std::vector<uint64_t>)), this, SLOT(updateSocketResults(QString, std::vector<uint64_t>)), Qt::QueuedConnection);
		connect(this, SIGNAL(updateProgress()), this, SLOT(updateProgressBar()), Qt::QueuedConnection);
		connect(this, SIGNAL(finishedTest()), this, SLOT(testFinished()), Qt::QueuedConnection);
		connect(this, SIGNAL(addErrorMessageBox(QString, QString)), this, SLOT(showErrorMessageBox(QString, QString)), Qt::QueuedConnection);
	}

	MainWindow::~MainWindow() {
		delete _controlSocket;
	}

	void MainWindow::closeTool() {
		qApp->exit();
	}

	void MainWindow::startTest() {
		QString ip = ipLineEdit->text();
		uint16_t port = uint16_t(portSpinBox->value());
		QStringList socketList;
		for (auto sp : _socketPlugins) {
			if (sp.second.second->isChecked()) {
				socketList.append(sp.first);
			}
		}
		uint32_t runs = uint32_t(runsSpinBox->value());
		uint32_t messageCount = uint32_t(messageCountSpinBox->value());
		uint32_t payloadSize = uint32_t(payloadSizeSpinBox->value());

		_completeMessageAmount = socketList.size() * runs * messageCount;
		_processedMessageAmount = 0;

		if (_completeMessageAmount == 0) {
			emit addErrorMessageBox("Can't start test.", "No socket implementations chosen to be tested. Starting test is stopped.");
			return;
		}

		// 0.1% of _completeMessageAmount or 1
		_triggerUpdateThreshold = std::max(uint64_t(1), _completeMessageAmount / 1000);

		QStandardItemModel * model = dynamic_cast<QStandardItemModel *>(resultTableView->model());
		while (model->rowCount() > 0) {
			model->removeRow(0);
		}

		enableGUI(false);

		progressBar->setValue(0);
		progressBar->setMaximum(_completeMessageAmount);

		delete _controlSocket;
		_controlSocket = nullptr;

		std::thread(std::bind(&MainWindow::performTest, this, ip, port, socketList, runs, messageCount, payloadSize)).detach();
	}

	void MainWindow::updateSocketResults(QString pluginName, std::vector<uint64_t> durations) {
		uint64_t minimumDuration = UINT64_MAX;
		uint64_t maximumDuration = 0;
		uint64_t durationSum = 0;
		for (uint64_t duration : durations) {
			if (minimumDuration > duration) {
				minimumDuration = duration;
			}
			if (maximumDuration < duration) {
				maximumDuration = duration;
			}
			durationSum += duration;
		}
		QStandardItemModel * model = dynamic_cast<QStandardItemModel *>(resultTableView->model());
		int rowCount = model->rowCount();
		// first column: plugin name
		QStandardItem * newItem = new QStandardItem(pluginName);
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 0, newItem);

		// second column: complete duration
		newItem = new QStandardItem(QString::number(durationSum / 1000));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 1, newItem);

		// third column: average duration
		newItem = new QNumberStandardItem(QString::number(uint64_t(durationSum / double(durations.size()) / 1000)));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 2, newItem);

		// fourth column: minimum duration
		newItem = new QStandardItem(QString::number(minimumDuration / 1000));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 3, newItem);

		// fifth column: maximum duration
		newItem = new QStandardItem(QString::number(maximumDuration / 1000));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 4, newItem);

		// sixth column: runs
		newItem = new QStandardItem(QString::number(durations.size()));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 5, newItem);

		// seventh column: message count
		newItem = new QStandardItem(QString::number(messageCountSpinBox->value()));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 6, newItem);

		// eighth column: payloadSize
		newItem = new QStandardItem(QString::number(payloadSizeSpinBox->value()));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 7, newItem);

		resultTableView->sortByColumn(2, Qt::SortOrder::AscendingOrder);
	}

	void MainWindow::updateProgressBar() {
		progressBar->setValue(_processedMessageAmount);
	}

	void MainWindow::testFinished() {
		enableGUI(true);
	}

	void MainWindow::showErrorMessageBox(QString title, QString message) const {
		QMessageBox box;
		box.setWindowTitle(title);
		box.setInformativeText(message);
		box.setStandardButtons(QMessageBox::StandardButton::Ok);
		box.exec();
	}

	void MainWindow::closeEvent(QCloseEvent * evt) {
		closeTool();
		evt->ignore();
	}

	void MainWindow::resizeEvent(QResizeEvent * evt) {
		QMainWindow::resizeEvent(evt);
		for (int i = 0; i < resultTableView->model()->columnCount(); i++) {
			resultTableView->setColumnWidth(i, width() / resultTableView->model()->columnCount());
		}
	}

	void MainWindow::loadPlugins() {
		loadSocketPlugins();
	}

	void MainWindow::loadSocketPlugins() {
		QDir pluginsDir = QDir(qApp->applicationDirPath() + "/plugins/sockets");
		foreach(QString fileName, pluginsDir.entryList(QDir::Files)) {
			QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
			QObject * plugin = loader.instance();
			if (plugin) {
				plugins::SocketPluginInterface * spi = qobject_cast<plugins::SocketPluginInterface *>(plugin);
				QCheckBox * cb = new QCheckBox(spi->getName(), this);
				cb->setChecked(true);
				_socketPlugins.insert(std::make_pair(spi->getName(), std::make_pair(spi, cb)));
			} else {
				emit addErrorMessageBox("Error loading plugin.", loader.errorString());
			}
		}
	}

	void MainWindow::addSocketCheckboxes() {
		uint32_t counter = 0;
		for (auto sp : _socketPlugins) {
			socketPluginLayout->addWidget(sp.second.second, counter / 3, counter % 3);
			counter++;
		}
	}

	void MainWindow::performTest(QString ip, uint16_t port, QStringList socketList, uint32_t runs, uint32_t messageCount, uint32_t payloadSize) {
		QString message(payloadSize, QChar('a'));
		_controlSocket = new clockUtils::sockets::TcpSocket();
		if (clockUtils::ClockError::SUCCESS != _controlSocket->connectToIP(ip.toStdString(), CONTROL_PORT, 1000)) {
			emit addErrorMessageBox("Connection failed.", "Can't connect to SocketPerformanceHelper. Maybe you haven't started it yet or the entered ip address or port are wrong.");
			emit finishedTest();
			return;
		}
		uint32_t pluginCounter = 0;
		for (QString socketPluginName : socketList) {
			std::vector<uint64_t> durations;
			plugins::SocketPluginInterface * socketPlugin = _socketPlugins[socketPluginName].first;
			uint8_t retries = 1;
			for (uint32_t i = 0; i < runs; i++) {
				// connect to helper and communicate which SocketPlugin to prepare
				common::ListenOnPluginAndPortMessage lopapm;
				lopapm.pluginName = socketPluginName.toStdString();
				lopapm.port = port;
				_controlSocket->writePacket(lopapm.Serialize());

				std::string reply;
				if (clockUtils::ClockError::SUCCESS != _controlSocket->receivePacket(reply)) {
					emit addErrorMessageBox("SocketPerformanceHelper not responding.", "SocketPerformanceHelper doesn't respond. Seems like an error occured.");
					emit finishedTest();
					return;
				}
				common::Message * msg = common::Message::Deserialize(reply);
				if (msg->type != common::MessageType::LISTENING) {
					emit addErrorMessageBox("SocketPerformanceHelper sent wrong message.", "SocketPerformanceHelper has sent a wrong message. Maybe the version is wrong and not compatible.");
					delete msg;
					emit finishedTest();
					return;
				}
				// received LISTENING from helper, so real test can start now
				delete msg;
				// connect to socket
				if (!socketPlugin->connect(ip, port, std::bind(&MainWindow::receivedMessage, this))) {
					emit addErrorMessageBox("Plugin can't connect.", "Failed to connect plugin: " + socketPlugin->getName() + "\n" + QString::number(3 - retries) + " retries left.");
					emit updateProgress();
					std::this_thread::sleep_for(std::chrono::milliseconds(500));
					if (retries++ < 3) {
						continue;
					} else {
						break;
					}
				}
				// start time measuring
				std::chrono::time_point<std::chrono::high_resolution_clock> startTime = std::chrono::high_resolution_clock::now();
				// send all messages
				for (uint32_t j = 0; j < messageCount; j++) {
					socketPlugin->sendMessage(message);
				}
				// wait until all messages are echoed or timeout is reached
				bool b = socketPlugin->waitForMessages(messageCount, 10000);
				// calculate duration to receive all message
				uint64_t duration = uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - startTime).count());
				if (!b) {
					emit addErrorMessageBox("Plugin timed out.", "Plugin '" + socketPlugin->getName() + "' hasn't received all messages and timed out.\n" + QString::number(3 - retries) + " retries left.");
					if (retries++ == 3) {
						break;
					}
				}
				// disconnect plugin to be able to do a clean reconnect for next repetition or new test later on
				socketPlugin->disconnect();
				// store current result
				if (b) { // otherwise not all messages were received
					durations.push_back(duration);
				}
			}
			if (!durations.empty()) {
				emit finishedSocket(socketPluginName, durations);
			}
			pluginCounter++;
			_processedMessageAmount = pluginCounter * messageCount * runs;
			emit updateProgress();
		}
		_processedMessageAmount = _completeMessageAmount;
		emit updateProgress();
		emit finishedTest();
	}

	void MainWindow::receivedMessage() {
		_processedMessageAmount++;
		if (_processedMessageAmount % _triggerUpdateThreshold == 0) {
			emit updateProgress();
		}
	}

	void MainWindow::enableGUI(bool enabled) {
		runsSpinBox->setEnabled(enabled);
		messageCountSpinBox->setEnabled(enabled);
		payloadSizeSpinBox->setEnabled(enabled);
		ipLineEdit->setEnabled(enabled);
		portSpinBox->setEnabled(enabled);
		startButton->setEnabled(enabled);
		if (enabled) {
			progressBar->hide();
		} else {
			progressBar->show();
		}
	}

} /* namespace widgets */
} /* namespace spc */
<commit_msg>SPC-12 plugins buttons now also get disabled while a test is running<commit_after>/*
 * SocketPerformanceTester
 * Copyright (2016) Daniel Bonrath, Michael Baer, All rights reserved.
 *
 * This file is part of SocketPerformanceTester; SocketPerformanceTester is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "widgets/MainWindow.h"

#include <thread>

#include "spcBuildSettings.h"

#include "MessageStructs.h"

#include "plugins/SocketPluginInterface.h"

#include "clockUtils/sockets/TcpSocket.h"

#include <QCheckBox>
#include <QCloseEvent>
#include <QDir>
#include <QMessageBox>
#include <QPluginLoader>
#include <QStandardItemModel>

#ifdef max
	#undef max
#endif

namespace spc {
namespace widgets {

	class QNumberStandardItem : public QStandardItem {
	public:
		QNumberStandardItem(QString text) : QStandardItem(text) {
		}

		bool operator<(const QStandardItem & other) const override {
			return text().toInt() < other.text().toInt();
		}

		int type() const override {
			return UserType;
		}
	};

	MainWindow::MainWindow(QMainWindow * par) : QMainWindow(par), _socketPlugins(), _completeMessageAmount(), _processedMessageAmount(0), _triggerUpdateThreshold(1), _controlSocket(nullptr) {
		setupUi(this);

		setWindowIcon(QIcon(":/icon.png"));

		setWindowTitle(QString("SocketPerformanceChecker (v ") + QString::number(SPC_VERSION_MAJOR) + QString(".") + QString::number(SPC_VERSION_MINOR) + QString(".") + QString::number(SPC_VERSION_PATCH) + QString(")"));

		progressBar->hide();

		QHeaderView * header = new QHeaderView(Qt::Orientation::Horizontal, resultTableView);
		QStandardItemModel * model = new QStandardItemModel(header);
		QStringList horizontalHeader;
		horizontalHeader.append("Socket implementation");
		horizontalHeader.append("Complete Duration in ms");
		horizontalHeader.append("Avg. Duration in ms");
		horizontalHeader.append("Min. Duration in ms");
		horizontalHeader.append("Max. Duration in ms");
		horizontalHeader.append("Runs");
		horizontalHeader.append("Message Count");
		horizontalHeader.append("Payload Size in Bytes");
		model->setHorizontalHeaderLabels(horizontalHeader);
		header->setModel(model);
		resultTableView->setHorizontalHeader(header);
		resultTableView->resizeRowsToContents();
		resultTableView->resizeColumnsToContents();

		resultTableView->setModel(model);

		loadPlugins();

		addSocketCheckboxes();

		qRegisterMetaType<std::vector<uint64_t>>("std::vector<uint64_t>");

		connect(this, SIGNAL(finishedSocket(QString, std::vector<uint64_t>)), this, SLOT(updateSocketResults(QString, std::vector<uint64_t>)), Qt::QueuedConnection);
		connect(this, SIGNAL(updateProgress()), this, SLOT(updateProgressBar()), Qt::QueuedConnection);
		connect(this, SIGNAL(finishedTest()), this, SLOT(testFinished()), Qt::QueuedConnection);
		connect(this, SIGNAL(addErrorMessageBox(QString, QString)), this, SLOT(showErrorMessageBox(QString, QString)), Qt::QueuedConnection);
	}

	MainWindow::~MainWindow() {
		delete _controlSocket;
	}

	void MainWindow::closeTool() {
		qApp->exit();
	}

	void MainWindow::startTest() {
		QString ip = ipLineEdit->text();
		uint16_t port = uint16_t(portSpinBox->value());
		QStringList socketList;
		for (auto sp : _socketPlugins) {
			if (sp.second.second->isChecked()) {
				socketList.append(sp.first);
			}
		}
		uint32_t runs = uint32_t(runsSpinBox->value());
		uint32_t messageCount = uint32_t(messageCountSpinBox->value());
		uint32_t payloadSize = uint32_t(payloadSizeSpinBox->value());

		_completeMessageAmount = socketList.size() * runs * messageCount;
		_processedMessageAmount = 0;

		if (_completeMessageAmount == 0) {
			emit addErrorMessageBox("Can't start test.", "No socket implementations chosen to be tested. Starting test is stopped.");
			return;
		}

		// 0.1% of _completeMessageAmount or 1
		_triggerUpdateThreshold = std::max(uint64_t(1), _completeMessageAmount / 1000);

		QStandardItemModel * model = dynamic_cast<QStandardItemModel *>(resultTableView->model());
		while (model->rowCount() > 0) {
			model->removeRow(0);
		}

		enableGUI(false);

		progressBar->setValue(0);
		progressBar->setMaximum(_completeMessageAmount);

		delete _controlSocket;
		_controlSocket = nullptr;

		std::thread(std::bind(&MainWindow::performTest, this, ip, port, socketList, runs, messageCount, payloadSize)).detach();
	}

	void MainWindow::updateSocketResults(QString pluginName, std::vector<uint64_t> durations) {
		uint64_t minimumDuration = UINT64_MAX;
		uint64_t maximumDuration = 0;
		uint64_t durationSum = 0;
		for (uint64_t duration : durations) {
			if (minimumDuration > duration) {
				minimumDuration = duration;
			}
			if (maximumDuration < duration) {
				maximumDuration = duration;
			}
			durationSum += duration;
		}
		QStandardItemModel * model = dynamic_cast<QStandardItemModel *>(resultTableView->model());
		int rowCount = model->rowCount();
		// first column: plugin name
		QStandardItem * newItem = new QStandardItem(pluginName);
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 0, newItem);

		// second column: complete duration
		newItem = new QStandardItem(QString::number(durationSum / 1000));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 1, newItem);

		// third column: average duration
		newItem = new QNumberStandardItem(QString::number(uint64_t(durationSum / double(durations.size()) / 1000)));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 2, newItem);

		// fourth column: minimum duration
		newItem = new QStandardItem(QString::number(minimumDuration / 1000));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 3, newItem);

		// fifth column: maximum duration
		newItem = new QStandardItem(QString::number(maximumDuration / 1000));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 4, newItem);

		// sixth column: runs
		newItem = new QStandardItem(QString::number(durations.size()));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 5, newItem);

		// seventh column: message count
		newItem = new QStandardItem(QString::number(messageCountSpinBox->value()));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 6, newItem);

		// eighth column: payloadSize
		newItem = new QStandardItem(QString::number(payloadSizeSpinBox->value()));
		newItem->setCheckable(false);
		newItem->setEditable(false);
		newItem->setSelectable(false);
		model->setItem(rowCount, 7, newItem);

		resultTableView->sortByColumn(2, Qt::SortOrder::AscendingOrder);
	}

	void MainWindow::updateProgressBar() {
		progressBar->setValue(_processedMessageAmount);
	}

	void MainWindow::testFinished() {
		enableGUI(true);
	}

	void MainWindow::showErrorMessageBox(QString title, QString message) const {
		QMessageBox box;
		box.setWindowTitle(title);
		box.setInformativeText(message);
		box.setStandardButtons(QMessageBox::StandardButton::Ok);
		box.exec();
	}

	void MainWindow::closeEvent(QCloseEvent * evt) {
		closeTool();
		evt->ignore();
	}

	void MainWindow::resizeEvent(QResizeEvent * evt) {
		QMainWindow::resizeEvent(evt);
		for (int i = 0; i < resultTableView->model()->columnCount(); i++) {
			resultTableView->setColumnWidth(i, width() / resultTableView->model()->columnCount());
		}
	}

	void MainWindow::loadPlugins() {
		loadSocketPlugins();
	}

	void MainWindow::loadSocketPlugins() {
		QDir pluginsDir = QDir(qApp->applicationDirPath() + "/plugins/sockets");
		foreach(QString fileName, pluginsDir.entryList(QDir::Files)) {
			QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
			QObject * plugin = loader.instance();
			if (plugin) {
				plugins::SocketPluginInterface * spi = qobject_cast<plugins::SocketPluginInterface *>(plugin);
				QCheckBox * cb = new QCheckBox(spi->getName(), this);
				cb->setChecked(true);
				_socketPlugins.insert(std::make_pair(spi->getName(), std::make_pair(spi, cb)));
			} else {
				emit addErrorMessageBox("Error loading plugin.", loader.errorString());
			}
		}
	}

	void MainWindow::addSocketCheckboxes() {
		uint32_t counter = 0;
		for (auto sp : _socketPlugins) {
			socketPluginLayout->addWidget(sp.second.second, counter / 3, counter % 3);
			counter++;
		}
	}

	void MainWindow::performTest(QString ip, uint16_t port, QStringList socketList, uint32_t runs, uint32_t messageCount, uint32_t payloadSize) {
		QString message(payloadSize, QChar('a'));
		_controlSocket = new clockUtils::sockets::TcpSocket();
		if (clockUtils::ClockError::SUCCESS != _controlSocket->connectToIP(ip.toStdString(), CONTROL_PORT, 1000)) {
			emit addErrorMessageBox("Connection failed.", "Can't connect to SocketPerformanceHelper. Maybe you haven't started it yet or the entered ip address or port are wrong.");
			emit finishedTest();
			return;
		}
		uint32_t pluginCounter = 0;
		for (QString socketPluginName : socketList) {
			std::vector<uint64_t> durations;
			plugins::SocketPluginInterface * socketPlugin = _socketPlugins[socketPluginName].first;
			uint8_t retries = 1;
			for (uint32_t i = 0; i < runs; i++) {
				// connect to helper and communicate which SocketPlugin to prepare
				common::ListenOnPluginAndPortMessage lopapm;
				lopapm.pluginName = socketPluginName.toStdString();
				lopapm.port = port;
				_controlSocket->writePacket(lopapm.Serialize());

				std::string reply;
				if (clockUtils::ClockError::SUCCESS != _controlSocket->receivePacket(reply)) {
					emit addErrorMessageBox("SocketPerformanceHelper not responding.", "SocketPerformanceHelper doesn't respond. Seems like an error occured.");
					emit finishedTest();
					return;
				}
				common::Message * msg = common::Message::Deserialize(reply);
				if (msg->type != common::MessageType::LISTENING) {
					emit addErrorMessageBox("SocketPerformanceHelper sent wrong message.", "SocketPerformanceHelper has sent a wrong message. Maybe the version is wrong and not compatible.");
					delete msg;
					emit finishedTest();
					return;
				}
				// received LISTENING from helper, so real test can start now
				delete msg;
				// connect to socket
				if (!socketPlugin->connect(ip, port, std::bind(&MainWindow::receivedMessage, this))) {
					emit addErrorMessageBox("Plugin can't connect.", "Failed to connect plugin: " + socketPlugin->getName() + "\n" + QString::number(3 - retries) + " retries left.");
					emit updateProgress();
					std::this_thread::sleep_for(std::chrono::milliseconds(500));
					if (retries++ < 3) {
						continue;
					} else {
						break;
					}
				}
				// start time measuring
				std::chrono::time_point<std::chrono::high_resolution_clock> startTime = std::chrono::high_resolution_clock::now();
				// send all messages
				for (uint32_t j = 0; j < messageCount; j++) {
					socketPlugin->sendMessage(message);
				}
				// wait until all messages are echoed or timeout is reached
				bool b = socketPlugin->waitForMessages(messageCount, 10000);
				// calculate duration to receive all message
				uint64_t duration = uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - startTime).count());
				if (!b) {
					emit addErrorMessageBox("Plugin timed out.", "Plugin '" + socketPlugin->getName() + "' hasn't received all messages and timed out.\n" + QString::number(3 - retries) + " retries left.");
					if (retries++ == 3) {
						break;
					}
				}
				// disconnect plugin to be able to do a clean reconnect for next repetition or new test later on
				socketPlugin->disconnect();
				// store current result
				if (b) { // otherwise not all messages were received
					durations.push_back(duration);
				}
			}
			if (!durations.empty()) {
				emit finishedSocket(socketPluginName, durations);
			}
			pluginCounter++;
			_processedMessageAmount = pluginCounter * messageCount * runs;
			emit updateProgress();
		}
		_processedMessageAmount = _completeMessageAmount;
		emit updateProgress();
		emit finishedTest();
	}

	void MainWindow::receivedMessage() {
		_processedMessageAmount++;
		if (_processedMessageAmount % _triggerUpdateThreshold == 0) {
			emit updateProgress();
		}
	}

	void MainWindow::enableGUI(bool enabled) {
		runsSpinBox->setEnabled(enabled);
		messageCountSpinBox->setEnabled(enabled);
		payloadSizeSpinBox->setEnabled(enabled);
		ipLineEdit->setEnabled(enabled);
		portSpinBox->setEnabled(enabled);
		startButton->setEnabled(enabled);
		if (enabled) {
			progressBar->hide();
		} else {
			progressBar->show();
		}
		for (auto sp : _socketPlugins) {
			sp.second.second->setEnabled(enabled);
		}
	}

} /* namespace widgets */
} /* namespace spc */
<|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * 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 <iostream>

#include "Cats/Corecat/System.hpp"

#define PRINT(x) do { std::cout << #x << " -> " << (x) << std::endl; } while(0)

int main() {

    PRINT(CORECAT_COMPILER);
    PRINT(CORECAT_OS);

    return 0;

}
<commit_msg>Update example<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * 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 <iostream>

#include "Cats/Corecat/System.hpp"

#define PRINT(x) do { std::cout << #x << " -> " << (x) << std::endl; } while(0)

int main() {

    PRINT(CORECAT_ARCHITECTURE);
    PRINT(CORECAT_COMPILER);
    PRINT(CORECAT_OS);

    return 0;

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "wallpaperbrief.h"
#include "wallpaperdescriptor.h"
#include "wallpapercurrentdescriptor.h"

#include <dcpwidgettypes.h>

#undef DEBUG
#include "../debug.h"

WallpaperBrief::WallpaperBrief (
        WallpaperBusinessLogic *businessLogic) :
    m_WallpaperBusinessLogic (businessLogic)
{
    connect (businessLogic, SIGNAL(wallpaperChanged()),
        this, SIGNAL(valuesChanged()));
}

int
WallpaperBrief::widgetTypeID() const
{
    SYS_DEBUG ("");
    return DcpWidgetType::Image;
}

QString
WallpaperBrief::valueText() const
{
    WallpaperCurrentDescriptor *desc = WallpaperCurrentDescriptor::instance();

    if (desc->valid()) {
        return desc->title();
    }

    //% "None"
    return qtTrId("wallpaper_none");
}

QString
WallpaperBrief::image () const
{
    WallpaperCurrentDescriptor *desc = WallpaperCurrentDescriptor::instance();

    if (desc->valid()) {
        // FIXME: We should have a method to get the thumbnail filename
        return desc->filename();
    }

    return "";
}

QString
WallpaperBrief::icon () const
{
    WallpaperCurrentDescriptor *desc = WallpaperCurrentDescriptor::instance();

    if (desc->valid()) {
        return desc->imageID ();
    }

    return "";
}

<commit_msg>Changes: do not use an invalid logical-id<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelapplets.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "wallpaperbrief.h"
#include "wallpaperdescriptor.h"
#include "wallpapercurrentdescriptor.h"

#include <dcpwidgettypes.h>

#undef DEBUG
#include "../debug.h"

WallpaperBrief::WallpaperBrief (
        WallpaperBusinessLogic *businessLogic) :
    m_WallpaperBusinessLogic (businessLogic)
{
    connect (businessLogic, SIGNAL(wallpaperChanged()),
        this, SIGNAL(valuesChanged()));
}

int
WallpaperBrief::widgetTypeID() const
{
    SYS_DEBUG ("");
    return DcpWidgetType::Image;
}

QString
WallpaperBrief::valueText() const
{
    WallpaperCurrentDescriptor *desc = WallpaperCurrentDescriptor::instance();

    if (desc->valid()) {
        return desc->title();
    }

    return "";
}

QString
WallpaperBrief::image () const
{
    WallpaperCurrentDescriptor *desc = WallpaperCurrentDescriptor::instance();

    if (desc->valid()) {
        // FIXME: We should have a method to get the thumbnail filename
        return desc->filename();
    }

    return "";
}

QString
WallpaperBrief::icon () const
{
    WallpaperCurrentDescriptor *desc = WallpaperCurrentDescriptor::instance();

    if (desc->valid()) {
        return desc->imageID ();
    }

    return "";
}

<|endoftext|>


<commit_before>
#include <GameData.h>
#include <File.h>
#include <DatCat.h>
#include <ExdData.h>
#include <ExdCat.h>
#include <Exd.h>
#include <Exh.h>
#include <iostream>
#include <cctype>
#include <set>
#include <Exd/ExdDataGenerated.h>
#include <Logging/Logger.h>

#include <fstream>
#include <streambuf>
#include <regex>

Sapphire::Data::ExdDataGenerated g_exdData;

using namespace Sapphire;

const std::string datLocation( "/home/mordred/sqpack" );
//const std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" );

bool invalidChar( char c )
{
  return !( c >= 0 && c < 128 );
}
void stripUnicode( std::string& str )
{
    str.erase( std::remove_if( str.begin(), str.end(), invalidChar ), str.end() );
   str.erase(std::remove_if(str.begin(), str.end(),
                            [](char c) { return !std::isalpha(c) && !std::isdigit(c) && !std::isspace(c) && !std::ispunct(c); }),
             str.end());
}

int main()
{

  Logger::init( "action_parse" );

  Logger::info( "Setting up EXD data" );
  if( !g_exdData.init( datLocation ) )
  {
    Logger::fatal( "Error setting up EXD data " );
    return 0;
  }
  auto idList = g_exdData.getActionIdList();

  for( auto id : idList )
  {
  auto gld = g_exdData.get< Sapphire::Data::Action >( id );
  auto gld1 = g_exdData.get< Sapphire::Data::ActionTransient >( id );
  if( gld )
  {
    if( gld->classJob == -1 || gld->name.empty() )
      continue;
    Logger::info( "{0} - {1}", id, gld->name );
    std::string desc = gld1->description;
    stripUnicode( desc );;
    desc = std::regex_replace( desc, std::regex( "HI" ), "\n" );
    desc = std::regex_replace( desc, std::regex( "IH" ), "" );
//    Logger::info( "got {0}", desc );

    std::smatch sm;
    std::regex r(R"(with a potency of \d*)");
    if( std::regex_search(desc, sm, r ) )
    {
      std::string potStr = sm.str();
      auto pos = potStr.find_last_of( " " );
      if( pos  != std::string::npos )
      {
        potStr = potStr.substr( pos + 1 );
	Logger::info( "Base Potency: {}", potStr);
      }
    }

    std::smatch sm1;
    std::regex r1(R"(\d* when executed from a target's rear)");
    if( std::regex_search(desc, sm1, r1 ) )
    {
      std::string potStr = sm1.str();
      auto pos = potStr.find_first_of( " " );
      if( pos  != std::string::npos )
      {
        potStr = potStr.substr( 0, pos );
	Logger::info( "Rear Potency: {}", potStr);
      }
    }

    std::smatch sm2;
    std::regex r2(R"(\d* when executed from a target's flank)");
    if( std::regex_search(desc, sm2, r2 ) )
    {
      std::string potStr = sm2.str();
      auto pos = potStr.find_first_of( " " );
      if( pos  != std::string::npos )
      {
        potStr = potStr.substr( 0, pos );
	Logger::info( "Flank Potency: {}", potStr);
      }
    }

    std::smatch sm3;
    std::regex r3(R"(\d* when executed in front of target)");
    if( std::regex_search(desc, sm3, r3 ) )
    {
      std::string potStr = sm3.str();
      auto pos = potStr.find_first_of( " " );
      if( pos  != std::string::npos )
      {
        potStr = potStr.substr( 0, pos );
	Logger::info( "Frontal Potency: {}", potStr);
      }
    }

    std::smatch sm4;
    std::regex r4(R"(Combo Potency: \d*)");
    if( std::regex_search(desc, sm4, r4 ) )
    {
      std::string potStr = sm4.str();
      auto pos = potStr.find_last_of( " " );
      if( pos  != std::string::npos )
      {
        potStr = potStr.substr( pos + 1 );
	Logger::info( "Combo Potency: {}", potStr);
      }
    }

    std::smatch sm5;
    std::regex r5(R"(Cure Potency: \d*)");
    if( std::regex_search(desc, sm5, r5 ) )
    {
      std::string potStr = sm5.str();
      auto pos = potStr.find_last_of( " " );
      if( pos  != std::string::npos )
      {
        potStr = potStr.substr( pos + 1 );
	Logger::info( "Cure Potency: {}", potStr);
      }
    }

    Logger::info( "-" );
  }
  else
    Logger::warn( "failed to get classjob {}", 1 );
  }

  return 0;
}
<commit_msg>action_parse improvements<commit_after>
#include <GameData.h>
#include <File.h>
#include <DatCat.h>
#include <ExdData.h>
#include <ExdCat.h>
#include <Exd.h>
#include <Exh.h>
#include <iostream>
#include <cctype>
#include <set>
#include <Exd/ExdDataGenerated.h>
#include <Logging/Logger.h>
#include <Common.h>

#include <fstream>
#include <streambuf>
#include <regex>

Sapphire::Data::ExdDataGenerated g_exdData;

using namespace Sapphire;

const std::string datLocation( "/home/mordred/sqpack" );
//const std::string datLocation( "/mnt/c/Program Files (x86)/Steam/steamapps/common/FINAL FANTASY XIV Online/game/sqpack" );

struct ActionEntry
{
  uint32_t id;
  std::string name;
  uint32_t potency;
  uint32_t comboPotency;
  uint32_t flankPotency;
  uint32_t frontPotency;
  uint32_t rearPotency;
  uint32_t curePotency;
  uint32_t restorePercentage;
};

bool invalidChar( char c )
{
  return !( c >= 0 && c < 128 );
}

void stripUnicode( std::string& str )
{
  str.erase( std::remove_if( str.begin(), str.end(), invalidChar ), str.end() );
  str.erase( std::remove_if( str.begin(), str.end(),
                             []( char c )
                             {
                               return !std::isalpha( c ) && !std::isdigit( c ) && !std::isspace( c ) &&
                                      !std::ispunct( c );
                             } ),
             str.end() );
}

uint32_t stripNonNumerics( std::string& str )
{
  str.erase( std::remove_if( str.begin(), str.end(),
    []( char c )
    {
      return !std::isdigit( c );
    }), str.end() );

  return std::atoi( str.c_str() );
}

int main()
{

  Logger::init( "action_parse" );

  Logger::info( "Setting up EXD data" );
  if( !g_exdData.init( datLocation ) )
  {
    Logger::fatal( "Error setting up EXD data " );
    return 0;
  }
  auto idList = g_exdData.getActionIdList();

  std::unordered_map< uint32_t, ActionEntry > actions;

  auto total = idList.size();
  int cursor = 0;

  for( auto id : idList )
  {
    auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f;
    if( cursor % 50 == 0 && cursor > 0 )
      Logger::info( "Processing {} actions of {} ({:.2f}%)", cursor, total, done );

    auto action = g_exdData.get< Sapphire::Data::Action >( id );
    auto actionTransient = g_exdData.get< Sapphire::Data::ActionTransient >( id );
    if( action )
    {
      if( action->classJob == -1 || action->name.empty() )
        continue;

      if( action->isPvP )
        continue;

      auto classJob = g_exdData.get< Sapphire::Data::ClassJob >( action->classJob );
      if( !classJob )
        continue;

      // exclude dol/doh
      if( classJob->classJobCategory == 32 || classJob->classJobCategory == 33 )
        continue;

      auto ac = static_cast< Common::ActionCategory >( action->actionCategory );
      if( ac != Common::ActionCategory::Ability &&
          ac != Common::ActionCategory::Autoattack &&
          ac != Common::ActionCategory::Spell &&
          ac != Common::ActionCategory::Weaponskill &&
          ac != Common::ActionCategory::LimitBreak )
        continue;

      ActionEntry entry{};

      entry.name = action->name;
      entry.id = id;

      Logger::info( "  {0} - {1}", id, action->name );
      std::string desc = actionTransient->description;
      stripUnicode( desc );
      desc = std::regex_replace( desc, std::regex( "HI" ), "\n" );
      desc = std::regex_replace( desc, std::regex( "IH" ), "" );
//    Logger::info( "got {0}", desc );

      std::smatch sm;
      std::regex r( R"(with a potency of [\d,]*)" );
      if( std::regex_search( desc, sm, r ) )
      {
        std::string potStr = sm.str();
        auto pos = potStr.find_last_of( " " );
        if( pos != std::string::npos )
        {
          potStr = potStr.substr( pos + 1 );
//          Logger::info( "Base Potency: {}", potStr );
          entry.potency = stripNonNumerics( potStr );
        }
      }

      std::smatch sm1;
      std::regex r1( R"([\d,]* when executed from a target's rear)" );
      if( std::regex_search( desc, sm1, r1 ) )
      {
        std::string potStr = sm1.str();
        auto pos = potStr.find_first_of( " " );
        if( pos != std::string::npos )
        {
          potStr = potStr.substr( 0, pos );
//          Logger::info( "Rear Potency: {}", potStr );
          entry.rearPotency = stripNonNumerics( potStr );
        }
      }

      std::smatch sm2;
      std::regex r2( R"([\d,]* when executed from a target's flank)" );
      if( std::regex_search( desc, sm2, r2 ) )
      {
        std::string potStr = sm2.str();
        auto pos = potStr.find_first_of( " " );
        if( pos != std::string::npos )
        {
          potStr = potStr.substr( 0, pos );
//          Logger::info( "Flank Potency: {}", potStr );
          entry.flankPotency = stripNonNumerics( potStr );
        }
      }

      std::smatch sm3;
      std::regex r3( R"([\d,]* when executed in front of target)" );
      if( std::regex_search( desc, sm3, r3 ) )
      {
        std::string potStr = sm3.str();
        auto pos = potStr.find_first_of( " " );
        if( pos != std::string::npos )
        {
          potStr = potStr.substr( 0, pos );
//          Logger::info( "Frontal Potency: {}", potStr );
          entry.frontPotency = stripNonNumerics( potStr );
        }
      }

      std::smatch sm4;
      std::regex r4( R"(Combo Potency: [\d,]*)" );
      if( std::regex_search( desc, sm4, r4 ) )
      {
        std::string potStr = sm4.str();
        auto pos = potStr.find_last_of( " " );
        if( pos != std::string::npos )
        {
          potStr = potStr.substr( pos + 1 );
//          Logger::info( "Combo Potency: {}", potStr );
          entry.comboPotency = stripNonNumerics( potStr );
        }
      }

      std::smatch sm5;
      std::regex r5( R"(Cure Potency: [\d,]*)" );
      if( std::regex_search( desc, sm5, r5 ) )
      {
        std::string potStr = sm5.str();
        auto pos = potStr.find_last_of( " " );
        if( pos != std::string::npos )
        {
          potStr = potStr.substr( pos + 1 );
//          Logger::info( "Cure Potency: {}", potStr );
          entry.curePotency = stripNonNumerics( potStr );
        }
      }

      std::smatch sm6;
      std::regex r6( R"(Restores \d*%)" );
      if( std::regex_search( desc, sm6, r6 ) )
      {
        std::string resStr = sm6.str();
        auto pos = resStr.find_last_of( " " );
        if( pos != std::string::npos )
        {
          resStr = resStr.substr( pos + 1 );
//          Logger::info( "Cure Percentage: {}", resStr );
          entry.restorePercentage = stripNonNumerics( resStr );
        }
      }

      actions[ id ] = std::move( entry );
    }
    else
      Logger::warn( "failed to get classjob {}", 1 );
  }

  // dump entries
  Logger::info( "Found {} player actions", actions.size() );
  for( const auto& action : actions )
  {
    const auto& data = action.second;
    Logger::info( " - {:<5} {:<25} pot: {:<4} flank pot: {:<4} front pot: {:<4} rear pot: {:<4} cure pot: {:<4} restore %: {:<4}",
                  action.first, data.name, data.potency, data.flankPotency, data.frontPotency, data.rearPotency,
                  data.curePotency, data.restorePercentage );
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library 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 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "engine_p.h"

#include "common.h"
#include "request_p.h"
#include "application.h"
#include "response.h"
#include "context_p.h"

#include <QUrl>
#include <QHostInfo>
#include <QSettings>
#include <QDebug>

using namespace Cutelyst;

typedef QPair<QString, QString> StringPair;

Engine::Engine(QObject *parent) :
    QObject(parent),
    d_ptr(new EnginePrivate)
{
    Q_D(Engine);

    // Load application configuration
    if (qEnvironmentVariableIsSet("CUTELYST_CONFIG")) {
        QByteArray config = qgetenv("CUTELYST_CONFIG");
        qCWarning(CUTELYST_CORE) << "Reading config file:" << config;
        QSettings settings(config, QSettings::IniFormat);
        Q_FOREACH (const QString &group, settings.childGroups()) {
            settings.beginGroup(group);
            QString groupLowered = group.toLower();
            Q_FOREACH (const QString &key, settings.childKeys()) {
                d->config[groupLowered].insert(key, settings.value(key));
            }
            settings.endGroup();
        }
    }
}

Engine::~Engine()
{
    delete d_ptr;
}

void Engine::finalizeCookies(Context *ctx)
{
    Q_FOREACH (const QNetworkCookie &cookie, ctx->response()->cookies()) {
        ctx->response()->addHeaderValue("Set-Cookie", cookie.toRawForm());
    }
}

void Engine::finalizeError(Context *ctx)
{
    ctx->res()->setContentType("text/html; charset=utf-8");

    QByteArray body;

    // Trick IE. Old versions of IE would display their own error page instead
    // of ours if we'd give it less than 512 bytes.
    body.reserve(512);

    body.append(ctx->errors().join(QLatin1Char('\n')));

    ctx->res()->body() = body;

    // Return 500
    ctx->res()->setStatus(Response::InternalServerError);
}

Application *Engine::app() const
{
    Q_D(const Engine);
    Q_ASSERT(d->app);
    return d->app;
}

bool Engine::initApplication(Application *app, bool postFork)
{
    Q_D(Engine);
    d->app = app;

    // To make easier for engines to clean up
    // the app must be a child of it
    app->setParent(this);

    if (!app->setup(this)) {
        qCCritical(CUTELYST_ENGINE) << "Failed to setup application";
        return false;
    }

    if (!init()) {
        qCCritical(CUTELYST_ENGINE) << "Failed to setup engine";
        return false;
    }

    if (postFork) {
        return postForkApplication();
    }

    return true;
}

bool Engine::postForkApplication()
{
    Q_D(Engine);

    if (!d->app) {
        qCCritical(CUTELYST_ENGINE) << "Failed to postForkApplication on a null application";
        return false;
    }
    return d->app->postFork();
}

QByteArray Engine::statusCode(quint16 status) const
{
    Q_D(const Engine);

    switch (status) {
    case Response::OK:
        return QByteArrayLiteral("200 OK");
    case Response::Found:
        return QByteArrayLiteral("302 Found");
    case Response::NotFound:
        return QByteArrayLiteral("404 Not Found");
    case Response::InternalServerError:
        return QByteArrayLiteral("500 Internal Server Error");
    case Response::MovedPermanently:
        return QByteArrayLiteral("301 Moved Permanently");
    case Response::NotModified:
        return QByteArrayLiteral("304 Not Modified");
    case Response::SeeOther:
        return QByteArrayLiteral("303 See Other");
    case Response::Forbidden:
        return QByteArrayLiteral("403 Forbidden");
    case Response::TemporaryRedirect:
        return QByteArrayLiteral("307 Temporary Redirect");
    case Response::Unauthorized:
        return QByteArrayLiteral("401 Unauthorized");
    case Response::BadRequest:
        return QByteArrayLiteral("400 Bad Request");
    case Response::MethodNotAllowed:
        return QByteArrayLiteral("405 Method Not Allowed");
    case Response::RequestTimeout:
        return QByteArrayLiteral("408 Request Timeout");
    case Response::Continue:
        return QByteArrayLiteral("100 Continue");
    case Response::SwitchingProtocols:
        return QByteArrayLiteral("101 Switching Protocols");
    case Response::Created:
        return QByteArrayLiteral("201 Created");
    case Response::Accepted:
        return QByteArrayLiteral("202 Accepted");
    case Response::NonAuthoritativeInformation:
        return QByteArrayLiteral("203 Non-Authoritative Information");
    case Response::NoContent:
        return QByteArrayLiteral("204 No Content");
    case Response::ResetContent:
        return QByteArrayLiteral("205 Reset Content");
    case Response::PartialContent:
        return QByteArrayLiteral("206 Partial Content");
    case Response::MultipleChoices:
        return QByteArrayLiteral("300 Multiple Choices");
    case Response::UseProxy:
        return QByteArrayLiteral("305 Use Proxy");
    case Response::PaymentRequired:
        return QByteArrayLiteral("402 Payment Required");
    case Response::NotAcceptable:
        return QByteArrayLiteral("406 Not Acceptable");
    case Response::ProxyAuthenticationRequired:
        return QByteArrayLiteral("407 Proxy Authentication Required");
    case Response::Conflict:
        return QByteArrayLiteral("409 Conflict");
    case Response::Gone:
        return QByteArrayLiteral("410 Gone");
    case Response::LengthRequired:
        return QByteArrayLiteral("411 Length Required");
    case Response::PreconditionFailed:
        return QByteArrayLiteral("412 Precondition Failed");
    case Response::RequestEntityTooLarge:
        return QByteArrayLiteral("413 Request Entity Too Large");
    case Response::RequestURITooLong:
        return QByteArrayLiteral("414 Request-URI Too Long");
    case Response::UnsupportedMediaType:
        return QByteArrayLiteral("415 Unsupported Media Type");
    case Response::RequestedRangeNotSatisfiable:
        return QByteArrayLiteral("416 Requested Range Not Satisfiable");
    case Response::ExpectationFailed:
        return QByteArrayLiteral("417 Expectation Failed");
    case Response::NotImplemented:
        return QByteArrayLiteral("501 Not Implemented");
    case Response::BadGateway:
        return QByteArrayLiteral("502 Bad Gateway");
    case Response::ServiceUnavailable:
        return QByteArrayLiteral("503 Service Unavailable");
    case Response::GatewayTimeout:
        return QByteArrayLiteral("504 Gateway Timeout");
    case Response::HTTPVersionNotSupported:
        return QByteArrayLiteral("505 HTTP Version Not Supported");
    case Response::BandwidthLimitExceeded:
        return QByteArrayLiteral("509 Bandwidth Limit Exceeded");
    default:
        return QByteArray::number(status);
    }
}

void Engine::reload()
{
    qCWarning(CUTELYST_ENGINE) << "Default reload implementation called, doing nothing";
}

QVariantHash Engine::config(const QString &entity) const
{
    Q_D(const Engine);
    return d->config.value(entity.toLower());
}

void Engine::handleRequest(Request *request, bool autoDelete)
{
    Q_D(Engine);
    Q_ASSERT(d->app);
    d->app->handleRequest(request);

    if (autoDelete) {
        delete request;
    }
}
<commit_msg>Fix compilation<commit_after>/*
 * Copyright (C) 2013 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library 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 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "engine_p.h"

#include "common.h"
#include "request_p.h"
#include "application.h"
#include "response.h"
#include "context_p.h"

#include <QUrl>
#include <QHostInfo>
#include <QSettings>
#include <QDebug>

using namespace Cutelyst;

typedef QPair<QString, QString> StringPair;

Engine::Engine(QObject *parent) :
    QObject(parent),
    d_ptr(new EnginePrivate)
{
    Q_D(Engine);

    // Load application configuration
    if (qEnvironmentVariableIsSet("CUTELYST_CONFIG")) {
        QByteArray config = qgetenv("CUTELYST_CONFIG");
        qCWarning(CUTELYST_CORE) << "Reading config file:" << config;
        QSettings settings(config, QSettings::IniFormat);
        Q_FOREACH (const QString &group, settings.childGroups()) {
            settings.beginGroup(group);
            QString groupLowered = group.toLower();
            Q_FOREACH (const QString &key, settings.childKeys()) {
                d->config[groupLowered].insert(key, settings.value(key));
            }
            settings.endGroup();
        }
    }
}

Engine::~Engine()
{
    delete d_ptr;
}

void Engine::finalizeCookies(Context *ctx)
{
    Q_FOREACH (const QNetworkCookie &cookie, ctx->response()->cookies()) {
        ctx->response()->addHeaderValue("Set-Cookie", cookie.toRawForm());
    }
}

void Engine::finalizeError(Context *ctx)
{
    ctx->res()->setContentType("text/html; charset=utf-8");

    QByteArray body;

    // Trick IE. Old versions of IE would display their own error page instead
    // of ours if we'd give it less than 512 bytes.
    body.reserve(512);

    body.append(ctx->errors().join(QLatin1Char('\n')));

    ctx->res()->body() = body;

    // Return 500
    ctx->res()->setStatus(Response::InternalServerError);
}

Application *Engine::app() const
{
    Q_D(const Engine);
    Q_ASSERT(d->app);
    return d->app;
}

bool Engine::initApplication(Application *app, bool postFork)
{
    Q_D(Engine);
    d->app = app;

    // To make easier for engines to clean up
    // the app must be a child of it
    app->setParent(this);

    if (!app->setup(this)) {
        qCCritical(CUTELYST_ENGINE) << "Failed to setup application";
        return false;
    }

    if (!init()) {
        qCCritical(CUTELYST_ENGINE) << "Failed to setup engine";
        return false;
    }

    if (postFork) {
        return postForkApplication();
    }

    return true;
}

bool Engine::postForkApplication()
{
    Q_D(Engine);

    if (!d->app) {
        qCCritical(CUTELYST_ENGINE) << "Failed to postForkApplication on a null application";
        return false;
    }
    return d->app->postFork();
}

QByteArray Engine::statusCode(quint16 status) const
{
    switch (status) {
    case Response::OK:
        return QByteArrayLiteral("200 OK");
    case Response::Found:
        return QByteArrayLiteral("302 Found");
    case Response::NotFound:
        return QByteArrayLiteral("404 Not Found");
    case Response::InternalServerError:
        return QByteArrayLiteral("500 Internal Server Error");
    case Response::MovedPermanently:
        return QByteArrayLiteral("301 Moved Permanently");
    case Response::NotModified:
        return QByteArrayLiteral("304 Not Modified");
    case Response::SeeOther:
        return QByteArrayLiteral("303 See Other");
    case Response::Forbidden:
        return QByteArrayLiteral("403 Forbidden");
    case Response::TemporaryRedirect:
        return QByteArrayLiteral("307 Temporary Redirect");
    case Response::Unauthorized:
        return QByteArrayLiteral("401 Unauthorized");
    case Response::BadRequest:
        return QByteArrayLiteral("400 Bad Request");
    case Response::MethodNotAllowed:
        return QByteArrayLiteral("405 Method Not Allowed");
    case Response::RequestTimeout:
        return QByteArrayLiteral("408 Request Timeout");
    case Response::Continue:
        return QByteArrayLiteral("100 Continue");
    case Response::SwitchingProtocols:
        return QByteArrayLiteral("101 Switching Protocols");
    case Response::Created:
        return QByteArrayLiteral("201 Created");
    case Response::Accepted:
        return QByteArrayLiteral("202 Accepted");
    case Response::NonAuthoritativeInformation:
        return QByteArrayLiteral("203 Non-Authoritative Information");
    case Response::NoContent:
        return QByteArrayLiteral("204 No Content");
    case Response::ResetContent:
        return QByteArrayLiteral("205 Reset Content");
    case Response::PartialContent:
        return QByteArrayLiteral("206 Partial Content");
    case Response::MultipleChoices:
        return QByteArrayLiteral("300 Multiple Choices");
    case Response::UseProxy:
        return QByteArrayLiteral("305 Use Proxy");
    case Response::PaymentRequired:
        return QByteArrayLiteral("402 Payment Required");
    case Response::NotAcceptable:
        return QByteArrayLiteral("406 Not Acceptable");
    case Response::ProxyAuthenticationRequired:
        return QByteArrayLiteral("407 Proxy Authentication Required");
    case Response::Conflict:
        return QByteArrayLiteral("409 Conflict");
    case Response::Gone:
        return QByteArrayLiteral("410 Gone");
    case Response::LengthRequired:
        return QByteArrayLiteral("411 Length Required");
    case Response::PreconditionFailed:
        return QByteArrayLiteral("412 Precondition Failed");
    case Response::RequestEntityTooLarge:
        return QByteArrayLiteral("413 Request Entity Too Large");
    case Response::RequestURITooLong:
        return QByteArrayLiteral("414 Request-URI Too Long");
    case Response::UnsupportedMediaType:
        return QByteArrayLiteral("415 Unsupported Media Type");
    case Response::RequestedRangeNotSatisfiable:
        return QByteArrayLiteral("416 Requested Range Not Satisfiable");
    case Response::ExpectationFailed:
        return QByteArrayLiteral("417 Expectation Failed");
    case Response::NotImplemented:
        return QByteArrayLiteral("501 Not Implemented");
    case Response::BadGateway:
        return QByteArrayLiteral("502 Bad Gateway");
    case Response::ServiceUnavailable:
        return QByteArrayLiteral("503 Service Unavailable");
    case Response::GatewayTimeout:
        return QByteArrayLiteral("504 Gateway Timeout");
    case Response::HTTPVersionNotSupported:
        return QByteArrayLiteral("505 HTTP Version Not Supported");
    case Response::BandwidthLimitExceeded:
        return QByteArrayLiteral("509 Bandwidth Limit Exceeded");
    default:
        return QByteArray::number(status);
    }
}

void Engine::reload()
{
    qCWarning(CUTELYST_ENGINE) << "Default reload implementation called, doing nothing";
}

QVariantHash Engine::config(const QString &entity) const
{
    Q_D(const Engine);
    return d->config.value(entity.toLower());
}

void Engine::handleRequest(Request *request, bool autoDelete)
{
    Q_D(Engine);
    Q_ASSERT(d->app);
    d->app->handleRequest(request);

    if (autoDelete) {
        delete request;
    }
}
<|endoftext|>