<commit_before>// This file is a part of Simdee, see homepage at http://github.com/tufak/simdee
// This file is distributed under the MIT license.

#ifndef SIMDEE_SIMD_TYPES_DUAL_HPP
#define SIMDEE_SIMD_TYPES_DUAL_HPP

#include "common.hpp"
#include <utility>

namespace sd {
    namespace impl {
        template <typename T>
        struct pair {
            using l_t = T;
            using r_t = T;
            T l;
            T r;
        };

        template <typename Mask_t>
        using dual_mask_t = impl::mask<((Mask_t::all_bits + 1) * (Mask_t::all_bits + 1)) - 1>;
    }

    template <typename T, typename Enable = void>
    struct dual;

    template <typename T>
    struct is_simd_type<dual<T>> : std::integral_constant<bool, true> {};

    template <typename T>
    struct simd_type_traits<dual<T>> {
        using simd_t = dual<T>;
        using vector_t = impl::pair<T>;
        using scalar_t = typename simd_type_traits<T>::scalar_t;
        using element_t = typename simd_type_traits<T>::element_t;
        using vec_b = dual<typename simd_type_traits<T>::vec_b>;
        using vec_f = dual<typename simd_type_traits<T>::vec_f>;
        using vec_u = dual<typename simd_type_traits<T>::vec_u>;
        using vec_s = dual<typename simd_type_traits<T>::vec_s>;
        using mask_t = impl::dual_mask_t<typename simd_type_traits<T>::mask_t>;
        using storage_t = impl::storage<simd_t, scalar_t, alignof(vector_t)>;
    };

    template <typename Crtp>
    struct dual_base : simd_base<Crtp> {
    protected:
        using T = typename simd_base<Crtp>::vector_t::l_t;
        using simd_base<Crtp>::mm;

    public:
        using vector_t = typename simd_base<Crtp>::vector_t;
        using scalar_t = typename simd_base<Crtp>::scalar_t;
        using element_t = typename simd_base<Crtp>::element_t;
        using storage_t = typename simd_base<Crtp>::storage_t;
        using simd_base<Crtp>::width;
        using simd_base<Crtp>::self;

        SIMDEE_TRIVIAL_TYPE(dual_base);

        SIMDEE_BASE_CTOR(dual_base, vector_t, mm = r);
        SIMDEE_BASE_CTOR(dual_base, scalar_t, mm.l = r; mm.r = r);
        SIMDEE_BASE_CTOR_TPL(dual_base, expr::aligned<T>, aligned_load(r.ptr));
        SIMDEE_BASE_CTOR_TPL(dual_base, expr::unaligned<T>, unaligned_load(r.ptr));
        SIMDEE_BASE_CTOR_TPL(dual_base, expr::init<T>, mm.l = r; mm.r = r);
        SIMDEE_BASE_CTOR(dual_base, storage_t, aligned_load(r.data()));

        SIMDEE_INL void aligned_load(const scalar_t* r) {
            mm.l.aligned_load(r);
            mm.r.aligned_load(r + T::width);
        }

        SIMDEE_INL void aligned_store(scalar_t* r) const {
            mm.l.aligned_store(r);
            mm.r.aligned_store(r + T::width);
        }

        SIMDEE_INL void unaligned_load(const scalar_t* r) {
            mm.l.unaligned_load(r);
            mm.r.unaligned_load(r + T::width);
        }

        SIMDEE_INL void unaligned_store(scalar_t* r) const {
            mm.l.unaligned_store(r);
            mm.r.unaligned_store(r + T::width);
        }

        SIMDEE_INL void interleaved_load(const scalar_t* r, std::size_t step) {
            mm.l.interleaved_load(r);
            mm.r.interleaved_load(r + (T::width * step));
        }

        SIMDEE_INL void interleaved_store(scalar_t* r, std::size_t step) const {
            mm.l.interleaved_store(r);
            mm.r.interleaved_store(r + (T::width * step));
        }

        template <typename Op_t>
        const Crtp reduce(Op_t f) const {
            vector_t res;
            res.l = mm.l.reduce(f);
            res.r = mm.r.reduce(f);
            res.l = f(res.l, res.r);
            res.r = res.l;
            return res;
        }

        SIMDEE_INL element_t first_element() const { return mm.l.first_element(); }
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_b>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using mask_t = typename simd_base<dual<T>>::mask_t;
        using dual_base<dual<T>>::dual_base;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL mask_t mask() const {
            return mask_t(mm.l.mask().value | (mm.r.mask().value << T::width));
        }
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_f>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vec_s = typename simd_base<dual<T>>::vec_s;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL explicit dual(const vec_s& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        using dual_base<dual<T>>::dual_base;
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_u>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vec_b = typename simd_base<dual<T>>::vec_b;
        using vec_s = typename simd_base<dual<T>>::vec_s;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL explicit dual(const vec_b& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        SIMDEE_INL explicit dual(const vec_s& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        using dual_base<dual<T>>::dual_base;
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_s>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vec_f = typename simd_base<dual<T>>::vec_f;
        using vec_u = typename simd_base<dual<T>>::vec_u;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL explicit dual(const vec_f& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        SIMDEE_INL explicit dual(const vec_u& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        using dual_base<dual<T>>::dual_base;
    };
}

#endif // SIMDEE_SIMD_TYPES_DUAL_HPP
<commit_msg>Implement dual's boolean arithmetic #8<commit_after>// This file is a part of Simdee, see homepage at http://github.com/tufak/simdee
// This file is distributed under the MIT license.

#ifndef SIMDEE_SIMD_TYPES_DUAL_HPP
#define SIMDEE_SIMD_TYPES_DUAL_HPP

#include "common.hpp"
#include <utility>

namespace sd {
    namespace impl {
        template <typename T>
        struct pair {
            using l_t = T;
            using r_t = T;
            T l;
            T r;
        };

        template <typename Mask_t>
        using dual_mask_t = impl::mask<((Mask_t::all_bits + 1) * (Mask_t::all_bits + 1)) - 1>;
    }

    template <typename T, typename Enable = void>
    struct dual;

    template <typename T>
    struct is_simd_type<dual<T>> : std::integral_constant<bool, true> {};

    template <typename T>
    struct simd_type_traits<dual<T>> {
        using simd_t = dual<T>;
        using vector_t = impl::pair<T>;
        using scalar_t = typename simd_type_traits<T>::scalar_t;
        using element_t = typename simd_type_traits<T>::element_t;
        using vec_b = dual<typename simd_type_traits<T>::vec_b>;
        using vec_f = dual<typename simd_type_traits<T>::vec_f>;
        using vec_u = dual<typename simd_type_traits<T>::vec_u>;
        using vec_s = dual<typename simd_type_traits<T>::vec_s>;
        using mask_t = impl::dual_mask_t<typename simd_type_traits<T>::mask_t>;
        using storage_t = impl::storage<simd_t, scalar_t, alignof(vector_t)>;
    };

    template <typename Crtp>
    struct dual_base : simd_base<Crtp> {
    protected:
        using T = typename simd_base<Crtp>::vector_t::l_t;
        using simd_base<Crtp>::mm;

    public:
        using vector_t = typename simd_base<Crtp>::vector_t;
        using scalar_t = typename simd_base<Crtp>::scalar_t;
        using element_t = typename simd_base<Crtp>::element_t;
        using storage_t = typename simd_base<Crtp>::storage_t;
        using simd_base<Crtp>::width;
        using simd_base<Crtp>::self;

        SIMDEE_TRIVIAL_TYPE(dual_base);

        SIMDEE_BASE_CTOR(dual_base, vector_t, mm = r);
        SIMDEE_BASE_CTOR(dual_base, scalar_t, mm.l = r; mm.r = r);
        SIMDEE_BASE_CTOR_TPL(dual_base, expr::aligned<T>, aligned_load(r.ptr));
        SIMDEE_BASE_CTOR_TPL(dual_base, expr::unaligned<T>, unaligned_load(r.ptr));
        SIMDEE_BASE_CTOR_TPL(dual_base, expr::init<T>, mm.l = r; mm.r = r);
        SIMDEE_BASE_CTOR(dual_base, storage_t, aligned_load(r.data()));

        SIMDEE_INL void aligned_load(const scalar_t* r) {
            mm.l.aligned_load(r);
            mm.r.aligned_load(r + T::width);
        }

        SIMDEE_INL void aligned_store(scalar_t* r) const {
            mm.l.aligned_store(r);
            mm.r.aligned_store(r + T::width);
        }

        SIMDEE_INL void unaligned_load(const scalar_t* r) {
            mm.l.unaligned_load(r);
            mm.r.unaligned_load(r + T::width);
        }

        SIMDEE_INL void unaligned_store(scalar_t* r) const {
            mm.l.unaligned_store(r);
            mm.r.unaligned_store(r + T::width);
        }

        SIMDEE_INL void interleaved_load(const scalar_t* r, std::size_t step) {
            mm.l.interleaved_load(r);
            mm.r.interleaved_load(r + (T::width * step));
        }

        SIMDEE_INL void interleaved_store(scalar_t* r, std::size_t step) const {
            mm.l.interleaved_store(r);
            mm.r.interleaved_store(r + (T::width * step));
        }

        template <typename Op_t>
        const Crtp reduce(Op_t f) const {
            vector_t res;
            res.l = mm.l.reduce(f);
            res.r = mm.r.reduce(f);
            res.l = f(res.l, res.r);
            res.r = res.l;
            return res;
        }

        SIMDEE_INL element_t first_element() const { return mm.l.first_element(); }
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_b>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vector_t = typename simd_base<dual<T>>::vector_t;
        using element_t = typename simd_base<dual<T>>::element_t;
        using vec_b = typename simd_base<dual<T>>::vec_b;
        using vec_f = typename simd_base<dual<T>>::vec_f;
        using vec_u = typename simd_base<dual<T>>::vec_u;
        using vec_s = typename simd_base<dual<T>>::vec_s;
        using mask_t = typename simd_base<dual<T>>::mask_t;
        using dual_base<dual<T>>::dual_base;

        SIMDEE_TRIVIAL_TYPE(dual);
        SIMDEE_CTOR(dual, element_t, mm.l = r; mm.r = r);

        SIMDEE_INL mask_t mask() const {
            return mask_t(mm.l.mask().value | (mm.r.mask().value << T::width));
        }

        SIMDEE_BINOP(vec_b, vec_b, operator==, (vector_t{ l.mm.l == r.mm.l, l.mm.r == r.mm.r }));
        SIMDEE_BINOP(vec_b, vec_b, operator!=, (vector_t{ l.mm.l != r.mm.l, l.mm.r != r.mm.r }));
        SIMDEE_BINOP(vec_b, vec_b, operator&&, (vector_t{ l.mm.l && r.mm.l, l.mm.r && r.mm.r }));
        SIMDEE_BINOP(vec_b, vec_b, operator||, (vector_t{ l.mm.l || r.mm.l, l.mm.r || r.mm.r }));
        SIMDEE_UNOP(vec_b, vec_b, operator!, (vector_t{!l.mm.l, !l.mm.r}));
        SIMDEE_BINOP(vec_b, vec_b, andnot, (vector_t{ andnot(l.mm.l, r.mm.l), andnot(l.mm.r, r.mm.r) }));
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_f>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vec_s = typename simd_base<dual<T>>::vec_s;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL explicit dual(const vec_s& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        using dual_base<dual<T>>::dual_base;
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_u>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vec_b = typename simd_base<dual<T>>::vec_b;
        using vec_s = typename simd_base<dual<T>>::vec_s;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL explicit dual(const vec_b& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        SIMDEE_INL explicit dual(const vec_s& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        using dual_base<dual<T>>::dual_base;
    };

    template <typename T>
    struct dual<T, typename std::enable_if<std::is_same<T, typename T::vec_s>::value>::type> : dual_base<dual<T>> {
    private:
        using simd_base<dual<T>>::mm;

    public:
        using vec_f = typename simd_base<dual<T>>::vec_f;
        using vec_u = typename simd_base<dual<T>>::vec_u;

        SIMDEE_TRIVIAL_TYPE(dual);

        SIMDEE_INL explicit dual(const vec_f& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        SIMDEE_INL explicit dual(const vec_u& r) {
            mm.l = decltype(mm.l)(r.data().l);
            mm.r = decltype(mm.r)(r.data().r);
        }

        using dual_base<dual<T>>::dual_base;
    };
}

#endif // SIMDEE_SIMD_TYPES_DUAL_HPP
<|endoftext|>


<commit_before>/*
* Copyright (C) 2016 - 2020 Judd Niemann - All Rights Reserved.
* You may use, distribute and modify this code under the
* terms of the GNU Lesser General Public License, version 2.1
*
* You should have received a copy of GNU Lesser General Public License v2.1
* with this file. If not, please refer to: https://github.com/jniemann66/ferocious
*/

#include "converterconfigurationdialog.h"
#include "checkboxdelegate.h"
#include "cmdlinehighlighterdelegate.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QApplication>
#include <QToolButton>

ConverterConfigurationDialog::ConverterConfigurationDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f), showToolTips(true)
{
    // allocate
    auto headingLabel = new QLabel("Configure External Converters");
    mainConverterLocationLabel = new QLabel("Location of Main Converter:");
    mainConverterLocationEdit = new FancyLineEdit;
    contextMenu = new QMenu(this);
    contextToolBar = new QToolBar(this);
    browseButton = new QPushButton("Browse ...");
    additionalConvertersLabel = new QLabel("Additional converters:");
    auto stdButtons = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    auto mainLayout = new QVBoxLayout;
    auto mainConverterLayout = new QHBoxLayout;

    // set tooltips
    additionalConvertersLabel->setToolTip("Use the table below to cofigure additional converters for specialized file formats.");
    QPushButton* restoreDefaultsButton = stdButtons->button(QDialogButtonBox::RestoreDefaults);
    if(restoreDefaultsButton != nullptr) {
        restoreDefaultsButton->setToolTip(tr("Restore converter configuration to default settings"));
    }

    // set model
    tableView.setModel(&convertersModel);

    // configure view
    tableView.verticalHeader()->setHidden(true);
    tableView.setSelectionMode(QAbstractItemView::SingleSelection);
    tableView.setSelectionBehavior(QAbstractItemView::SelectRows);
    tableView.setContextMenuPolicy(Qt::CustomContextMenu);
    tableView.horizontalHeader()->setStretchLastSection(true);

    // configure menu & toolbar
    initMenu();
    initToolBar();
    contextToolBar->hide();

    // configure fonts
    QFont defaultFont{qApp->font()};
    QFont heading2Font{defaultFont};
    QFont heading1Font{defaultFont};
    heading2Font.setPointSize(defaultFont.pointSize() + 2);
    heading1Font.setPointSize(defaultFont.pointSize() + 4);

    // configure widgets
    headingLabel->setFont(heading1Font);
    headingLabel->setAlignment(Qt::AlignHCenter);
    mainConverterLocationEdit->hideEditButton();
    mainConverterLocationLabel->setFont(heading2Font);
    additionalConvertersLabel->setFont(heading2Font);

    // attach widgets to main layout
    mainLayout->addWidget(headingLabel);
    mainLayout->addSpacing(6);
    mainLayout->addWidget(mainConverterLocationLabel);
    mainConverterLayout->addWidget(mainConverterLocationEdit);
    mainConverterLayout->addWidget(browseButton);
    mainLayout->addLayout(mainConverterLayout);
    mainLayout->addSpacing(6);
    mainLayout->addWidget(additionalConvertersLabel);
    mainLayout->addWidget(&tableView);
    mainLayout->addWidget(stdButtons);
    setLayout(mainLayout);

    // hide unnecessary columns
    tableView.setColumnHidden(0, true);
    tableView.setColumnHidden(3, true);
    tableView.setColumnHidden(6, true);
    tableView.setColumnHidden(9, true);
    tableView.setColumnHidden(10, true);

    // set delegates
    tableView.setItemDelegateForColumn(8, new CmdLineHighlighterDelegate(this));
    tableView.setItemDelegateForColumn(1, new CheckBoxDelegate(this));

    // connect signals / slots
    connect(mainConverterLocationEdit, &QLineEdit::editingFinished, this, [this] {
       mainConverterPath = mainConverterLocationEdit->text();
    });

    connect(browseButton, &QPushButton::clicked, this, &ConverterConfigurationDialog::promptForResamplerLocation);
    connect(&tableView, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){
        contextMenu->popup(QPoint{this->mapToGlobal(pos).x(), this->mapToGlobal(pos).y() + contextMenu->sizeHint().height()});
        contextToolBar->hide();
    });

    connect(&tableView, &QTableView::clicked, this, [this](const QModelIndex& modelIndex) {
        if(modelIndex.column() == 1)
            return;

        QPoint p{tableView.columnViewportPosition(4), tableView.rowViewportPosition(modelIndex.row())};
        QPoint q = tableView.mapTo(this, p + QPoint{0, tableView.rowHeight(modelIndex.row()) / 2});
        contextToolBar->move(q);
        contextToolBar->show();
        contextToolBar->raise();
    });

    connect(stdButtons, &QDialogButtonBox::clicked, this, [this, stdButtons](QAbstractButton* b) {
        if(b == stdButtons->button(QDialogButtonBox::RestoreDefaults)) {
            onRestoreDefaults();
        }
    });

    connect(stdButtons, &QDialogButtonBox::accepted, this, &QDialog::accept);
    connect(stdButtons, &QDialogButtonBox::rejected, this, &QDialog::reject);
}

void ConverterConfigurationDialog::initMenu() {
	contextMenu->addAction(tr("New"), [this] {
       onNewRequested(tableView.currentIndex());
    }, QKeySequence::New);

	contextMenu->addAction(tr("Edit ..."), [this] {
       onEditRequested(tableView.currentIndex());
    });

	contextMenu->addAction(tr("Clone"), [this] {
       onCloneRequested(tableView.currentIndex());
    }, QKeySequence::Copy);

	contextMenu->addAction(tr("Delete"), [this] {
       onDeleteRequested(tableView.currentIndex());
    }, {QKeySequence::Delete});

	contextMenu->addAction(tr("Move Up"), [this] {
        onMoveUpRequested(tableView.currentIndex());
    });

	contextMenu->addAction(tr("Move Down"), [this] {
        onMoveDownRequested(tableView.currentIndex());
    });
}

void ConverterConfigurationDialog::initToolBar() {
    QList<QAction*> actions;

	actions.append(contextToolBar->addAction(tr("New"), [this] {
       onNewRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Edit ..."), [this] {
       onEditRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Clone"), [this] {
       onCloneRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Delete"), [this] {
       onDeleteRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Move Up"), [this] {
        onMoveUpRequested(tableView.currentIndex());
        //contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Move Down"), [this] {
        onMoveDownRequested(tableView.currentIndex());
        //contextToolBar->hide();
    }));

    contextToolBar->setContentsMargins(0, 0, 0, 0);
    contextToolBar->setMinimumWidth(tableView.width() / 2);
    contextToolBar->setMaximumWidth(tableView.width());
    contextToolBar->setFixedHeight(40);
    contextToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    contextToolBar->setStyleSheet("QToolBar {background-color: rgba(0,0,0,0);}");

    for(QAction* a : actions) {
        QWidget* w = contextToolBar->widgetForAction(a);
        if(QString(w->metaObject()->className()) == "QToolButton") {
            auto* t = qobject_cast<QToolButton*>(w);
            if(t != nullptr) {
                t->setStyleSheet("QToolButton {padding: 5px; border-radius: 3px}");
            }
        }
    }
}

void ConverterConfigurationDialog::showEvent(QShowEvent* event) {

    if(mainConverterPath.isEmpty() || !QFile::exists(mainConverterPath)) {
       promptForResamplerLocation();
    }

    mainConverterLocationLabel->setText(QString{"Location of Main Converter (%1):"}.arg(expectedMainConverter));
    mainConverterLocationEdit->setText(mainConverterPath);

    QDialog::showEvent(event);
}

void ConverterConfigurationDialog::resizeEvent(QResizeEvent *event)
{
    int tw = event->size().width();

    static const QVector<double> columnWidths {
        0,      /* "Priority" */
        10,     /* "Enabled" */
        20,     /* "Name" */
        0 ,     /* "Comment" */
        12,     /* "Input File Extension" */
        12,     /* "Output File Extension" */
        0 ,     /* "Executable" */
        20,     /* "Executable Path" */
        20,     /* "Command Line" */
        0 ,     /* "Download Locations" */
        0      /* "Operating Systems" */
    };

    for(int col = 0; col < convertersModel.columnCount({}) - 1; col++) {
        tableView.horizontalHeader()->resizeSection(col, tw * columnWidths.at(col)/100.0);
    }

    tableView.horizontalHeader()->setHidden(false);

    QDialog::resizeEvent(event);
}

QVector<ConverterDefinition> ConverterConfigurationDialog::getConverterDefinitions() const
{
    return convertersModel.getConverterDefinitions();
}

void ConverterConfigurationDialog::setConverterDefinitions(const QVector<ConverterDefinition> &value)
{
    convertersModel.setConverterDefinitions(value);
}

void ConverterConfigurationDialog::promptForResamplerLocation() {
    QString s(tr("Please locate the file: "));
    s.append(expectedMainConverter);

#if defined (Q_OS_WIN)
    QString filter = "*.exe";
#else
    QString filter = "";
#endif

    QString cp = QFileDialog::getOpenFileName(this, s, mainConverterPath,  filter);

    if(!cp.isNull()) {
        mainConverterPath = cp;
        if(mainConverterPath.lastIndexOf(expectedMainConverter, -1, Qt::CaseInsensitive) == -1) { // safeguard against wrong executable being configured
            mainConverterPath.clear();
            QMessageBox::warning(this, tr("Converter Location"), tr("That is not the right program!\n"), QMessageBox::Ok);
        }
    }
}

QString ConverterConfigurationDialog::getMainConverterPath() const
{
    return mainConverterPath;
}

void ConverterConfigurationDialog::setMainConverterPath(const QString &value)
{
    mainConverterPath = value;
}

QString ConverterConfigurationDialog::getExpectedMainConverter() const
{
    return expectedMainConverter;
}

void ConverterConfigurationDialog::setExpectedMainConverter(const QString &value)
{
    expectedMainConverter = value;
    // set tooltips
    mainConverterLocationLabel->setToolTip(QString{"Please enter the location of %1 in the box below.\n"
                                           "(%1 is the command-line audio converter that Ferocious was designed to work with.)"
                                           }.arg(expectedMainConverter));
    mainConverterLocationEdit->setToolTip(QString{"Location of %1\n"
                                          "Note: you can also use drag-and-drop, or the 'Browse' button"}.arg(expectedMainConverter));
    browseButton->setToolTip(QString{"Browse to location of %1"}.arg(expectedMainConverter));
}

void ConverterConfigurationDialog::onNewRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0)
        return;

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        converterDefinitions.insert(row, {});
        convertersModel.setConverterDefinitions(converterDefinitions);
    }
}

void ConverterConfigurationDialog::onEditRequested(const QModelIndex& modelIndex)
{
    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if (converterDefinitions.isEmpty())
        return;

    int row = modelIndex.row();

    if (row < 0)
        return;

    auto dlg = new ConverterConfigurationEditDialog(this);
    dlg->setShowToolTips(showToolTips);
    if(!editDialogGeometry.isNull()) {
        dlg->setGeometry(editDialogGeometry);
    }

    if(row < converterDefinitions.count()) {
        dlg->setConverterDefinition(converterDefinitions.at(row));
        int result = dlg->exec();
        editDialogGeometry = dlg->geometry();
        if(result == QDialog::Accepted) {
            converterDefinitions[row] = dlg->getConverterDefinition();
            convertersModel.setConverterDefinitions(converterDefinitions);
        }
    }
}

void ConverterConfigurationDialog::onDeleteRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0)
        return;

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        converterDefinitions.removeAt(row);
        convertersModel.setConverterDefinitions(converterDefinitions);
    }
}

void ConverterConfigurationDialog::onCloneRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0)
        return;

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        converterDefinitions.insert(row, converterDefinitions.at(row));
        convertersModel.setConverterDefinitions(converterDefinitions);
    }
}

void ConverterConfigurationDialog::onMoveUpRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 1) {
        return;
    }

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        qSwap(converterDefinitions[row], converterDefinitions[row - 1]);
        convertersModel.setConverterDefinitions(converterDefinitions);
        tableView.selectRow(row - 1);
    }
}

void ConverterConfigurationDialog::onMoveDownRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0) {
        return;
    }

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count() - 1) {
        qSwap(converterDefinitions[row], converterDefinitions[row + 1]);
        convertersModel.setConverterDefinitions(converterDefinitions);
        tableView.selectRow(row + 1);
    }
}

void ConverterConfigurationDialog::onRestoreDefaults() {
    setConverterDefinitions(ConverterDefinition::loadConverterDefinitions(":/converters.json"));
}

QRect ConverterConfigurationDialog::getEditDialogGeometry() const
{
    return editDialogGeometry;
}

void ConverterConfigurationDialog::setEditDialogGeometry(const QRect &value)
{
    editDialogGeometry = value;
}

void ConverterConfigurationDialog::setShowToolTips(bool value)
{
    showToolTips = value;
}

bool ConverterConfigurationDialog::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::ToolTip) { // Intercept tooltip event
        return (showToolTips);
    }

	return ConverterConfigurationDialog::eventFilter(obj, event);
}
<commit_msg>cleanup<commit_after>/*
* Copyright (C) 2016 - 2020 Judd Niemann - All Rights Reserved.
* You may use, distribute and modify this code under the
* terms of the GNU Lesser General Public License, version 2.1
*
* You should have received a copy of GNU Lesser General Public License v2.1
* with this file. If not, please refer to: https://github.com/jniemann66/ferocious
*/

#include "converterconfigurationdialog.h"
#include "checkboxdelegate.h"
#include "cmdlinehighlighterdelegate.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QApplication>
#include <QToolButton>

ConverterConfigurationDialog::ConverterConfigurationDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f), showToolTips(true)
{
    // allocate
    auto headingLabel = new QLabel("Configure External Converters");
    mainConverterLocationLabel = new QLabel("Location of Main Converter:");
    mainConverterLocationEdit = new FancyLineEdit;
    contextMenu = new QMenu(this);
    contextToolBar = new QToolBar(this);
    browseButton = new QPushButton("Browse ...");
    additionalConvertersLabel = new QLabel("Additional converters:");
    auto stdButtons = new QDialogButtonBox(QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    auto mainLayout = new QVBoxLayout;
    auto mainConverterLayout = new QHBoxLayout;

    // set tooltips
    additionalConvertersLabel->setToolTip("Use the table below to cofigure additional converters for specialized file formats.");
    QPushButton* restoreDefaultsButton = stdButtons->button(QDialogButtonBox::RestoreDefaults);
    if(restoreDefaultsButton != nullptr) {
        restoreDefaultsButton->setToolTip(tr("Restore converter configuration to default settings"));
    }

    // set model
    tableView.setModel(&convertersModel);

    // configure view
    tableView.verticalHeader()->setHidden(true);
    tableView.setSelectionMode(QAbstractItemView::SingleSelection);
    tableView.setSelectionBehavior(QAbstractItemView::SelectRows);
    tableView.setContextMenuPolicy(Qt::CustomContextMenu);
    tableView.horizontalHeader()->setStretchLastSection(true);

    // configure menu & toolbar
    initMenu();
    initToolBar();
    contextToolBar->hide();

    // configure fonts
    QFont defaultFont{qApp->font()};
    QFont heading2Font{defaultFont};
    QFont heading1Font{defaultFont};
    heading2Font.setPointSize(defaultFont.pointSize() + 2);
    heading1Font.setPointSize(defaultFont.pointSize() + 4);

    // configure widgets
    headingLabel->setFont(heading1Font);
    headingLabel->setAlignment(Qt::AlignHCenter);
    mainConverterLocationEdit->hideEditButton();
    mainConverterLocationLabel->setFont(heading2Font);
    additionalConvertersLabel->setFont(heading2Font);

    // attach widgets to main layout
    mainLayout->addWidget(headingLabel);
    mainLayout->addSpacing(6);
    mainLayout->addWidget(mainConverterLocationLabel);
    mainConverterLayout->addWidget(mainConverterLocationEdit);
    mainConverterLayout->addWidget(browseButton);
    mainLayout->addLayout(mainConverterLayout);
    mainLayout->addSpacing(6);
    mainLayout->addWidget(additionalConvertersLabel);
    mainLayout->addWidget(&tableView);
    mainLayout->addWidget(stdButtons);
    setLayout(mainLayout);

    // hide unnecessary columns
    tableView.setColumnHidden(0, true);
    tableView.setColumnHidden(3, true);
    tableView.setColumnHidden(6, true);
    tableView.setColumnHidden(9, true);
    tableView.setColumnHidden(10, true);

    // set delegates
    tableView.setItemDelegateForColumn(8, new CmdLineHighlighterDelegate(this));
    tableView.setItemDelegateForColumn(1, new CheckBoxDelegate(this));

    // connect signals / slots
    connect(mainConverterLocationEdit, &QLineEdit::editingFinished, this, [this] {
       mainConverterPath = mainConverterLocationEdit->text();
    });

    connect(browseButton, &QPushButton::clicked, this, &ConverterConfigurationDialog::promptForResamplerLocation);
    connect(&tableView, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){
        contextMenu->popup(QPoint{this->mapToGlobal(pos).x(), this->mapToGlobal(pos).y() + contextMenu->sizeHint().height()});
        contextToolBar->hide();
    });

    connect(&tableView, &QTableView::clicked, this, [this](const QModelIndex& modelIndex) {
        if(modelIndex.column() == 1)
            return;

        QPoint p{tableView.columnViewportPosition(4), tableView.rowViewportPosition(modelIndex.row())};
        QPoint q = tableView.mapTo(this, p + QPoint{0, tableView.rowHeight(modelIndex.row()) / 2});
        contextToolBar->move(q);
        contextToolBar->show();
        contextToolBar->raise();
    });

    connect(stdButtons, &QDialogButtonBox::clicked, this, [this, stdButtons](QAbstractButton* b) {
        if(b == stdButtons->button(QDialogButtonBox::RestoreDefaults)) {
            onRestoreDefaults();
        }
    });

    connect(stdButtons, &QDialogButtonBox::accepted, this, &QDialog::accept);
    connect(stdButtons, &QDialogButtonBox::rejected, this, &QDialog::reject);
}

void ConverterConfigurationDialog::initMenu() {
	contextMenu->addAction(tr("New"), [this] {
       onNewRequested(tableView.currentIndex());
    }, QKeySequence::New);

	contextMenu->addAction(tr("Edit ..."), [this] {
       onEditRequested(tableView.currentIndex());
    });

	contextMenu->addAction(tr("Clone"), [this] {
       onCloneRequested(tableView.currentIndex());
    }, QKeySequence::Copy);

	contextMenu->addAction(tr("Delete"), [this] {
       onDeleteRequested(tableView.currentIndex());
    }, {QKeySequence::Delete});

	contextMenu->addAction(tr("Move Up"), [this] {
        onMoveUpRequested(tableView.currentIndex());
    });

	contextMenu->addAction(tr("Move Down"), [this] {
        onMoveDownRequested(tableView.currentIndex());
    });
}

void ConverterConfigurationDialog::initToolBar() {
    QList<QAction*> actions;

	actions.append(contextToolBar->addAction(tr("New"), [this] {
       onNewRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Edit ..."), [this] {
       onEditRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Clone"), [this] {
       onCloneRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Delete"), [this] {
       onDeleteRequested(tableView.currentIndex());
       contextToolBar->hide();
    }));

	actions.append(contextToolBar->addAction(tr("Move Up"), [this] {
        onMoveUpRequested(tableView.currentIndex());
    }));

	actions.append(contextToolBar->addAction(tr("Move Down"), [this] {
        onMoveDownRequested(tableView.currentIndex());
    }));

    contextToolBar->setContentsMargins(0, 0, 0, 0);
    contextToolBar->setMinimumWidth(tableView.width() / 2);
    contextToolBar->setMaximumWidth(tableView.width());
    contextToolBar->setFixedHeight(40);
    contextToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    contextToolBar->setStyleSheet("QToolBar {background-color: rgba(0,0,0,0);}");

    for(QAction* a : actions) {
        QWidget* w = contextToolBar->widgetForAction(a);
        if(QString(w->metaObject()->className()) == "QToolButton") {
            auto* t = qobject_cast<QToolButton*>(w);
            if(t != nullptr) {
                t->setStyleSheet("QToolButton {padding: 5px; border-radius: 3px}");
            }
        }
    }
}

void ConverterConfigurationDialog::showEvent(QShowEvent* event) {

    if(mainConverterPath.isEmpty() || !QFile::exists(mainConverterPath)) {
       promptForResamplerLocation();
    }

    mainConverterLocationLabel->setText(QString{"Location of Main Converter (%1):"}.arg(expectedMainConverter));
    mainConverterLocationEdit->setText(mainConverterPath);

    QDialog::showEvent(event);
}

void ConverterConfigurationDialog::resizeEvent(QResizeEvent *event)
{
    int tw = event->size().width();

    static const QVector<double> columnWidths {
        0,      /* "Priority" */
        10,     /* "Enabled" */
        20,     /* "Name" */
        0 ,     /* "Comment" */
        12,     /* "Input File Extension" */
        12,     /* "Output File Extension" */
        0 ,     /* "Executable" */
        20,     /* "Executable Path" */
        20,     /* "Command Line" */
        0 ,     /* "Download Locations" */
        0      /* "Operating Systems" */
    };

    for(int col = 0; col < convertersModel.columnCount({}) - 1; col++) {
        tableView.horizontalHeader()->resizeSection(col, tw * columnWidths.at(col)/100.0);
    }

    tableView.horizontalHeader()->setHidden(false);

    QDialog::resizeEvent(event);
}

QVector<ConverterDefinition> ConverterConfigurationDialog::getConverterDefinitions() const
{
    return convertersModel.getConverterDefinitions();
}

void ConverterConfigurationDialog::setConverterDefinitions(const QVector<ConverterDefinition> &value)
{
    convertersModel.setConverterDefinitions(value);
}

void ConverterConfigurationDialog::promptForResamplerLocation() {
    QString s(tr("Please locate the file: "));
    s.append(expectedMainConverter);

#if defined (Q_OS_WIN)
    QString filter = "*.exe";
#else
    QString filter = "";
#endif

    QString cp = QFileDialog::getOpenFileName(this, s, mainConverterPath,  filter);

    if(!cp.isNull()) {
        mainConverterPath = cp;
        if(mainConverterPath.lastIndexOf(expectedMainConverter, -1, Qt::CaseInsensitive) == -1) { // safeguard against wrong executable being configured
            mainConverterPath.clear();
            QMessageBox::warning(this, tr("Converter Location"), tr("That is not the right program!\n"), QMessageBox::Ok);
        }
    }
}

QString ConverterConfigurationDialog::getMainConverterPath() const
{
    return mainConverterPath;
}

void ConverterConfigurationDialog::setMainConverterPath(const QString &value)
{
    mainConverterPath = value;
}

QString ConverterConfigurationDialog::getExpectedMainConverter() const
{
    return expectedMainConverter;
}

void ConverterConfigurationDialog::setExpectedMainConverter(const QString &value)
{
    expectedMainConverter = value;
    // set tooltips
    mainConverterLocationLabel->setToolTip(QString{"Please enter the location of %1 in the box below.\n"
                                           "(%1 is the command-line audio converter that Ferocious was designed to work with.)"
                                           }.arg(expectedMainConverter));
    mainConverterLocationEdit->setToolTip(QString{"Location of %1\n"
                                          "Note: you can also use drag-and-drop, or the 'Browse' button"}.arg(expectedMainConverter));
    browseButton->setToolTip(QString{"Browse to location of %1"}.arg(expectedMainConverter));
}

void ConverterConfigurationDialog::onNewRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0)
        return;

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        converterDefinitions.insert(row, {});
        convertersModel.setConverterDefinitions(converterDefinitions);
    }
}

void ConverterConfigurationDialog::onEditRequested(const QModelIndex& modelIndex)
{
    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if (converterDefinitions.isEmpty())
        return;

    int row = modelIndex.row();

    if (row < 0)
        return;

    auto dlg = new ConverterConfigurationEditDialog(this);
    dlg->setShowToolTips(showToolTips);
    if(!editDialogGeometry.isNull()) {
        dlg->setGeometry(editDialogGeometry);
    }

    if(row < converterDefinitions.count()) {
        dlg->setConverterDefinition(converterDefinitions.at(row));
        int result = dlg->exec();
        editDialogGeometry = dlg->geometry();
        if(result == QDialog::Accepted) {
            converterDefinitions[row] = dlg->getConverterDefinition();
            convertersModel.setConverterDefinitions(converterDefinitions);
        }
    }
}

void ConverterConfigurationDialog::onDeleteRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0)
        return;

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        converterDefinitions.removeAt(row);
        convertersModel.setConverterDefinitions(converterDefinitions);
    }
}

void ConverterConfigurationDialog::onCloneRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0)
        return;

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        converterDefinitions.insert(row, converterDefinitions.at(row));
        convertersModel.setConverterDefinitions(converterDefinitions);
    }
}

void ConverterConfigurationDialog::onMoveUpRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 1) {
        return;
    }

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count()) {
        qSwap(converterDefinitions[row], converterDefinitions[row - 1]);
        convertersModel.setConverterDefinitions(converterDefinitions);
        tableView.selectRow(row - 1);
    }
}

void ConverterConfigurationDialog::onMoveDownRequested(const QModelIndex& modelIndex)
{
    int row = modelIndex.row();

    if(row < 0) {
        return;
    }

    QVector<ConverterDefinition> converterDefinitions = convertersModel.getConverterDefinitions();
    if(row < converterDefinitions.count() - 1) {
        qSwap(converterDefinitions[row], converterDefinitions[row + 1]);
        convertersModel.setConverterDefinitions(converterDefinitions);
        tableView.selectRow(row + 1);
    }
}

void ConverterConfigurationDialog::onRestoreDefaults() {
    setConverterDefinitions(ConverterDefinition::loadConverterDefinitions(":/converters.json"));
}

QRect ConverterConfigurationDialog::getEditDialogGeometry() const
{
    return editDialogGeometry;
}

void ConverterConfigurationDialog::setEditDialogGeometry(const QRect &value)
{
    editDialogGeometry = value;
}

void ConverterConfigurationDialog::setShowToolTips(bool value)
{
    showToolTips = value;
}

bool ConverterConfigurationDialog::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::ToolTip) { // Intercept tooltip event
        return (showToolTips);
    }

	return ConverterConfigurationDialog::eventFilter(obj, event);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep07/call_mss_eff_config.C $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file call_mss_eff_config.C
 *  Contains the wrapper for mss_eff_config istep
 */

/******************************************************************************/
// Includes
/******************************************************************************/

// STD
#include    <stdint.h>
#include    <stdlib.h>
#include    <map>

// Generated
#include    <attributeenums.H>
#include    <config.h>

// Errors and Tracing Support
#include    <trace/interface.H>
#include    <initservice/taskargs.H>
#include    <initservice/isteps_trace.H>
#include    <errl/errlentry.H>
#include    <errl/errludtarget.H>
#include    <isteps/hwpisteperror.H>
#include    <hbotcompid.H>

// Pnor Support
#include    <pnor/pnorif.H>

// Targeting Support
#include    <targeting/common/commontargeting.H>
#include    <targeting/common/utilFilter.H>
#include    <targeting/common/util.H>
#include    <targeting/targplatutil.H>

// Fapi Support
#include    <fapi2.H>
#include    <fapi2/plat_hwp_invoker.H>

// HWPs
#include    <p10_mss_eff_config.H>
#include    <exp_mss_eff_config_thermal.H>
#include    <p10_mss_eff_grouping.H>

// SMF Support
#include    <secureboot/smf.H>
#include    <secureboot/smf_utils.H>

#include    <nvram/nvram_interface.H>

// isSimicsRunning
#include    <util/misc.H>

namespace   ISTEP_07
{

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;

/**
 * @brief Call p10_mss_eff_grouping HWP on each proc target
 * @param io_istepErr - updated with any HWP errors
 */
void call_mss_eff_grouping(IStepError & io_istepErr)
{
    errlHndl_t l_err = nullptr;

    TargetHandleList l_procsList;
    getAllChips(l_procsList, TYPE_PROC);

    for (const auto & l_cpu_target : l_procsList)
    {
        //  print call to hwp and write HUID of the target(s)
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "p10_mss_eff_grouping HWP cpu target HUID %.8X",
            get_huid(l_cpu_target));

        // cast OUR type of target to a FAPI type of target.
        const fapi2::Target <fapi2::TARGET_TYPE_PROC_CHIP> l_fapi_cpu_target
            (l_cpu_target);

        FAPI_INVOKE_HWP(l_err, p10_mss_eff_grouping, l_fapi_cpu_target);

        //  process return code.
        if ( l_err )
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "ERROR in p10_mss_eff_grouping HWP on target %.8x. "
               TRACE_ERR_FMT,
               get_huid(l_cpu_target),
               TRACE_ERR_ARGS(l_err));

            // capture the target data in the elog
            ErrlUserDetailsTarget(l_cpu_target).addToLog(l_err);
            io_istepErr.addErrorDetails(l_err);
            errlCommit(l_err, ISTEP_COMP_ID);
        }
        else
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "SUCCESS :  p10_mss_eff_grouping HWP on target %.8x",
                get_huid(l_cpu_target));
        }
    }   // end processor list processing
}

/**
 * @brief Common function to distribute SMF Memory among procs
 *        This will just handle any errors internally, they should not
 *        affect the istep
 */
void distributeSmfMemory()
{
    errlHndl_t l_err = nullptr;

#ifndef CONFIG_FSP_BUILD
    uint64_t l_smfMemAmt = 0;
    const char* l_smfMemAmtStr = nullptr;

    l_err = NVRAM::nvramRead(NVRAM::SMF_MEM_AMT_KEY, l_smfMemAmtStr);
    if(l_err)
    {
        TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"NVRAM read failed. Will not attempt to distribute any SMF memory.");
        // Do not propagate the error - we don't care if NVRAM read fails
        delete l_err;
        l_err = nullptr;
    }
    else
    {
        // l_smfMemAmtStr will be nullptr if the SMF_MEM_AMT_KEY doesn't exist
        if(l_smfMemAmtStr)
        {
            l_smfMemAmt = strtoul(l_smfMemAmtStr, nullptr, 16);
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"Distributing 0x%.16llx SMF memory among the procs on the system", l_smfMemAmt);
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"SMF_MEM_AMT_KEY was not found in NVRAM; 0 SMF memory will be distributed.");
        }
    }

    UTIL::assertGetToplevelTarget()->setAttr<ATTR_SMF_MEM_AMT_REQUESTED>(l_smfMemAmt);
#endif

    // The default for ATTR_SMF_MEM_AMT_REQUESTED is 0. For FSP, that means that
    // the following call will disable SMF_CONFIG.
    l_err = SECUREBOOT::SMF::distributeSmfMem();
    if(l_err)
    {
        // Do not propagate or break on error - distributeSmfMem will
        // not return unrecoverable errors.
        errlCommit(l_err, ISTEP_COMP_ID);
    }
}

void* call_mss_eff_config (void *io_pArgs)
{
    IStepError l_StepError;
    errlHndl_t l_err = nullptr;

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config entry" );

    TARGETING::TargetHandleList l_membufTargetList;
    TARGETING::TargetHandleList l_mcsTargetList;
    TARGETING::TargetHandleList l_memportTargetList;
    std::vector<fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>> l_fapi_ocmb_targets;

    do {
        // Build up this list from memport parents, used in exp_mss_eff_config_thermal
        std::vector<fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>> l_fapi2_ocmb_targets;

        // Get all functional MEM_PORT chiplets
        TargetHandleList l_memportTargetList;
        getAllChiplets(l_memportTargetList, TYPE_MEM_PORT);

        for(const auto & l_memport_target: l_memportTargetList)
        {
            // Create a FAPI target representing the MEM_PORT target
            const fapi2::Target <fapi2::TARGET_TYPE_MEM_PORT> l_fapi_memport_target
                (l_memport_target);

            // Grab parent OCMB to add to list consumed later
            const auto l_fapi2_ocmb_target =
                l_fapi_memport_target.getParent<fapi2::TARGET_TYPE_OCMB_CHIP>();
            l_fapi2_ocmb_targets.push_back(l_fapi2_ocmb_target);

            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                      "call p10_mss_eff_config HWP on MEM_PORT HUID %.8X",
                      get_huid(l_memport_target));

            FAPI_INVOKE_HWP(l_err, p10_mss_eff_config, l_fapi_memport_target);

            if (l_err)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "ERROR in p10_mss_eff_config HWP on target 0x%.08X. "
                          TRACE_ERR_FMT,
                          get_huid(l_memport_target),
                          TRACE_ERR_ARGS(l_err));

                // Ensure istep error created and has same plid as this error
                ErrlUserDetailsTarget(l_memport_target).addToLog(l_err);
                l_err->collectTrace(EEPROM_COMP_NAME);
                l_err->collectTrace(I2C_COMP_NAME);
                l_StepError.addErrorDetails(l_err);
                errlCommit(l_err, ISTEP_COMP_ID);
            }
            else
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "SUCCESS :  p10_mss_eff_config HWP on target 0x%.08X",
                          get_huid(l_memport_target));
            }
        } // end mem_port list

        if(!l_StepError.isNull())
        {
            break;
        }

        if(l_fapi2_ocmb_targets.size() > 0)
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                      "call exp_mss_eff_config_thermal HWP on %d OCMB targets",
                      l_fapi2_ocmb_targets.size());

            FAPI_INVOKE_HWP(l_err, exp_mss_eff_config_thermal, l_fapi2_ocmb_targets);
            if (l_err)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "ERROR in exp_mss_eff_config_thermal HWP. "
                          TRACE_ERR_FMT, TRACE_ERR_ARGS(l_err));

                // Ensure istep error created and has same plid as this error
                l_err->collectTrace(EEPROM_COMP_NAME);
                l_err->collectTrace(I2C_COMP_NAME);
                l_StepError.addErrorDetails(l_err);
                errlCommit(l_err, ISTEP_COMP_ID);
            }
            else
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "SUCCESS :  exp_mss_eff_config_thermal HWP");
            }
        }
        else
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                      "No OCMB targets found, skipping exp_mss_eff_config_thermal HWP");
        }

        // Stack the memory on each chip
        call_mss_eff_grouping(l_StepError);
        if(!l_StepError.isNull())
        {
            break;
        }

        // Distribute the SMF Memory (if system appropriate)
        distributeSmfMemory();

        if(SECUREBOOT::SMF::isSmfEnabled())
        {
            // SMF is still enabled, which means that the requested amount of
            // SMF memory may have changed. Rerun the mss_eff_grouping HWP
            // to update the SMF BAR/SMF memory amounts.
            call_mss_eff_grouping(l_StepError);
            if(!l_StepError.isNull())
            {
                break;
            }
        }

    } while(0);

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config exit" );

    // end task, returning any error logs to IStepDisp
    return l_StepError.getErrorHandle();
}

};   // end namespace
<commit_msg>Do Not Read NVRAM in Non-SMF Mode<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep07/call_mss_eff_config.C $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file call_mss_eff_config.C
 *  Contains the wrapper for mss_eff_config istep
 */

/******************************************************************************/
// Includes
/******************************************************************************/

// STD
#include    <stdint.h>
#include    <stdlib.h>
#include    <map>

// Generated
#include    <attributeenums.H>
#include    <config.h>

// Errors and Tracing Support
#include    <trace/interface.H>
#include    <initservice/taskargs.H>
#include    <initservice/isteps_trace.H>
#include    <errl/errlentry.H>
#include    <errl/errludtarget.H>
#include    <isteps/hwpisteperror.H>
#include    <hbotcompid.H>

// Pnor Support
#include    <pnor/pnorif.H>

// Targeting Support
#include    <targeting/common/commontargeting.H>
#include    <targeting/common/utilFilter.H>
#include    <targeting/common/util.H>
#include    <targeting/targplatutil.H>

// Fapi Support
#include    <fapi2.H>
#include    <fapi2/plat_hwp_invoker.H>

// HWPs
#include    <p10_mss_eff_config.H>
#include    <exp_mss_eff_config_thermal.H>
#include    <p10_mss_eff_grouping.H>

// SMF Support
#include    <secureboot/smf.H>
#include    <secureboot/smf_utils.H>

#include    <nvram/nvram_interface.H>

// isSimicsRunning
#include    <util/misc.H>

namespace   ISTEP_07
{

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;

/**
 * @brief Call p10_mss_eff_grouping HWP on each proc target
 * @param io_istepErr - updated with any HWP errors
 */
void call_mss_eff_grouping(IStepError & io_istepErr)
{
    errlHndl_t l_err = nullptr;

    TargetHandleList l_procsList;
    getAllChips(l_procsList, TYPE_PROC);

    for (const auto & l_cpu_target : l_procsList)
    {
        //  print call to hwp and write HUID of the target(s)
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "p10_mss_eff_grouping HWP cpu target HUID %.8X",
            get_huid(l_cpu_target));

        // cast OUR type of target to a FAPI type of target.
        const fapi2::Target <fapi2::TARGET_TYPE_PROC_CHIP> l_fapi_cpu_target
            (l_cpu_target);

        FAPI_INVOKE_HWP(l_err, p10_mss_eff_grouping, l_fapi_cpu_target);

        //  process return code.
        if ( l_err )
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "ERROR in p10_mss_eff_grouping HWP on target %.8x. "
               TRACE_ERR_FMT,
               get_huid(l_cpu_target),
               TRACE_ERR_ARGS(l_err));

            // capture the target data in the elog
            ErrlUserDetailsTarget(l_cpu_target).addToLog(l_err);
            io_istepErr.addErrorDetails(l_err);
            errlCommit(l_err, ISTEP_COMP_ID);
        }
        else
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "SUCCESS :  p10_mss_eff_grouping HWP on target %.8x",
                get_huid(l_cpu_target));
        }
    }   // end processor list processing
}

/**
 * @brief Common function to distribute SMF Memory among procs
 *        This will just handle any errors internally, they should not
 *        affect the istep
 */
void distributeSmfMemory()
{
    errlHndl_t l_err = nullptr;

#ifndef CONFIG_FSP_BUILD
    uint64_t l_smfMemAmt = 0;
    const char* l_smfMemAmtStr = nullptr;

    l_err = NVRAM::nvramRead(NVRAM::SMF_MEM_AMT_KEY, l_smfMemAmtStr);
    if(l_err)
    {
        TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"NVRAM read failed. Will not attempt to distribute any SMF memory.");
        // Do not propagate the error - we don't care if NVRAM read fails
        delete l_err;
        l_err = nullptr;
    }
    else
    {
        // l_smfMemAmtStr will be nullptr if the SMF_MEM_AMT_KEY doesn't exist
        if(l_smfMemAmtStr)
        {
            l_smfMemAmt = strtoul(l_smfMemAmtStr, nullptr, 16);
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"Distributing 0x%.16llx SMF memory among the procs on the system", l_smfMemAmt);
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"SMF_MEM_AMT_KEY was not found in NVRAM; 0 SMF memory will be distributed.");
        }
    }

    UTIL::assertGetToplevelTarget()->setAttr<ATTR_SMF_MEM_AMT_REQUESTED>(l_smfMemAmt);
#endif

    // The default for ATTR_SMF_MEM_AMT_REQUESTED is 0. For FSP, that means that
    // the following call will disable SMF_CONFIG.
    l_err = SECUREBOOT::SMF::distributeSmfMem();
    if(l_err)
    {
        // Do not propagate or break on error - distributeSmfMem will
        // not return unrecoverable errors.
        errlCommit(l_err, ISTEP_COMP_ID);
    }
}

void* call_mss_eff_config (void *io_pArgs)
{
    IStepError l_StepError;
    errlHndl_t l_err = nullptr;

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config entry" );

    TARGETING::TargetHandleList l_membufTargetList;
    TARGETING::TargetHandleList l_mcsTargetList;
    TARGETING::TargetHandleList l_memportTargetList;
    std::vector<fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>> l_fapi_ocmb_targets;

    do {
        // Build up this list from memport parents, used in exp_mss_eff_config_thermal
        std::vector<fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>> l_fapi2_ocmb_targets;

        // Get all functional MEM_PORT chiplets
        TargetHandleList l_memportTargetList;
        getAllChiplets(l_memportTargetList, TYPE_MEM_PORT);

        for(const auto & l_memport_target: l_memportTargetList)
        {
            // Create a FAPI target representing the MEM_PORT target
            const fapi2::Target <fapi2::TARGET_TYPE_MEM_PORT> l_fapi_memport_target
                (l_memport_target);

            // Grab parent OCMB to add to list consumed later
            const auto l_fapi2_ocmb_target =
                l_fapi_memport_target.getParent<fapi2::TARGET_TYPE_OCMB_CHIP>();
            l_fapi2_ocmb_targets.push_back(l_fapi2_ocmb_target);

            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                      "call p10_mss_eff_config HWP on MEM_PORT HUID %.8X",
                      get_huid(l_memport_target));

            FAPI_INVOKE_HWP(l_err, p10_mss_eff_config, l_fapi_memport_target);

            if (l_err)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "ERROR in p10_mss_eff_config HWP on target 0x%.08X. "
                          TRACE_ERR_FMT,
                          get_huid(l_memport_target),
                          TRACE_ERR_ARGS(l_err));

                // Ensure istep error created and has same plid as this error
                ErrlUserDetailsTarget(l_memport_target).addToLog(l_err);
                l_err->collectTrace(EEPROM_COMP_NAME);
                l_err->collectTrace(I2C_COMP_NAME);
                l_StepError.addErrorDetails(l_err);
                errlCommit(l_err, ISTEP_COMP_ID);
            }
            else
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "SUCCESS :  p10_mss_eff_config HWP on target 0x%.08X",
                          get_huid(l_memport_target));
            }
        } // end mem_port list

        if(!l_StepError.isNull())
        {
            break;
        }

        if(l_fapi2_ocmb_targets.size() > 0)
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                      "call exp_mss_eff_config_thermal HWP on %d OCMB targets",
                      l_fapi2_ocmb_targets.size());

            FAPI_INVOKE_HWP(l_err, exp_mss_eff_config_thermal, l_fapi2_ocmb_targets);
            if (l_err)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "ERROR in exp_mss_eff_config_thermal HWP. "
                          TRACE_ERR_FMT, TRACE_ERR_ARGS(l_err));

                // Ensure istep error created and has same plid as this error
                l_err->collectTrace(EEPROM_COMP_NAME);
                l_err->collectTrace(I2C_COMP_NAME);
                l_StepError.addErrorDetails(l_err);
                errlCommit(l_err, ISTEP_COMP_ID);
            }
            else
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          "SUCCESS :  exp_mss_eff_config_thermal HWP");
            }
        }
        else
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                      "No OCMB targets found, skipping exp_mss_eff_config_thermal HWP");
        }

        // Stack the memory on each chip
        call_mss_eff_grouping(l_StepError);
        if(!l_StepError.isNull())
        {
            break;
        }

        if(SECUREBOOT::SMF::isSmfEnabled())
        {
            // Distribute the SMF Memory (if system appropriate)
            distributeSmfMemory();
        }

        // We need to check for SMF again, since distributeSmfMemory may have
        // disabled it.
        if(SECUREBOOT::SMF::isSmfEnabled())
        {
            // SMF is still enabled, which means that the requested amount of
            // SMF memory may have changed. Rerun the mss_eff_grouping HWP
            // to update the SMF BAR/SMF memory amounts.
            call_mss_eff_grouping(l_StepError);
            if(!l_StepError.isNull())
            {
                break;
            }
        }

    } while(0);

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config exit" );

    // end task, returning any error logs to IStepDisp
    return l_StepError.getErrorHandle();
}

};   // end namespace
<|endoftext|>


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

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2015
 * Unit tests for the gas estimator.
 */

#include <test/libsolidity/SolidityExecutionFramework.h>
#include <libevmasm/EVMSchedule.h>
#include <libevmasm/GasMeter.h>
#include <libevmasm/KnownState.h>
#include <libevmasm/PathGasMeter.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/interface/GasEstimator.h>
#include <libsolidity/interface/SourceReferenceFormatter.h>

using namespace std;
using namespace dev::eth;
using namespace dev::solidity;
using namespace dev::test;

namespace dev
{
namespace solidity
{
namespace test
{

class GasMeterTestFramework: public SolidityExecutionFramework
{
public:
	GasMeterTestFramework() { }
	void compile(string const& _sourceCode)
	{
		m_compiler.setSource("pragma solidity >= 0.0;" + _sourceCode);
		ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(), "Compiling contract failed");

		AssemblyItems const* items = m_compiler.runtimeAssemblyItems("");
		ASTNode const& sourceUnit = m_compiler.ast();
		BOOST_REQUIRE(items != nullptr);
		m_gasCosts = GasEstimator::breakToStatementLevel(
			GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
			{&sourceUnit}
		);
	}

	void testCreationTimeGas(string const& _sourceCode)
	{
		EVMSchedule schedule;

		compileAndRun(_sourceCode);
		auto state = make_shared<KnownState>();
		PathGasMeter meter(*m_compiler.assemblyItems());
		GasMeter::GasConsumption gas = meter.estimateMax(0, state);
		u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
		// costs for deployment
		gas += bytecodeSize * schedule.createDataGas;
		// costs for transaction
		gas += gasForTransaction(m_compiler.object().bytecode, true);

		BOOST_REQUIRE(!gas.isInfinite);
		BOOST_CHECK(gas.value == m_gasUsed);
	}

	/// Compares the gas computed by PathGasMeter for the given signature (but unknown arguments)
	/// against the actual gas usage computed by the VM on the given set of argument variants.
	void testRunTimeGas(string const& _sig, vector<bytes> _argumentVariants)
	{
		u256 gasUsed = 0;
		GasMeter::GasConsumption gas;
		FixedHash<4> hash(dev::keccak256(_sig));
		for (bytes const& arguments: _argumentVariants)
		{
			sendMessage(hash.asBytes() + arguments, false, 0);
			gasUsed = max(gasUsed, m_gasUsed);
			gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false));
		}

		gas += GasEstimator::functionalEstimation(
			*m_compiler.runtimeAssemblyItems(),
			_sig
		);
		BOOST_REQUIRE(!gas.isInfinite);
		BOOST_CHECK(gas.value == m_gasUsed);
	}

	static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
	{
		EVMSchedule schedule;
		GasMeter::GasConsumption gas = _isCreation ? schedule.txCreateGas : schedule.txGas;
		for (auto i: _data)
			gas += i != 0 ? schedule.txDataNonZeroGas : schedule.txDataZeroGas;
		return gas;
	}

protected:
	map<ASTNode const*, eth::GasMeter::GasConsumption> m_gasCosts;
};

BOOST_FIXTURE_TEST_SUITE(GasMeterTests, GasMeterTestFramework)

BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
{
	char const* sourceCode = R"(
		contract test {
			bytes x;
			function f(uint a) returns (uint b) {
				x.length = a;
				for (; a < 200; ++a) {
					x[a] = 9;
					b = a * a;
				}
				return f(a - 1);
			}
		}
	)";
	compile(sourceCode);
	for (auto first = m_gasCosts.cbegin(); first != m_gasCosts.cend(); ++first)
	{
		auto second = first;
		for (++second; second != m_gasCosts.cend(); ++second)
			if (first->first->location().intersects(second->first->location()))
			{
				BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
				auto scannerFromSource = [&](string const&) -> Scanner const& { return m_compiler.scanner(); };
				SourceReferenceFormatter::printSourceLocation(cout, &first->first->location(), scannerFromSource);
				SourceReferenceFormatter::printSourceLocation(cout, &second->first->location(), scannerFromSource);
			}
	}
}

BOOST_AUTO_TEST_CASE(simple_contract)
{
	// Tests a simple "deploy contract" code without constructor. The actual contract is not relevant.
	char const* sourceCode = R"(
		contract test {
			bytes32 public shaValue;
			function f(uint a) {
				shaValue = sha3(a);
			}
		}
	)";
	testCreationTimeGas(sourceCode);
}

BOOST_AUTO_TEST_CASE(store_sha3)
{
	char const* sourceCode = R"(
		contract test {
			bytes32 public shaValue;
			function test(uint a) {
				shaValue = sha3(a);
			}
		}
	)";
	testCreationTimeGas(sourceCode);
}

BOOST_AUTO_TEST_CASE(updating_store)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function test() {
				data = 1;
				data = 2;
				data2 = 0;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
}

BOOST_AUTO_TEST_CASE(branches)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function f(uint x) {
				if (x > 7)
					data2 = 1;
				else
					data = 1;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
}

BOOST_AUTO_TEST_CASE(function_calls)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function f(uint x) {
				if (x > 7)
					data2 = g(x**8) + 1;
				else
					data = 1;
			}
			function g(uint x) internal returns (uint) {
				return data2;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
}

BOOST_AUTO_TEST_CASE(multiple_external_functions)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function f(uint x) {
				if (x > 7)
					data2 = g(x**8) + 1;
				else
					data = 1;
			}
			function g(uint x) returns (uint) {
				return data2;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
	testRunTimeGas("g(uint256)", vector<bytes>{encodeArgs(2)});
}

BOOST_AUTO_TEST_CASE(exponent_size)
{
	char const* sourceCode = R"(
		contract A {
			function g(uint x) returns (uint) {
				return x ** 0x100;
			}
			function h(uint x) returns (uint) {
				return x ** 0x10000;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2)});
	testRunTimeGas("g(uint256)", vector<bytes>{encodeArgs(2)});
}

BOOST_AUTO_TEST_CASE(balance_gas)
{
	char const* sourceCode = R"(
		contract A {
			function lookup_balance(address a) returns (uint) {
				return a.balance;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(100)});
}

BOOST_AUTO_TEST_CASE(selfdestruct_gas)
{
	char const* sourceCode = R"(
		contract A {
			function f() {
				selfdestruct(0x30);
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f()", vector<bytes>{encodeArgs()});
}

BOOST_AUTO_TEST_CASE(extcodesize_gas)
{
	char const* sourceCode = R"(
		contract A {
			function f() returns (uint _s) {
				assembly {
					_s := extcodesize(0x30)
				}
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f()", vector<bytes>{encodeArgs()});
}

BOOST_AUTO_TEST_SUITE_END()

}
}
}
<commit_msg>test: fix invalid signatures<commit_after>/*
	This file is part of solidity.

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2015
 * Unit tests for the gas estimator.
 */

#include <test/libsolidity/SolidityExecutionFramework.h>
#include <libevmasm/EVMSchedule.h>
#include <libevmasm/GasMeter.h>
#include <libevmasm/KnownState.h>
#include <libevmasm/PathGasMeter.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/interface/GasEstimator.h>
#include <libsolidity/interface/SourceReferenceFormatter.h>

using namespace std;
using namespace dev::eth;
using namespace dev::solidity;
using namespace dev::test;

namespace dev
{
namespace solidity
{
namespace test
{

class GasMeterTestFramework: public SolidityExecutionFramework
{
public:
	GasMeterTestFramework() { }
	void compile(string const& _sourceCode)
	{
		m_compiler.setSource("pragma solidity >= 0.0;" + _sourceCode);
		ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(), "Compiling contract failed");

		AssemblyItems const* items = m_compiler.runtimeAssemblyItems("");
		ASTNode const& sourceUnit = m_compiler.ast();
		BOOST_REQUIRE(items != nullptr);
		m_gasCosts = GasEstimator::breakToStatementLevel(
			GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
			{&sourceUnit}
		);
	}

	void testCreationTimeGas(string const& _sourceCode)
	{
		EVMSchedule schedule;

		compileAndRun(_sourceCode);
		auto state = make_shared<KnownState>();
		PathGasMeter meter(*m_compiler.assemblyItems());
		GasMeter::GasConsumption gas = meter.estimateMax(0, state);
		u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
		// costs for deployment
		gas += bytecodeSize * schedule.createDataGas;
		// costs for transaction
		gas += gasForTransaction(m_compiler.object().bytecode, true);

		BOOST_REQUIRE(!gas.isInfinite);
		BOOST_CHECK(gas.value == m_gasUsed);
	}

	/// Compares the gas computed by PathGasMeter for the given signature (but unknown arguments)
	/// against the actual gas usage computed by the VM on the given set of argument variants.
	void testRunTimeGas(string const& _sig, vector<bytes> _argumentVariants)
	{
		u256 gasUsed = 0;
		GasMeter::GasConsumption gas;
		FixedHash<4> hash(dev::keccak256(_sig));
		for (bytes const& arguments: _argumentVariants)
		{
			sendMessage(hash.asBytes() + arguments, false, 0);
			gasUsed = max(gasUsed, m_gasUsed);
			gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false));
		}

		gas += GasEstimator::functionalEstimation(
			*m_compiler.runtimeAssemblyItems(),
			_sig
		);
		BOOST_REQUIRE(!gas.isInfinite);
		BOOST_CHECK(gas.value == m_gasUsed);
	}

	static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
	{
		EVMSchedule schedule;
		GasMeter::GasConsumption gas = _isCreation ? schedule.txCreateGas : schedule.txGas;
		for (auto i: _data)
			gas += i != 0 ? schedule.txDataNonZeroGas : schedule.txDataZeroGas;
		return gas;
	}

protected:
	map<ASTNode const*, eth::GasMeter::GasConsumption> m_gasCosts;
};

BOOST_FIXTURE_TEST_SUITE(GasMeterTests, GasMeterTestFramework)

BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
{
	char const* sourceCode = R"(
		contract test {
			bytes x;
			function f(uint a) returns (uint b) {
				x.length = a;
				for (; a < 200; ++a) {
					x[a] = 9;
					b = a * a;
				}
				return f(a - 1);
			}
		}
	)";
	compile(sourceCode);
	for (auto first = m_gasCosts.cbegin(); first != m_gasCosts.cend(); ++first)
	{
		auto second = first;
		for (++second; second != m_gasCosts.cend(); ++second)
			if (first->first->location().intersects(second->first->location()))
			{
				BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
				auto scannerFromSource = [&](string const&) -> Scanner const& { return m_compiler.scanner(); };
				SourceReferenceFormatter::printSourceLocation(cout, &first->first->location(), scannerFromSource);
				SourceReferenceFormatter::printSourceLocation(cout, &second->first->location(), scannerFromSource);
			}
	}
}

BOOST_AUTO_TEST_CASE(simple_contract)
{
	// Tests a simple "deploy contract" code without constructor. The actual contract is not relevant.
	char const* sourceCode = R"(
		contract test {
			bytes32 public shaValue;
			function f(uint a) {
				shaValue = sha3(a);
			}
		}
	)";
	testCreationTimeGas(sourceCode);
}

BOOST_AUTO_TEST_CASE(store_sha3)
{
	char const* sourceCode = R"(
		contract test {
			bytes32 public shaValue;
			function test(uint a) {
				shaValue = sha3(a);
			}
		}
	)";
	testCreationTimeGas(sourceCode);
}

BOOST_AUTO_TEST_CASE(updating_store)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function test() {
				data = 1;
				data = 2;
				data2 = 0;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
}

BOOST_AUTO_TEST_CASE(branches)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function f(uint x) {
				if (x > 7)
					data2 = 1;
				else
					data = 1;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
}

BOOST_AUTO_TEST_CASE(function_calls)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function f(uint x) {
				if (x > 7)
					data2 = g(x**8) + 1;
				else
					data = 1;
			}
			function g(uint x) internal returns (uint) {
				return data2;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
}

BOOST_AUTO_TEST_CASE(multiple_external_functions)
{
	char const* sourceCode = R"(
		contract test {
			uint data;
			uint data2;
			function f(uint x) {
				if (x > 7)
					data2 = g(x**8) + 1;
				else
					data = 1;
			}
			function g(uint x) returns (uint) {
				return data2;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f(uint256)", vector<bytes>{encodeArgs(2), encodeArgs(8)});
	testRunTimeGas("g(uint256)", vector<bytes>{encodeArgs(2)});
}

BOOST_AUTO_TEST_CASE(exponent_size)
{
	char const* sourceCode = R"(
		contract A {
			function g(uint x) returns (uint) {
				return x ** 0x100;
			}
			function h(uint x) returns (uint) {
				return x ** 0x10000;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("g(uint256)", vector<bytes>{encodeArgs(2)});
	testRunTimeGas("h(uint256)", vector<bytes>{encodeArgs(2)});
}

BOOST_AUTO_TEST_CASE(balance_gas)
{
	char const* sourceCode = R"(
		contract A {
			function lookup_balance(address a) returns (uint) {
				return a.balance;
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("lookup_balance(address)", vector<bytes>{encodeArgs(2), encodeArgs(100)});
}

BOOST_AUTO_TEST_CASE(selfdestruct_gas)
{
	char const* sourceCode = R"(
		contract A {
			function f() {
				selfdestruct(0x30);
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f()", vector<bytes>{encodeArgs()});
}

BOOST_AUTO_TEST_CASE(extcodesize_gas)
{
	char const* sourceCode = R"(
		contract A {
			function f() returns (uint _s) {
				assembly {
					_s := extcodesize(0x30)
				}
			}
		}
	)";
	testCreationTimeGas(sourceCode);
	testRunTimeGas("f()", vector<bytes>{encodeArgs()});
}

BOOST_AUTO_TEST_SUITE_END()

}
}
}
<|endoftext|>


<commit_before>#include <thread>
#include <chrono>
#include <string>
#include <map>
#include <utility>
#include <cstdint>
#include <uv.h>

#include "polling_thread.h"
#include "polled_root.h"
#include "../thread.h"
#include "../status.h"
#include "../result.h"
#include "../message_buffer.h"
#include "../log.h"

using std::string;
using std::endl;

PollingThread::PollingThread(uv_async_t *main_callback) :
  Thread("polling thread", main_callback),
  poll_interval{DEFAULT_POLL_INTERVAL},
  poll_throttle{DEFAULT_POLL_THROTTLE}
{
  //
}

PollingThread::~PollingThread()
{
  //
}

void PollingThread::collect_status(Status &status)
{
  status.polling_thread_state = state_name();
  status.polling_thread_ok = get_error();
  status.polling_in_size = get_in_queue_size();
  status.polling_in_ok = get_in_queue_error();
  status.polling_out_size = get_out_queue_size();
  status.polling_out_ok = get_out_queue_error();
}

Result<> PollingThread::body()
{
  while (true) {
    LOGGER << "Handling commands." << endl;
    Result<size_t> cr = handle_commands();
    if (cr.is_error()) {
      LOGGER << "Unable to process incoming commands: " << cr << endl;
    } else if (is_stopping()) {
      LOGGER << "Polling thread stopping." << endl;
      return ok_result();
    }

    LOGGER << "Polling root directories." << endl;
    cycle();

    if (is_healthy()) {
      LOGGER << "Sleeping for " << poll_interval.count() << "ms." << endl;
      std::this_thread::sleep_for(poll_interval);
      LOGGER << "Waking up." << endl;
    }
  }
}

Result<> PollingThread::cycle()
{
  MessageBuffer buffer;
  size_t remaining = poll_throttle;

  auto it = roots.begin();
  size_t roots_left = roots.size();
  LOGGER << "Polling " << plural(roots_left, "root")
    << " with " << plural(poll_throttle, "throttle slot")
    << "." << endl;

  while (it != roots.end()) {
    PolledRoot &root = it->second;
    size_t allotment = remaining / roots_left;

    LOGGER << "Polling " << root
      << " with an allotment of " << plural(allotment, "throttle slot") << "." << endl;

    size_t progress = root.advance(buffer, allotment);
    remaining -= progress;
    LOGGER << root << " consumed " << plural(progress, "throttle slot") << "." << endl;

    roots_left--;
    ++it;
  }

  return emit_all(buffer.begin(), buffer.end());
}

Result<Thread::OfflineCommandOutcome> PollingThread::handle_offline_command(const CommandPayload *payload)
{
  Result<OfflineCommandOutcome> r = Thread::handle_offline_command(payload);
  if (r.is_error()) return r;

  if (payload->get_action() == COMMAND_ADD) {
    return ok_result(TRIGGER_RUN);
  }

  return ok_result(OFFLINE_ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_add_command(const CommandPayload *payload)
{
  LOGGER << "Adding poll root at path "
    << payload->get_root()
    << " to channel " << payload->get_channel_id()
    << "." << endl;

  roots.emplace(
    std::piecewise_construct,
    std::forward_as_tuple(payload->get_channel_id()),
    std::forward_as_tuple(string(payload->get_root()), payload->get_channel_id())
  );

  return ok_result(ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_remove_command(const CommandPayload *payload)
{
  LOGGER << "Removing poll root at channel "
    << payload->get_channel_id()
    << "." << endl;

  auto it = roots.find(payload->get_channel_id());
  if (it != roots.end()) roots.erase(it);

  if (roots.empty()) {
    LOGGER << "Final root removed." << endl;
    return ok_result(TRIGGER_STOP);
  }

  return ok_result(ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_polling_interval_command(const CommandPayload *payload)
{
  poll_interval = std::chrono::milliseconds(payload->get_arg());
  return ok_result(ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_polling_throttle_command(const CommandPayload *payload)
{
  poll_throttle = payload->get_arg();
  return ok_result(ACK);
}
<commit_msg>Configure polling thread options offline<commit_after>#include <thread>
#include <chrono>
#include <string>
#include <map>
#include <utility>
#include <cstdint>
#include <uv.h>

#include "polling_thread.h"
#include "polled_root.h"
#include "../thread.h"
#include "../status.h"
#include "../result.h"
#include "../message_buffer.h"
#include "../log.h"

using std::string;
using std::endl;

PollingThread::PollingThread(uv_async_t *main_callback) :
  Thread("polling thread", main_callback),
  poll_interval{DEFAULT_POLL_INTERVAL},
  poll_throttle{DEFAULT_POLL_THROTTLE}
{
  //
}

PollingThread::~PollingThread()
{
  //
}

void PollingThread::collect_status(Status &status)
{
  status.polling_thread_state = state_name();
  status.polling_thread_ok = get_error();
  status.polling_in_size = get_in_queue_size();
  status.polling_in_ok = get_in_queue_error();
  status.polling_out_size = get_out_queue_size();
  status.polling_out_ok = get_out_queue_error();
}

Result<> PollingThread::body()
{
  while (true) {
    LOGGER << "Handling commands." << endl;
    Result<size_t> cr = handle_commands();
    if (cr.is_error()) {
      LOGGER << "Unable to process incoming commands: " << cr << endl;
    } else if (is_stopping()) {
      LOGGER << "Polling thread stopping." << endl;
      return ok_result();
    }

    LOGGER << "Polling root directories." << endl;
    cycle();

    if (is_healthy()) {
      LOGGER << "Sleeping for " << poll_interval.count() << "ms." << endl;
      std::this_thread::sleep_for(poll_interval);
      LOGGER << "Waking up." << endl;
    }
  }
}

Result<> PollingThread::cycle()
{
  MessageBuffer buffer;
  size_t remaining = poll_throttle;

  auto it = roots.begin();
  size_t roots_left = roots.size();
  LOGGER << "Polling " << plural(roots_left, "root")
    << " with " << plural(poll_throttle, "throttle slot")
    << "." << endl;

  while (it != roots.end()) {
    PolledRoot &root = it->second;
    size_t allotment = remaining / roots_left;

    LOGGER << "Polling " << root
      << " with an allotment of " << plural(allotment, "throttle slot") << "." << endl;

    size_t progress = root.advance(buffer, allotment);
    remaining -= progress;
    LOGGER << root << " consumed " << plural(progress, "throttle slot") << "." << endl;

    roots_left--;
    ++it;
  }

  return emit_all(buffer.begin(), buffer.end());
}

Result<Thread::OfflineCommandOutcome> PollingThread::handle_offline_command(const CommandPayload *payload)
{
  Result<OfflineCommandOutcome> r = Thread::handle_offline_command(payload);
  if (r.is_error()) return r;

  if (payload->get_action() == COMMAND_ADD) {
    return ok_result(TRIGGER_RUN);
  }

  if (payload->get_action() == COMMAND_POLLING_INTERVAL) {
    handle_polling_interval_command(payload);
  }

  if (payload->get_action() == COMMAND_POLLING_THROTTLE) {
    handle_polling_throttle_command(payload);
  }

  return ok_result(OFFLINE_ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_add_command(const CommandPayload *payload)
{
  LOGGER << "Adding poll root at path "
    << payload->get_root()
    << " to channel " << payload->get_channel_id()
    << "." << endl;

  roots.emplace(
    std::piecewise_construct,
    std::forward_as_tuple(payload->get_channel_id()),
    std::forward_as_tuple(string(payload->get_root()), payload->get_channel_id())
  );

  return ok_result(ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_remove_command(const CommandPayload *payload)
{
  LOGGER << "Removing poll root at channel "
    << payload->get_channel_id()
    << "." << endl;

  auto it = roots.find(payload->get_channel_id());
  if (it != roots.end()) roots.erase(it);

  if (roots.empty()) {
    LOGGER << "Final root removed." << endl;
    return ok_result(TRIGGER_STOP);
  }

  return ok_result(ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_polling_interval_command(const CommandPayload *payload)
{
  poll_interval = std::chrono::milliseconds(payload->get_arg());
  return ok_result(ACK);
}

Result<Thread::CommandOutcome> PollingThread::handle_polling_throttle_command(const CommandPayload *payload)
{
  poll_throttle = payload->get_arg();
  return ok_result(ACK);
}
<|endoftext|>


<commit_before><commit_msg>workaround for LO namespace pollution breaking KDE4 fpicker build<commit_after><|endoftext|>


<commit_before>#include "SparseMatrixData.h"

using namespace smurff;

SparseMatrixData::SparseMatrixData(Eigen::SparseMatrix<double> Y)
   : FullMatrixData<Eigen::SparseMatrix<double>>(Y)
{
   this->name = "SparseMatrixData [fully known]";
}

double SparseMatrixData::train_rmse(const SubModel& model) const
{
   double se = 0.;
   #pragma omp parallel for schedule(guided) reduction(+:se)
   for(int c = 0; c < Y().cols(); ++c)
   {
      int r = 0;
      for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
      {
         for(; r < it.row(); r++) //handle implicit zeroes
            se += square(model.predict({r, c}));

         se += square(it.value() - model.predict({r, c}));
      }

      for(; r < Y().rows(); r++) //handle implicit zeroes
         se += square(model.predict({r, c}));
   }
   return sqrt(se / Y().rows() / Y().cols());
}

double SparseMatrixData::var_total() const
{
   double cwise_mean = this->sum() / (this->size() - this->nna());
   double se = 0.0;

   #pragma omp parallel for schedule(dynamic, 4) reduction(+:se)
   for(int c = 0; c < Y().cols(); ++c)
   {
      int r = 0;
      for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
      {
         for(; r < it.row(); r++) //handle implicit zeroes
            se += square(cwise_mean);

         se += square(it.value() - cwise_mean);
      }

      for(; r < Y().rows(); r++) //handle implicit zeroes
         se += square(cwise_mean);
   }

   double var = se / Y().nonZeros();
   if (var <= 0.0 || std::isnan(var))
   {
      // if var cannot be computed using 1.0
      var = 1.0;
   }

   return var;
}

double SparseMatrixData::sumsq(const SubModel& model) const
{
   double sumsq = 0.0;

   #pragma omp parallel for schedule(dynamic, 4) reduction(+:sumsq)
   for(int c = 0; c < Y().cols(); ++c)
   {
      int r = 0;
      for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
      {
         for(; r < it.row(); r++) //handle implicit zeroes
            sumsq += square(model.predict({r, c}));

         sumsq += square(model.predict({r, c}) - it.value());
      }

      for(; r < Y().rows(); r++) //handle implicit zeroes
         sumsq += square(model.predict({r, c}));
   }

   return sumsq;
}<commit_msg>issue #57. fix bug in iterating through implicit zeroes in SparseMatrixData class.<commit_after>#include "SparseMatrixData.h"

using namespace smurff;

SparseMatrixData::SparseMatrixData(Eigen::SparseMatrix<double> Y)
   : FullMatrixData<Eigen::SparseMatrix<double>>(Y)
{
   this->name = "SparseMatrixData [fully known]";
}

double SparseMatrixData::train_rmse(const SubModel& model) const
{
   double se = 0.;
   #pragma omp parallel for schedule(guided) reduction(+:se)
   for(int c = 0; c < Y().cols(); ++c)
   {
      int r = 0;
      for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
      {
         for(; r < it.row(); r++) //handle implicit zeroes
            se += square(model.predict({r, c}));

         se += square(it.value() - model.predict({r, c}));
         r++;
      }

      for(; r < Y().rows(); r++) //handle implicit zeroes
         se += square(model.predict({r, c}));
   }
   return sqrt(se / Y().rows() / Y().cols());
}

double SparseMatrixData::var_total() const
{
   double cwise_mean = this->sum() / (this->size() - this->nna());
   double se = 0.0;

   #pragma omp parallel for schedule(dynamic, 4) reduction(+:se)
   for(int c = 0; c < Y().cols(); ++c)
   {
      int r = 0;
      for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
      {
         for(; r < it.row(); r++) //handle implicit zeroes
            se += square(cwise_mean);

         se += square(it.value() - cwise_mean);
         r++;
      }

      for(; r < Y().rows(); r++) //handle implicit zeroes
         se += square(cwise_mean);
   }

   double var = se / Y().nonZeros();
   if (var <= 0.0 || std::isnan(var))
   {
      // if var cannot be computed using 1.0
      var = 1.0;
   }

   return var;
}

double SparseMatrixData::sumsq(const SubModel& model) const
{
   double sumsq = 0.0;

   #pragma omp parallel for schedule(dynamic, 4) reduction(+:sumsq)
   for(int c = 0; c < Y().cols(); ++c)
   {
      int r = 0;
      for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
      {
         for(; r < it.row(); r++) //handle implicit zeroes
            sumsq += square(model.predict({r, c}));

         sumsq += square(model.predict({r, c}) - it.value());
         r++;
      }

      for(; r < Y().rows(); r++) //handle implicit zeroes
         sumsq += square(model.predict({r, c}));
   }

   return sumsq;
}<|endoftext|>