<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2022 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/editor/workspacegridview.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/common/inviwomodule.h>
#include <inviwo/core/network/workspaceannotations.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/stdextensions.h>
#include <modules/qtwidgets/inviwoqtutils.h>

#include <inviwo/qt/editor/workspacemodelroles.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QStyledItemDelegate>
#include <QPainter>
#include <QStyle>
#include <QApplication>
#include <QSortFilterProxyModel>
#include <QHeaderView>
#include <QPainterPath>
#include <QIdentityProxyModel>
#include <QHash>
#include <QResizeEvent>
#include <QPersistentModelIndex>
#include <QScrollBar>
#include <warn/pop>

namespace inviwo {

using Role = WorkspaceModelRole;
using Type = WorkspaceModelType;

namespace {

class SectionDelegate : public QStyledItemDelegate {
public:
    SectionDelegate(int itemSize, QWidget* parent = nullptr);
    virtual ~SectionDelegate() override = default;

    virtual void paint(QPainter* painter, const QStyleOptionViewItem& option,
                       const QModelIndex& index) const override;
    QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;

private:
    QImage rightArrow;
    QImage downArrow;
    int itemSize_;
};

SectionDelegate::SectionDelegate(int itemSize, QWidget* parent)
    : QStyledItemDelegate(parent)
    , rightArrow{":/svgicons/arrow-right-enabled.svg"}
    , downArrow{":/svgicons/arrow-down-enabled.svg"}
    , itemSize_(itemSize) {}

void SectionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o,
                            const QModelIndex& index) const {

    auto option = o;
    initStyleOption(&option, index);
    painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing |
                            QPainter::SmoothPixmapTransform);

    painter->save();
    if (utilqt::getData(index, Role::Type) == Type::File) {

        option.text = "";
        QStyle* style = option.widget ? option.widget->style() : QApplication::style();
        style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);

        const auto name = utilqt::getData(index, Qt::DisplayRole).toString();
        const auto path = utilqt::getData(index, Role::Path).toString();
        const auto image = utilqt::getData(index, Role::PrimaryImage).value<QImage>();

        const auto margin = utilqt::emToPx(option.fontMetrics, 0.5);

        const auto baseRect = option.rect.adjusted(margin, margin, -margin, -margin);

        const auto txtHeight = baseRect.height() / 4;
        const auto imgCenter = baseRect.adjusted(0, 0, 0, -txtHeight - margin).center();
        const auto w = std::min(baseRect.width(), baseRect.height() - txtHeight - margin) / 2;
        const auto imgRect = QRect{imgCenter, QSize{0, 0}}.adjusted(-w, -w, w, w);

        QPainterPath border;
        border.addRoundedRect(imgRect, 35, 35, Qt::RelativeSize);

        const auto is = std::min(image.rect().width(), image.rect().height()) / 2;
        const auto sourceRect =
            QRect{image.rect().center(), QSize{0, 0}}.adjusted(-is, -is, is, is);
        painter->setClipPath(border, Qt::ReplaceClip);
        painter->drawImage(imgRect, image, sourceRect);
        painter->setClipPath(border, Qt::NoClip);

        painter->setPen(QPen{option.palette.text().color(), 1.5});
        painter->drawPath(border);

        const auto nameRect = baseRect.adjusted(0, baseRect.height() - txtHeight, 0, 0);
        painter->setPen(option.palette.text().color().lighter());
        painter->drawText(nameRect, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWrapAnywhere, name);

    } else if (index.column() == 0) {
        // enlarge and emphasize font of section headers
        option.font.setBold(true);
        option.font.setPointSizeF(option.font.pointSizeF() * 1.2);

        option.text = "";
        QStyle* style = option.widget ? option.widget->style() : QApplication::style();
        style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);

        painter->setClipping(false);

        const auto name = utilqt::getData(index, Qt::DisplayRole).toString();

        const auto& img = option.state & QStyle::State_Open ? downArrow : rightArrow;

        const auto indent = style->pixelMetric(QStyle::PM_TreeViewIndentation, 0, option.widget);

        const auto level = [&]() {
            auto i = index.parent();
            int l = 0;
            while (i.isValid()) {
                i = i.parent();
                ++l;
            }
            return l;
        }();

        auto rect = option.rect;
        const auto imgRect = QRect{
            QPoint{level * indent, rect.center().y() - img.rect().center().y()}, img.rect().size()};
        painter->drawImage(imgRect, img, img.rect());

        auto nameRect = option.rect;
        nameRect.adjust(level * indent + rect.height(), 0, 0, 0);

        painter->setFont(option.font);
        painter->drawText(nameRect,
                          Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip | Qt::TextSingleLine,
                          name);
    }
    painter->restore();
}

QSize SectionDelegate::sizeHint(const QStyleOptionViewItem& o, const QModelIndex& index) const {
    if (!index.isValid()) return QSize();

    auto size = QStyledItemDelegate::sizeHint(o, index);
    if (utilqt::getData(index, Role::Type) == Type::File) {
        size.setHeight(itemSize_);
    }
    return size;
}

}  // namespace

class ChunkProxyModel : public QAbstractProxyModel {
public:
    ChunkProxyModel(QAbstractItemModel* model, int chunkSize, QObject* parent)
        : QAbstractProxyModel(parent), chunkSize_{chunkSize} {

        setSourceModel(model);
        auto reset = [this]() {
            beginResetModel();
            sourceIndexMapping_.clear();
            endResetModel();
        };
        connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, reset);
        connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, reset);
        connect(model, &QAbstractItemModel::rowsAboutToBeMoved, this, reset);
        connect(model, &QAbstractItemModel::columnsAboutToBeInserted, this, reset);
        connect(model, &QAbstractItemModel::columnsAboutToBeRemoved, this, reset);
        connect(model, &QAbstractItemModel::columnsAboutToBeMoved, this, reset);
        connect(model, &QAbstractItemModel::modelAboutToBeReset, this, reset);
        connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, reset);

        connect(
            model, &QAbstractItemModel::dataChanged, this,
            [this](const QModelIndex& topLeft, const QModelIndex& bottomRight, const auto& roles) {
                for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
                    auto changed = mapFromSource(sourceModel()->index(i, 0, topLeft.parent()));
                    dataChanged(changed, changed, roles);
                }
            });
    }

    virtual int columnCount(
        [[maybe_unused]] const QModelIndex& parent = QModelIndex()) const override {
        return chunkSize_;
    }
    virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override {
        auto sourceParent = mapToSource(parent);
        auto sourceRows = sourceModel()->rowCount(sourceParent);

        if (utilqt::getData(sourceParent, Role::Type) == Type::SubSection) {
            auto chunkedRows = (sourceRows + chunkSize_ - 1) / chunkSize_;
            return chunkedRows;
        } else {
            return sourceRows;
        }
    }

    QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override {
        if (!sourceIndex.isValid()) return {};

        auto map = mapping(sourceIndex);
        if (utilqt::getData(sourceIndex, Role::Type) == Type::File) {
            const auto row = sourceIndex.row() / chunkSize_;
            const auto col = sourceIndex.row() % chunkSize_;
            return createIndex(row, col, map);
        } else {
            return createIndex(sourceIndex.row(), sourceIndex.column(), map);
        }
    }

    QModelIndex mapToSource(const QModelIndex& proxyIndex) const override {
        if (!proxyIndex.isValid()) return {};

        auto m = static_cast<const Mapping*>(proxyIndex.internalPointer());
        return sourceModel()->index(m->sourceRow, m->sourceCol, m->sourceParent);
    }

    QModelIndex parent(const QModelIndex& child) const override {
        const QModelIndex sourceIndex = mapToSource(child);
        const QModelIndex sourceParent = sourceIndex.parent();
        return mapFromSource(sourceParent);
    }

    QModelIndex index(int row, int column, const QModelIndex& parent) const override {
        const QModelIndex sourceParent = mapToSource(parent);

        if (utilqt::getData(sourceParent, Role::Type) == Type::SubSection) {
            const int sourceRow = row * chunkSize_ + column;
            return mapFromSource(sourceModel()->index(sourceRow, 0, sourceParent));
        } else {
            return mapFromSource(sourceModel()->index(row, column, sourceParent));
        }
    }

    QModelIndex sibling(int row, int column, const QModelIndex& idx) const override {
        if (!idx.isValid()) return {};
        return index(row, column, idx.parent());
    }

    void setChunkSize(int chunkSize) {
        if (chunkSize_ == chunkSize) return;

        beginResetModel();
        chunkSize_ = chunkSize;
        sourceIndexMapping_.clear();
        endResetModel();
    }

    int chunkSize() const { return chunkSize_; }

private:
    struct Hash {
        size_t operator()(const QModelIndex& idx, size_t seed = std::hash<int>{}(0)) const {
            return qHash(idx, seed);
        }
    };
    struct Mapping {
        int sourceRow;
        int sourceCol;
        QPersistentModelIndex sourceParent;
    };
    using IndexMap = std::unordered_map<QModelIndex, Mapping, Hash>;

    Mapping* mapping(const QModelIndex& sourceIndex) const {
        auto [it, inserted] = sourceIndexMapping_.try_emplace(sourceIndex);
        if (inserted) {
            it->second.sourceRow = sourceIndex.row();
            it->second.sourceCol = sourceIndex.column();
            it->second.sourceParent = sourceIndex.parent();
        }
        return &(it->second);
    }
    mutable IndexMap sourceIndexMapping_;
    int chunkSize_;
};

WorkspaceGridView::WorkspaceGridView(QAbstractItemModel* theModel, QWidget* parent)
    : QTreeView{parent}
    , itemSize_{utilqt::emToPx(this, 14)}
    , proxy_{new ChunkProxyModel{theModel, 3, this}} {

    setModel(proxy_);

    setHeaderHidden(true);
    setSelectionBehavior(QAbstractItemView::SelectItems);
    setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
    setItemDelegate(new SectionDelegate(itemSize_, this));
    setIndentation(0);

#if defined(WIN32)
    // Scrolling on Windows is set to scroll per item by default. Also need to adjust the step size
    // since the default appears to be based on the number of items in the view.
    setVerticalScrollMode(ScrollPerPixel);
    verticalScrollBar()->setSingleStep(utilqt::emToPx(parent, 1.5));
#endif

    connect(this, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) {
        if (index.isValid() && (utilqt::getData(index, Role::Type) == Type::File)) {
            const auto filename = utilqt::getData(index, Role::FilePath).toString();
            const auto isExample = utilqt::getData(index, Role::isExample).toBool();
            emit loadFile(filename, isExample);
        }
    });

    connect(this, &QTreeView::clicked, this, [this](const QModelIndex& index) {
        if (index.isValid() && (utilqt::getData(index, Role::Type) != Type::File)) {

            if (QGuiApplication::keyboardModifiers() & Qt::ControlModifier) {
                isExpanded(index) ? collapseRecursively(index) : expandRecursively(index);
            } else {
                setExpanded(index, !isExpanded(index));
            }
        }
    });

    connect(selectionModel(), &QItemSelectionModel::currentChanged, this,
            [this](const QModelIndex& current, const QModelIndex&) {
                if (current.isValid() && (utilqt::getData(current, Role::Type) == Type::File)) {
                    emit selectFile(current);
                } else {
                    emit selectFile(QModelIndex{});
                }
            });

    header()->setSectionResizeMode(QHeaderView::Stretch);
}

const QAbstractProxyModel& WorkspaceGridView::proxy() const { return *proxy_; }

void WorkspaceGridView::resizeEvent(QResizeEvent* event) {
    QTreeView::resizeEvent(event);

    const int newChunkSize = event->size().width() / itemSize_;

    if (newChunkSize != proxy_->chunkSize()) {
        std::vector<QModelIndex> expanded;
        auto findExpaned = [&](auto& self, const QModelIndex& parent) -> void {
            auto rows = proxy_->rowCount(parent);
            for (int i = 0; i < rows; ++i) {
                auto index = proxy_->index(i, 0, parent);
                if (isExpanded(index)) {
                    expanded.push_back(proxy_->mapToSource(index));
                    self(self, index);
                }
            }
        };
        findExpaned(findExpaned, QModelIndex{});
        proxy_->setChunkSize(event->size().width() / itemSize_);
        for (const auto& idx : expanded) {
            expand(proxy_->mapFromSource(idx));
        }
    }
}

#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
// QTreeView::expandRecursively() was introduced in Qt 5.13
// see https://doc.qt.io/qt-5/qtreeview.html#expandRecursively
void WorkspaceGridView::expandRecursively(const QModelIndex& index) {
    if (index.isValid()) {
        for (int i = 0; i < index.model()->rowCount(index); ++i) {
            expandRecursively(index.child(i, 0));
        }
        if (!isExpanded(index)) {
            expand(index);
        }
    }
}
#endif

void WorkspaceGridView::collapseRecursively(const QModelIndex& index) {
    if (index.isValid()) {
        for (int i = 0; i < model()->rowCount(index); ++i) {
            collapseRecursively(model()->index(i, 0, index));
        }
        if (isExpanded(index)) {
            collapse(index);
        }
    }
}

}  // namespace inviwo
<commit_msg>Qt: clang fix, #1284<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2022 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/qt/editor/workspacegridview.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/common/inviwomodule.h>
#include <inviwo/core/network/workspaceannotations.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/stdextensions.h>
#include <modules/qtwidgets/inviwoqtutils.h>

#include <inviwo/qt/editor/workspacemodelroles.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QStyledItemDelegate>
#include <QPainter>
#include <QStyle>
#include <QApplication>
#include <QSortFilterProxyModel>
#include <QHeaderView>
#include <QPainterPath>
#include <QIdentityProxyModel>
#include <QHash>
#include <QResizeEvent>
#include <QPersistentModelIndex>
#include <QScrollBar>
#include <warn/pop>

namespace inviwo {

using Role = WorkspaceModelRole;
using Type = WorkspaceModelType;

namespace {

class SectionDelegate : public QStyledItemDelegate {
public:
    SectionDelegate(int itemSize, QWidget* parent = nullptr);
    virtual ~SectionDelegate() override = default;

    virtual void paint(QPainter* painter, const QStyleOptionViewItem& option,
                       const QModelIndex& index) const override;
    QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;

private:
    QImage rightArrow;
    QImage downArrow;
    int itemSize_;
};

SectionDelegate::SectionDelegate(int itemSize, QWidget* parent)
    : QStyledItemDelegate(parent)
    , rightArrow{":/svgicons/arrow-right-enabled.svg"}
    , downArrow{":/svgicons/arrow-down-enabled.svg"}
    , itemSize_(itemSize) {}

void SectionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o,
                            const QModelIndex& index) const {

    auto option = o;
    initStyleOption(&option, index);
    painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing |
                            QPainter::SmoothPixmapTransform);

    painter->save();
    if (utilqt::getData(index, Role::Type) == Type::File) {

        option.text = "";
        QStyle* style = option.widget ? option.widget->style() : QApplication::style();
        style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);

        const auto name = utilqt::getData(index, Qt::DisplayRole).toString();
        const auto path = utilqt::getData(index, Role::Path).toString();
        const auto image = utilqt::getData(index, Role::PrimaryImage).value<QImage>();

        const auto margin = utilqt::emToPx(option.fontMetrics, 0.5);

        const auto baseRect = option.rect.adjusted(margin, margin, -margin, -margin);

        const auto txtHeight = baseRect.height() / 4;
        const auto imgCenter = baseRect.adjusted(0, 0, 0, -txtHeight - margin).center();
        const auto w = std::min(baseRect.width(), baseRect.height() - txtHeight - margin) / 2;
        const auto imgRect = QRect{imgCenter, QSize{0, 0}}.adjusted(-w, -w, w, w);

        QPainterPath border;
        border.addRoundedRect(imgRect, 35, 35, Qt::RelativeSize);

        const auto is = std::min(image.rect().width(), image.rect().height()) / 2;
        const auto sourceRect =
            QRect{image.rect().center(), QSize{0, 0}}.adjusted(-is, -is, is, is);
        painter->setClipPath(border, Qt::ReplaceClip);
        painter->drawImage(imgRect, image, sourceRect);
        painter->setClipPath(border, Qt::NoClip);

        painter->setPen(QPen{option.palette.text().color(), 1.5});
        painter->drawPath(border);

        const auto nameRect = baseRect.adjusted(0, baseRect.height() - txtHeight, 0, 0);
        painter->setPen(option.palette.text().color().lighter());
        painter->drawText(nameRect, Qt::AlignHCenter | Qt::AlignTop | Qt::TextWrapAnywhere, name);

    } else if (index.column() == 0) {
        // enlarge and emphasize font of section headers
        option.font.setBold(true);
        option.font.setPointSizeF(option.font.pointSizeF() * 1.2);

        option.text = "";
        QStyle* style = option.widget ? option.widget->style() : QApplication::style();
        style->drawControl(QStyle::CE_ItemViewItem, &option, painter, option.widget);

        painter->setClipping(false);

        const auto name = utilqt::getData(index, Qt::DisplayRole).toString();

        const auto& img = option.state & QStyle::State_Open ? downArrow : rightArrow;

        const auto indent = style->pixelMetric(QStyle::PM_TreeViewIndentation, 0, option.widget);

        const auto level = [&]() {
            auto i = index.parent();
            int l = 0;
            while (i.isValid()) {
                i = i.parent();
                ++l;
            }
            return l;
        }();

        auto rect = option.rect;
        const auto imgRect = QRect{
            QPoint{level * indent, rect.center().y() - img.rect().center().y()}, img.rect().size()};
        painter->drawImage(imgRect, img, img.rect());

        auto nameRect = option.rect;
        nameRect.adjust(level * indent + rect.height(), 0, 0, 0);

        painter->setFont(option.font);
        painter->drawText(nameRect,
                          Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip | Qt::TextSingleLine,
                          name);
    }
    painter->restore();
}

QSize SectionDelegate::sizeHint(const QStyleOptionViewItem& o, const QModelIndex& index) const {
    if (!index.isValid()) return QSize();

    auto size = QStyledItemDelegate::sizeHint(o, index);
    if (utilqt::getData(index, Role::Type) == Type::File) {
        size.setHeight(itemSize_);
    }
    return size;
}

}  // namespace

class ChunkProxyModel : public QAbstractProxyModel {
public:
    ChunkProxyModel(QAbstractItemModel* model, int chunkSize, QObject* parent)
        : QAbstractProxyModel(parent), chunkSize_{chunkSize} {

        setSourceModel(model);
        auto reset = [this]() {
            beginResetModel();
            sourceIndexMapping_.clear();
            endResetModel();
        };
        connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, reset);
        connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, reset);
        connect(model, &QAbstractItemModel::rowsAboutToBeMoved, this, reset);
        connect(model, &QAbstractItemModel::columnsAboutToBeInserted, this, reset);
        connect(model, &QAbstractItemModel::columnsAboutToBeRemoved, this, reset);
        connect(model, &QAbstractItemModel::columnsAboutToBeMoved, this, reset);
        connect(model, &QAbstractItemModel::modelAboutToBeReset, this, reset);
        connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, reset);

        connect(
            model, &QAbstractItemModel::dataChanged, this,
            [this](const QModelIndex& topLeft, const QModelIndex& bottomRight, const auto& roles) {
                for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
                    auto changed = mapFromSource(sourceModel()->index(i, 0, topLeft.parent()));
                    dataChanged(changed, changed, roles);
                }
            });
    }

    virtual int columnCount(
        [[maybe_unused]] const QModelIndex& parent = QModelIndex()) const override {
        return chunkSize_;
    }
    virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override {
        auto sourceParent = mapToSource(parent);
        auto sourceRows = sourceModel()->rowCount(sourceParent);

        if (utilqt::getData(sourceParent, Role::Type) == Type::SubSection) {
            auto chunkedRows = (sourceRows + chunkSize_ - 1) / chunkSize_;
            return chunkedRows;
        } else {
            return sourceRows;
        }
    }

    QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override {
        if (!sourceIndex.isValid()) return {};

        auto map = mapping(sourceIndex);
        if (utilqt::getData(sourceIndex, Role::Type) == Type::File) {
            const auto row = sourceIndex.row() / chunkSize_;
            const auto col = sourceIndex.row() % chunkSize_;
            return createIndex(row, col, map);
        } else {
            return createIndex(sourceIndex.row(), sourceIndex.column(), map);
        }
    }

    QModelIndex mapToSource(const QModelIndex& proxyIndex) const override {
        if (!proxyIndex.isValid()) return {};

        auto m = static_cast<const Mapping*>(proxyIndex.internalPointer());
        return sourceModel()->index(m->sourceRow, m->sourceCol, m->sourceParent);
    }

    QModelIndex parent(const QModelIndex& child) const override {
        const QModelIndex sourceIndex = mapToSource(child);
        const QModelIndex sourceParent = sourceIndex.parent();
        return mapFromSource(sourceParent);
    }

    QModelIndex index(int row, int column, const QModelIndex& parent) const override {
        const QModelIndex sourceParent = mapToSource(parent);

        if (utilqt::getData(sourceParent, Role::Type) == Type::SubSection) {
            const int sourceRow = row * chunkSize_ + column;
            return mapFromSource(sourceModel()->index(sourceRow, 0, sourceParent));
        } else {
            return mapFromSource(sourceModel()->index(row, column, sourceParent));
        }
    }

    QModelIndex sibling(int row, int column, const QModelIndex& idx) const override {
        if (!idx.isValid()) return {};
        return index(row, column, idx.parent());
    }

    void setChunkSize(int chunkSize) {
        if (chunkSize_ == chunkSize) return;

        beginResetModel();
        chunkSize_ = chunkSize;
        sourceIndexMapping_.clear();
        endResetModel();
    }

    int chunkSize() const { return chunkSize_; }

private:
    struct Hash {
        size_t operator()(const QModelIndex& idx) const { return qHash(idx, std::hash<int>{}(0)); }
    };
    struct Mapping {
        int sourceRow;
        int sourceCol;
        QPersistentModelIndex sourceParent;
    };
    using IndexMap = std::unordered_map<QModelIndex, Mapping, Hash>;

    Mapping* mapping(const QModelIndex& sourceIndex) const {
        auto [it, inserted] = sourceIndexMapping_.try_emplace(sourceIndex);
        if (inserted) {
            it->second.sourceRow = sourceIndex.row();
            it->second.sourceCol = sourceIndex.column();
            it->second.sourceParent = sourceIndex.parent();
        }
        return &(it->second);
    }
    mutable IndexMap sourceIndexMapping_;
    int chunkSize_;
};

WorkspaceGridView::WorkspaceGridView(QAbstractItemModel* theModel, QWidget* parent)
    : QTreeView{parent}
    , itemSize_{utilqt::emToPx(this, 14)}
    , proxy_{new ChunkProxyModel{theModel, 3, this}} {

    setModel(proxy_);

    setHeaderHidden(true);
    setSelectionBehavior(QAbstractItemView::SelectItems);
    setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
    setItemDelegate(new SectionDelegate(itemSize_, this));
    setIndentation(0);

#if defined(WIN32)
    // Scrolling on Windows is set to scroll per item by default. Also need to adjust the step size
    // since the default appears to be based on the number of items in the view.
    setVerticalScrollMode(ScrollPerPixel);
    verticalScrollBar()->setSingleStep(utilqt::emToPx(parent, 1.5));
#endif

    connect(this, &QTreeView::doubleClicked, this, [this](const QModelIndex& index) {
        if (index.isValid() && (utilqt::getData(index, Role::Type) == Type::File)) {
            const auto filename = utilqt::getData(index, Role::FilePath).toString();
            const auto isExample = utilqt::getData(index, Role::isExample).toBool();
            emit loadFile(filename, isExample);
        }
    });

    connect(this, &QTreeView::clicked, this, [this](const QModelIndex& index) {
        if (index.isValid() && (utilqt::getData(index, Role::Type) != Type::File)) {

            if (QGuiApplication::keyboardModifiers() & Qt::ControlModifier) {
                isExpanded(index) ? collapseRecursively(index) : expandRecursively(index);
            } else {
                setExpanded(index, !isExpanded(index));
            }
        }
    });

    connect(selectionModel(), &QItemSelectionModel::currentChanged, this,
            [this](const QModelIndex& current, const QModelIndex&) {
                if (current.isValid() && (utilqt::getData(current, Role::Type) == Type::File)) {
                    emit selectFile(current);
                } else {
                    emit selectFile(QModelIndex{});
                }
            });

    header()->setSectionResizeMode(QHeaderView::Stretch);
}

const QAbstractProxyModel& WorkspaceGridView::proxy() const { return *proxy_; }

void WorkspaceGridView::resizeEvent(QResizeEvent* event) {
    QTreeView::resizeEvent(event);

    const int newChunkSize = event->size().width() / itemSize_;

    if (newChunkSize != proxy_->chunkSize()) {
        std::vector<QModelIndex> expanded;
        auto findExpaned = [&](auto& self, const QModelIndex& parent) -> void {
            auto rows = proxy_->rowCount(parent);
            for (int i = 0; i < rows; ++i) {
                auto index = proxy_->index(i, 0, parent);
                if (isExpanded(index)) {
                    expanded.push_back(proxy_->mapToSource(index));
                    self(self, index);
                }
            }
        };
        findExpaned(findExpaned, QModelIndex{});
        proxy_->setChunkSize(event->size().width() / itemSize_);
        for (const auto& idx : expanded) {
            expand(proxy_->mapFromSource(idx));
        }
    }
}

#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
// QTreeView::expandRecursively() was introduced in Qt 5.13
// see https://doc.qt.io/qt-5/qtreeview.html#expandRecursively
void WorkspaceGridView::expandRecursively(const QModelIndex& index) {
    if (index.isValid()) {
        for (int i = 0; i < index.model()->rowCount(index); ++i) {
            expandRecursively(index.child(i, 0));
        }
        if (!isExpanded(index)) {
            expand(index);
        }
    }
}
#endif

void WorkspaceGridView::collapseRecursively(const QModelIndex& index) {
    if (index.isValid()) {
        for (int i = 0; i < model()->rowCount(index); ++i) {
            collapseRecursively(model()->index(i, 0, index));
        }
        if (isExpanded(index)) {
            collapse(index);
        }
    }
}

}  // namespace inviwo
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <iterator>

#include <sstream>
#include <vector>
#include <memory>
#include <regex>
#include <map>
#include <algorithm>
#include <functional>

using namespace std;

wstringstream program_test(L" 10 ( hello?) (hello -5) ( hi ( one two))  ");
wstringstream program_norwig(L"(begin (define r 10) (* pi (* r r)))");

typedef wstring Token;
typedef vector<Token>::iterator TokenItr;

const Token openParen = L"(";
const Token closeParen = L")";

bool IsNumber(const Token& token)
{
	return regex_match(token, wregex(L"[(-|+)|][0-9]+"));
}

vector<Token> tokenize(wistream& program)
{
	vector<Token> tokens;

	istreambuf_iterator<wchar_t> itr(program);
	istreambuf_iterator<wchar_t> eos;

	while(itr != eos)
	{
		while(itr != eos && iswspace(*itr))
			itr++;

		tokens.emplace_back();

		if(*itr == '(')
		{
			tokens.back() = openParen;
			itr++;
		}
		else if(*itr == ')')
		{
			tokens.back() = closeParen;
			itr++;
		}
		else
		{
			while(itr != eos && !iswspace(*itr) && !(*itr == ')') && !(*itr == '('))
			{
				tokens.back().push_back(*itr);
				itr++;
			}
		}

		while(itr != eos && iswspace(*itr))
			itr++;
	}

	return tokens;
}

template<typename T>
void print(const T& x, wostream& os)
{
	//os << x << '\n';
	os << x ;
}

class Context;

struct Expression
{
	template<typename T>
	Expression(const T& src):Expression_(new Impl<T>(src))
	{
	}

	Expression(const Expression& src):Expression_(src.Expression_){}

	friend void print(const Expression& x, wostream& os)
	{
		x.Expression_->print_(os);
	}

	template<typename T>
	T get() const
	{
		auto impl = dynamic_cast<Impl<T>*>(Expression_.get());
		if(impl)
		{
			return impl->mData;
		}

		throw;
	}

private:
	struct Concept
	{
		virtual void print_(wostream&) const = 0;
		virtual Expression eval(const Context& context) const = 0;
	};

	template<typename T>
	struct Impl : public Concept
	{
		Impl(const T& data):mData(data){}

		void print_(wostream& os) const override
		{
			print(mData, os);
		}

		T mData;
	};

private:
	shared_ptr<Concept> Expression_;
};

struct Number
{
	Number(int value): value_(value){}

	Expression eval() const { return Expression(*this); }

	operator int() const { return value_; }

	void print_(wostream& os) const
	{
		os << value_;
	}

private:
	int value_;
};

Expression make_atom(Token token)
{
	if(IsNumber(token))
	{
		wstringstream ss(token);

		int num = 0;

		ss >> num;

		return num;
	}
	else
	{
		return token;
	}
}

struct List
{
	List(vector<Token>::iterator& itr, const vector<Token>::iterator& last)
	{
		while(itr != last)
		{
			if(*itr == openParen)
			{
				list_.emplace_back(List(++itr, last));
			}
			else if(*itr == closeParen)
			{
				itr++;
				return;
			}
			else
			{
				list_.push_back(make_atom(*itr));
				itr++;
			}
		}
	}

	Expression eval() const { return Expression(0); }

	void print_(wostream& os) const
	{
		os << "[";

		for(const auto& expr : list_)
		{
			print(expr, os);
			os << ' ';
		}

		os << "]";
	}

private:
	vector<Expression> list_;
};

wostream& operator<<(wostream& os, const List& listExpr)
{
	listExpr.print_(os);

	return os;
}

typedef map<wstring, Expression> Context;

struct OpPlus
{
	void print_(wostream& os) const
	{
		os << L"+";
	}

	Expression operator()(vector<Expression> operands)
	{
		int sum = 0;

		for(const auto& operand : operands)
		{
			sum += operand.get<int>();
		}

		return sum;
	}

};

wostream& operator<<(wostream& os, const OpPlus& op)
{
	op.print_(os);

	return os;
}

typedef vector<Expression> Program;

int main(int argc, char** argv)
{
	Context gContext;

	gContext.emplace(wstring(L"+"), Expression(OpPlus()));

	Program program;

	program.push_back(1);
	program.push_back(wstring(L"Hello"));
	program.push_back(Number(5));

	for(const auto& aExpr : program)
	{
		print(aExpr, wcout);
	}

	wcout << program.front().get<int>() << '\n';

	//Program toSum = { 1, 2, 3 , wstring(L"Hello")};
	Program toSum = { 1, 2, 3 };

	auto op = OpPlus();

	auto sumExpr = op(toSum);

	wcout << L"sum = ";

	print(sumExpr, wcout);

	wcout << '\n';

	auto aTokens = tokenize(program_norwig);

	auto myList = List(aTokens.begin(), aTokens.end());

	print(myList, wcout);

	wcout << '\n';

	aTokens = tokenize(program_test);

	auto myList2 = List(aTokens.begin(), aTokens.end());

	print(myList2, wcout);

	wcout << '\n';

	return 0;
}
<commit_msg>wtf concepts<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <iterator>

#include <sstream>
#include <vector>
#include <memory>
#include <regex>
#include <map>
#include <algorithm>
#include <functional>

using namespace std;

wstringstream program_test(L" 10 ( hello?) (hello -5) ( hi ( one two))  ");
wstringstream program_norwig(L"(begin (define r 10) (* pi (* r r)))");

typedef wstring Token;
typedef vector<Token>::iterator TokenItr;

const Token openParen = L"(";
const Token closeParen = L")";

bool IsNumber(const Token& token)
{
	return regex_match(token, wregex(L"[(-|+)|][0-9]+"));
}

vector<Token> tokenize(wistream& program)
{
	vector<Token> tokens;

	istreambuf_iterator<wchar_t> itr(program);
	istreambuf_iterator<wchar_t> eos;

	while(itr != eos)
	{
		while(itr != eos && iswspace(*itr))
			itr++;

		tokens.emplace_back();

		if(*itr == '(')
		{
			tokens.back() = openParen;
			itr++;
		}
		else if(*itr == ')')
		{
			tokens.back() = closeParen;
			itr++;
		}
		else
		{
			while(itr != eos && !iswspace(*itr) && !(*itr == ')') && !(*itr == '('))
			{
				tokens.back().push_back(*itr);
				itr++;
			}
		}

		while(itr != eos && iswspace(*itr))
			itr++;
	}

	return tokens;
}

template<typename T>
void print(const T& x, wostream& os)
{
	//os << x << '\n';
	os << x ;
}

struct Context;

struct Expression
{
	template<typename T>
	Expression(const T& src):Expression_(new Impl<T>(src))
	{
	}

	Expression(const Expression& src):Expression_(src.Expression_){}

	friend void print(const Expression& x, std::wostream& os)
	{
		x.Expression_->print_(os);
	}

	friend Expression eval(const Expression& e, const Context& context)
	{
		return e.Expression_->eval(context);
	}

	template<typename T>
	T get() const
	{
		auto impl = dynamic_cast<Impl<T>*>(Expression_.get());
		if(impl)
		{
			return impl->mData;
		}

		throw;
	}

private:
	struct Concept
	{
		virtual void print_(std::wostream&) const = 0;
		virtual Expression eval(const Context& context) const = 0;
	};

	template<typename T>
	struct Impl : public Concept
	{
		Impl(const T& data):mData(data){}

		void print_(wostream& os) const override
		{
			print(mData, os);
		}

		Expression eval(const Context& context) const override
		{
			return *this;
		}

		T mData;
	};

private:
	shared_ptr<Concept> Expression_;
};

struct Number
{
	Number(int value): value_(value){}

	Expression eval(const Context& context) const { return Expression(*this); }

	operator int() const { return value_; }

	void print_(std::wostream& os) const
	{
		os << value_;
	}

private:
	int value_;
};

wostream& operator<<(wostream& os, const Number& num)
{
	num.print_(os);

	return os;
};

struct Symbol
{
	Symbol(wstring value): value_(value){}

	Expression eval(const Context& context) const { return Expression(*this); }

	operator wstring() const { return value_; }

	void print_(std::wostream& os) const
	{
		os << value_;
	}

private:
	wstring value_;
};

wostream& operator<<(wostream& os, const Symbol& symbol)
{
	symbol.print_(os);

	return os;
};

Expression make_atom(Token token)
{
	if(IsNumber(token))
	{
		wstringstream ss(token);

		int num = 0;

		ss >> num;

		return Number(num);
	}
	else
	{
		return Symbol(token);
	}
}

typedef unary_function<vector<Expression>&, Expression> Op;

struct OpPlus : public Op
{
	void print_(wostream& os) const
	{
		os << L"+";
	}

	Expression operator()(vector<Expression>& operands) const
	{
		int sum = 0;

		for(const auto& operand : operands)
		{
			sum += operand.get<Number>();
		}

		return sum;
	}

	Expression eval(const Context& context) const
	{
		return Expression(0);
	}

};

struct List
{
	List(vector<Token>::iterator& itr, const vector<Token>::iterator& last)
	{
		while(itr != last)
		{
			if(*itr == openParen)
			{
				list_.emplace_back(List(++itr, last));
			}
			else if(*itr == closeParen)
			{
				itr++;
				return;
			}
			else
			{
				list_.push_back(make_atom(*itr));
				itr++;
			}
		}
	}

	Expression eval(const Context& context) const
	{
		OpPlus op = list_.front().get<OpPlus>();

		vector<Expression> args(++list_.begin(), list_.end());

		return op(args);
	}

	void print_(wostream& os) const
	{
		os << "[";

		for(const auto& expr : list_)
		{
			print(expr, os);
			os << ' ';
		}

		os << "]";
	}

private:
	vector<Expression> list_;
};

wostream& operator<<(wostream& os, const List& listExpr)
{
	listExpr.print_(os);

	return os;
}

struct Context
{
	Expression Find(const Token& token) const
	{
		auto ret = map_.find(token);
		if(ret != map_.end())
		{
			return ret->second;
		}

		throw "Undefined symbol";
	}

	map<Token, Expression> map_;
};

wostream& operator<<(wostream& os, const OpPlus& op)
{
	op.print_(os);

	return os;
}

typedef vector<Expression> Program;

int main(int argc, char** argv)
{
	Context gContext;

	gContext.map_.emplace(wstring(L"+"), Expression(OpPlus()));

	Program program;

	//program.push_back(Number(1));
	//program.push_back(wstring(L"Hello"));
	//program.push_back(Number(5));

	for(const auto& aExpr : program)
	{
		print(aExpr, wcout);
	}

	//wcout << program.front().get<Number>() << '\n';

	//Program toSum = { 1, 2, 3 , wstring(L"Hello")};
	//Program toSum = { 1, 2, 3 };

	//auto op = OpPlus();

	//auto sumExpr = op(toSum);

	//wcout << L"sum = ";

	//print(sumExpr, wcout);

	wcout << '\n';

	auto aTokens = tokenize(program_norwig);

	auto myList = List(aTokens.begin(), aTokens.end());

	print(myList, wcout);

	wcout << '\n';

	aTokens = tokenize(program_test);

	auto myList2 = List(aTokens.begin(), aTokens.end());

	print(myList2, wcout);

	wcout << '\n';

	return 0;
}
<|endoftext|>


<commit_before>#include <fstream>
#include <string>
#include <iostream>
#include <math.h>
#include <algorithm>

#include "io.hh"
#include "str.hh"
#include "conf.hh"
#include "HmmSet.hh"
#include "util.hh"

using namespace aku;

conf::Config config;

HmmSet model1;
HmmSet model2;

int
main(int argc, char *argv[])
{
  std::string m1_gk, m1_mc, m1_ph;
  std::string m2_gk, m2_mc;
  std::string out_base;
  try {
    config("usage: clskld [OPTION...]\n")
      ('h', "help", "", "", "display help")
      ('\0', "base1=BASENAME", "arg", "", "base filename for the source model")
      ('\0', "gk1=FILE", "arg", "", "Mixture base distributions for the source model")
      ('\0', "mc1=FILE", "arg", "", "Mixture coefficients for the states of the source model")
      ('\0', "ph1=FILE", "arg", "", "HMM definitions for the source model")
      ('\0', "base2=BASENAME", "arg", "", "base filename for the updated model")
      ('\0', "gk2=FILE", "arg", "", "Mixture base distributions for the updated model")
      ('\0', "mc2=FILE", "arg", "", "Mixture coefficients for the states of the updated model")
      ('\0', "ph2=FILE", "arg", "", "HMM definitions for the updated model")
      ('w', "mixtures", "", "", "Print KLDs of mixture weights")
      ('m', "means", "", "", "Print KLDs of Gaussian means")
      ('c', "covs", "", "", "Print KLDs of Gaussian covariances")
      ;
    config.default_parse(argc, argv);

    // Load the first model
    if (config["base1"].specified)
    {
      model1.read_all(config["base1"].get_str());
    }
    else if (config["gk1"].specified && config["mc1"].specified &&
             config["ph1"].specified)
    {
      model1.read_gk(config["gk1"].get_str());
      model1.read_mc(config["mc1"].get_str());
      model1.read_ph(config["ph1"].get_str());
    }
    else
      throw std::string("Must give either --base1 or all --gk1, --mc1 and --ph1");

    // Load the second model
    if (config["base2"].specified)
    {
      model2.read_all(config["base2"].get_str());
    }
    else if (config["gk2"].specified && config["mc2"].specified &&
             config["ph2"].specified)
    {
      model2.read_gk(config["gk2"].get_str());
      model2.read_mc(config["mc2"].get_str());
      model2.read_ph(config["ph2"].get_str());
    }
    else
      throw std::string("Must give either --base2 or all --gk2, --mc2 and --ph2");

    // Model similarity check
    if (model1.num_emission_pdfs() != model2.num_emission_pdfs())
      throw std::string("Both models must have the same number of mixtures");
    if (model1.num_pool_pdfs() != model2.num_pool_pdfs())
      throw std::string("Both models must have the same number of Gaussians");

    if (config["mixtures"].specified)
    {
      for (int i = 0; i < model1.num_emission_pdfs(); i++)
      {
        Mixture *m1 = model1.get_emission_pdf(i);
        Mixture *m2 = model2.get_emission_pdf(i);
        //assert( m1->size() == m2->size() );
        if (m1->size() != m2->size())
          continue;

        double kld = 0;
        for (int j = 0; j < m1->size(); j++)
        {
          double w1 = m1->get_mixture_coefficient(j);
          double w2 = m2->get_mixture_coefficient(j);
          kld += w2*log(w2/w1);
        }
        printf("%g\n", kld);
      }
    }
    if (config["means"].specified)
    {
      PDFPool *pool1 = model1.get_pool();
      PDFPool *pool2 = model2.get_pool();

      for (int i = 0; i < pool1->size(); i++)
      {
        Gaussian *pdf1 = dynamic_cast< Gaussian* >(pool1->get_pdf(i));
        Gaussian *pdf2 = dynamic_cast< Gaussian* >(pool2->get_pdf(i));
        if (pdf1 == NULL || pdf2 == NULL)
          throw std::string("Only Gaussian PDFs are supported!");

        Vector mean1;
        Vector mean2;
        Vector cov;
        pdf1->get_mean(mean1);
        pdf2->get_mean(mean2);
        pdf1->get_covariance(cov);

        int dim = mean1.size();
        double kld = 0;
        for (int j = 0; j < dim; j++)
        {
          double d = mean2(j)-mean1(j);
          kld += d*d/cov(j);
        }
        kld /= 2.0;
        printf("%g\n", kld);
      }
    }

    if (config["covs"].specified)
    {
      PDFPool *pool1 = model1.get_pool();
      PDFPool *pool2 = model2.get_pool();

      for (int i = 0; i < pool1->size(); i++)
      {
        Gaussian *pdf1 = dynamic_cast< Gaussian* >(pool1->get_pdf(i));
        Gaussian *pdf2 = dynamic_cast< Gaussian* >(pool2->get_pdf(i));
        if (pdf1 == NULL || pdf2 == NULL)
          throw std::string("Only Gaussian PDFs are supported!");

        Vector cov1;
        Vector cov2;
        pdf1->get_covariance(cov1);
        pdf2->get_covariance(cov2);

        int dim = cov1.size();
        double kld = 0;
        for (int j = 0; j < dim; j++)
          kld += cov2(j)/cov1(j) + log(cov1(j)/cov2(j));
        kld = (kld - dim)/2.0;
        printf("%g\n", kld);
      }
    }
  }

  // Handle errors
  catch (std::exception &e) {
    fprintf(stderr, "exception: %s\n", e.what());
    abort();
  }

  catch (std::string &str) {
    fprintf(stderr, "exception: %s\n", str.c_str());
    abort();
  }

}
<commit_msg>Gaussian KLD evaluation<commit_after>#include <fstream>
#include <string>
#include <iostream>
#include <math.h>
#include <algorithm>

#include "io.hh"
#include "str.hh"
#include "conf.hh"
#include "HmmSet.hh"
#include "util.hh"

using namespace aku;

conf::Config config;

HmmSet model1;
HmmSet model2;

int
main(int argc, char *argv[])
{
  std::string m1_gk, m1_mc, m1_ph;
  std::string m2_gk, m2_mc;
  std::string out_base;
  try {
    config("usage: clskld [OPTION...]\n")
      ('h', "help", "", "", "display help")
      ('\0', "base1=BASENAME", "arg", "", "base filename for the source model")
      ('\0', "gk1=FILE", "arg", "", "Mixture base distributions for the source model")
      ('\0', "mc1=FILE", "arg", "", "Mixture coefficients for the states of the source model")
      ('\0', "ph1=FILE", "arg", "", "HMM definitions for the source model")
      ('\0', "base2=BASENAME", "arg", "", "base filename for the updated model")
      ('\0', "gk2=FILE", "arg", "", "Mixture base distributions for the updated model")
      ('\0', "mc2=FILE", "arg", "", "Mixture coefficients for the states of the updated model")
      ('\0', "ph2=FILE", "arg", "", "HMM definitions for the updated model")
      ('w', "mixtures", "", "", "Print KLDs of mixture weights")
      ('g', "gaussians", "", "", "Print KLDs of Gaussians")
      ('m', "means", "", "", "Print KLDs of Gaussian means")
      ('c', "covs", "", "", "Print KLDs of Gaussian covariances")
      ;
    config.default_parse(argc, argv);

    // Load the first model
    if (config["base1"].specified)
    {
      model1.read_all(config["base1"].get_str());
    }
    else if (config["gk1"].specified && config["mc1"].specified &&
             config["ph1"].specified)
    {
      model1.read_gk(config["gk1"].get_str());
      model1.read_mc(config["mc1"].get_str());
      model1.read_ph(config["ph1"].get_str());
    }
    else
      throw std::string("Must give either --base1 or all --gk1, --mc1 and --ph1");

    // Load the second model
    if (config["base2"].specified)
    {
      model2.read_all(config["base2"].get_str());
    }
    else if (config["gk2"].specified && config["mc2"].specified &&
             config["ph2"].specified)
    {
      model2.read_gk(config["gk2"].get_str());
      model2.read_mc(config["mc2"].get_str());
      model2.read_ph(config["ph2"].get_str());
    }
    else
      throw std::string("Must give either --base2 or all --gk2, --mc2 and --ph2");

    // Model similarity check
    if (model1.num_emission_pdfs() != model2.num_emission_pdfs())
      throw std::string("Both models must have the same number of mixtures");
    if (model1.num_pool_pdfs() != model2.num_pool_pdfs())
      throw std::string("Both models must have the same number of Gaussians");

    if (config["mixtures"].specified)
    {
      for (int i = 0; i < model1.num_emission_pdfs(); i++)
      {
        Mixture *m1 = model1.get_emission_pdf(i);
        Mixture *m2 = model2.get_emission_pdf(i);
        //assert( m1->size() == m2->size() );
        if (m1->size() != m2->size())
          continue;

        double kld = 0;
        for (int j = 0; j < m1->size(); j++)
        {
          double w1 = m1->get_mixture_coefficient(j);
          double w2 = m2->get_mixture_coefficient(j);
          kld += w2*log(w2/w1);
        }
        printf("%g\n", kld);
      }
    }
    if (config["gaussians"].specified)
    {
      PDFPool *pool1 = model1.get_pool();
      PDFPool *pool2 = model2.get_pool();

      for (int i = 0; i < pool1->size(); i++)
      {
        Gaussian *pdf1 = dynamic_cast< Gaussian* >(pool1->get_pdf(i));
        Gaussian *pdf2 = dynamic_cast< Gaussian* >(pool2->get_pdf(i));
        if (pdf1 == NULL || pdf2 == NULL)
          throw std::string("Only Gaussian PDFs are supported!");

        Vector mean1;
        Vector mean2;
        Vector cov1;
        Vector cov2;
        pdf1->get_mean(mean1);
        pdf2->get_mean(mean2);
        pdf1->get_covariance(cov1);
        pdf2->get_covariance(cov2);
        int dim = cov1.size();
        double kld = 0;
        for (int j = 0; j < dim; j++)
        {
          double d = mean2(j)-mean1(j);
          kld += d*d/cov1(j);
          kld += cov2(j)/cov1(j) + log(cov1(j)/cov2(j));
        }
        kld = (kld - dim)/2.0;
        printf("%g\n", kld);
      }
    }

    if (config["means"].specified)
    {
      PDFPool *pool1 = model1.get_pool();
      PDFPool *pool2 = model2.get_pool();

      for (int i = 0; i < pool1->size(); i++)
      {
        Gaussian *pdf1 = dynamic_cast< Gaussian* >(pool1->get_pdf(i));
        Gaussian *pdf2 = dynamic_cast< Gaussian* >(pool2->get_pdf(i));
        if (pdf1 == NULL || pdf2 == NULL)
          throw std::string("Only Gaussian PDFs are supported!");

        Vector mean1;
        Vector mean2;
        Vector cov;
        pdf1->get_mean(mean1);
        pdf2->get_mean(mean2);
        pdf1->get_covariance(cov);

        int dim = mean1.size();
        double kld = 0;
        for (int j = 0; j < dim; j++)
        {
          double d = mean2(j)-mean1(j);
          kld += d*d/cov(j);
        }
        kld /= 2.0;
        printf("%g\n", kld);
      }
    }

    if (config["covs"].specified)
    {
      PDFPool *pool1 = model1.get_pool();
      PDFPool *pool2 = model2.get_pool();

      for (int i = 0; i < pool1->size(); i++)
      {
        Gaussian *pdf1 = dynamic_cast< Gaussian* >(pool1->get_pdf(i));
        Gaussian *pdf2 = dynamic_cast< Gaussian* >(pool2->get_pdf(i));
        if (pdf1 == NULL || pdf2 == NULL)
          throw std::string("Only Gaussian PDFs are supported!");

        Vector cov1;
        Vector cov2;
        pdf1->get_covariance(cov1);
        pdf2->get_covariance(cov2);

        int dim = cov1.size();
        double kld = 0;
        for (int j = 0; j < dim; j++)
          kld += cov2(j)/cov1(j) + log(cov1(j)/cov2(j));
        kld = (kld - dim)/2.0;
        printf("%g\n", kld);
      }
    }
  }

  // Handle errors
  catch (std::exception &e) {
    fprintf(stderr, "exception: %s\n", e.what());
    abort();
  }

  catch (std::string &str) {
    fprintf(stderr, "exception: %s\n", str.c_str());
    abort();
  }

}
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2016 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include "runtimes/libjoynr-runtime/LibJoynrRuntime.h"

#include <cassert>
#include <vector>

#include "joynr/Dispatcher.h"
#include "joynr/InProcessDispatcher.h"
#include "joynr/system/RoutingTypes/CommonApiDbusAddress.h"
#include "joynr/PublicationManager.h"
#include "joynr/SubscriptionManager.h"
#include "joynr/InProcessPublicationSender.h"
#include "joynr/JoynrMessageSender.h"
#include "joynr/MessageRouter.h"
#include "libjoynr/in-process/InProcessLibJoynrMessagingSkeleton.h"
#include "joynr/InProcessMessagingAddress.h"
#include "joynr/MessagingStubFactory.h"
#include "libjoynr/in-process/InProcessMessagingStubFactory.h"
#include "joynr/system/DiscoveryProxy.h"
#include "joynr/TypeUtil.h"
#include "joynr/Util.h"
#include "joynr/Settings.h"

namespace joynr
{

LibJoynrRuntime::LibJoynrRuntime(Settings* settings)
        : JoynrRuntime(*settings),
          subscriptionManager(nullptr),
          inProcessPublicationSender(nullptr),
          inProcessConnectorFactory(nullptr),
          joynrMessagingConnectorFactory(nullptr),
          joynrMessagingSendStub(nullptr),
          joynrMessageSender(nullptr),
          joynrDispatcher(nullptr),
          inProcessDispatcher(nullptr),
          settings(settings),
          libjoynrSettings(new LibjoynrSettings(*settings)),
          dispatcherMessagingSkeleton(nullptr),
          runtimeExecutor(nullptr)
{
    libjoynrSettings->printSettings();
}

LibJoynrRuntime::~LibJoynrRuntime()
{
    delete proxyFactory;
    delete inProcessDispatcher;
    delete joynrMessageSender;
    delete joynrDispatcher;
    delete libjoynrSettings;
    libjoynrSettings = nullptr;
    delete settings;
}

void LibJoynrRuntime::init(
        std::shared_ptr<IMiddlewareMessagingStubFactory> middlewareMessagingStubFactory,
        std::shared_ptr<const joynr::system::RoutingTypes::Address> libjoynrMessagingAddress,
        std::shared_ptr<const joynr::system::RoutingTypes::Address> ccMessagingAddress)
{
    // create messaging stub factory
    auto messagingStubFactory = std::make_shared<MessagingStubFactory>();
    middlewareMessagingStubFactory->registerOnMessagingStubClosedCallback([messagingStubFactory](
            const std::shared_ptr<const joynr::system::RoutingTypes::Address>& destinationAddress) {
        messagingStubFactory->remove(destinationAddress);
    });
    messagingStubFactory->registerStubFactory(middlewareMessagingStubFactory);
    messagingStubFactory->registerStubFactory(std::make_shared<InProcessMessagingStubFactory>());

    // create message router
    messageRouter = std::make_shared<MessageRouter>(std::move(messagingStubFactory),
                                                    libjoynrMessagingAddress,
                                                    singleThreadIOService.getIOService());

    startLibJoynrMessagingSkeleton(messageRouter);

    joynrMessageSender = new JoynrMessageSender(messageRouter);
    joynrDispatcher = new Dispatcher(joynrMessageSender, singleThreadIOService.getIOService());
    joynrMessageSender->registerDispatcher(joynrDispatcher);

    // create the inprocess skeleton for the dispatcher
    dispatcherMessagingSkeleton =
            std::make_shared<InProcessLibJoynrMessagingSkeleton>(joynrDispatcher);
    dispatcherAddress = std::make_shared<InProcessMessagingAddress>(dispatcherMessagingSkeleton);

    publicationManager = new PublicationManager(singleThreadIOService.getIOService());
    subscriptionManager = new SubscriptionManager(singleThreadIOService.getIOService());
    inProcessDispatcher = new InProcessDispatcher(singleThreadIOService.getIOService());

    inProcessPublicationSender = new InProcessPublicationSender(subscriptionManager);
    inProcessConnectorFactory = new InProcessConnectorFactory(
            subscriptionManager,
            publicationManager,
            inProcessPublicationSender,
            dynamic_cast<IRequestCallerDirectory*>(inProcessDispatcher));
    joynrMessagingConnectorFactory =
            new JoynrMessagingConnectorFactory(joynrMessageSender, subscriptionManager);

    auto connectorFactory = std::make_unique<ConnectorFactory>(
            inProcessConnectorFactory, joynrMessagingConnectorFactory);
    proxyFactory = new ProxyFactory(libjoynrMessagingAddress, std::move(connectorFactory), nullptr);

    // Set up the persistence file for storing provider participant ids
    std::string persistenceFilename = libjoynrSettings->getParticipantIdsPersistenceFilename();
    participantIdStorage = std::make_shared<ParticipantIdStorage>(persistenceFilename);

    // initialize the dispatchers
    std::vector<IDispatcher*> dispatcherList;
    dispatcherList.push_back(inProcessDispatcher);
    dispatcherList.push_back(joynrDispatcher);

    joynrDispatcher->registerPublicationManager(publicationManager);
    joynrDispatcher->registerSubscriptionManager(subscriptionManager);

    discoveryProxy = std::make_unique<LocalDiscoveryAggregator>(systemServicesSettings);
    requestCallerDirectory = dynamic_cast<IRequestCallerDirectory*>(inProcessDispatcher);

    std::string systemServicesDomain = systemServicesSettings.getDomain();
    std::string routingProviderParticipantId =
            systemServicesSettings.getCcRoutingProviderParticipantId();

    DiscoveryQos routingProviderDiscoveryQos;
    routingProviderDiscoveryQos.setCacheMaxAgeMs(1000);
    routingProviderDiscoveryQos.setArbitrationStrategy(
            DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
    routingProviderDiscoveryQos.addCustomParameter(
            "fixedParticipantId", routingProviderParticipantId);
    routingProviderDiscoveryQos.setDiscoveryTimeoutMs(50);

    std::unique_ptr<ProxyBuilder<joynr::system::RoutingProxy>> routingProxyBuilder(
            createProxyBuilder<joynr::system::RoutingProxy>(systemServicesDomain));
    auto routingProxy = routingProxyBuilder->setMessagingQos(MessagingQos(10000))
                                ->setCached(false)
                                ->setDiscoveryQos(routingProviderDiscoveryQos)
                                ->build();
    messageRouter->setParentRouter(std::unique_ptr<system::RoutingProxy>(routingProxy),
                                   ccMessagingAddress,
                                   routingProviderParticipantId);

    // setup discovery
    std::string discoveryProviderParticipantId =
            systemServicesSettings.getCcDiscoveryProviderParticipantId();
    DiscoveryQos discoveryProviderDiscoveryQos;
    discoveryProviderDiscoveryQos.setCacheMaxAgeMs(1000);
    discoveryProviderDiscoveryQos.setArbitrationStrategy(
            DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
    discoveryProviderDiscoveryQos.addCustomParameter(
            "fixedParticipantId", discoveryProviderParticipantId);
    discoveryProviderDiscoveryQos.setDiscoveryTimeoutMs(1000);

    std::unique_ptr<ProxyBuilder<joynr::system::DiscoveryProxy>> discoveryProxyBuilder(
            createProxyBuilder<joynr::system::DiscoveryProxy>(systemServicesDomain));
    joynr::system::IDiscoverySync* proxy =
            discoveryProxyBuilder->setMessagingQos(MessagingQos(40000))
                    ->setCached(false)
                    ->setDiscoveryQos(discoveryProviderDiscoveryQos)
                    ->build();
    discoveryProxy->setDiscoveryProxy(std::unique_ptr<joynr::system::IDiscoverySync>(proxy));
    capabilitiesRegistrar = std::make_unique<CapabilitiesRegistrar>(
            dispatcherList,
            *discoveryProxy,
            participantIdStorage,
            dispatcherAddress,
            messageRouter,
            messagingSettings.getDiscoveryEntryExpiryIntervalMs());
}

void LibJoynrRuntime::unregisterProvider(const std::string& participantId)
{
    assert(capabilitiesRegistrar);
    capabilitiesRegistrar->remove(participantId);
}

void LibJoynrRuntime::setRuntimeExecutor(JoynrRuntimeExecutor* runtimeExecutor)
{
    this->runtimeExecutor = std::unique_ptr<JoynrRuntimeExecutor>(runtimeExecutor);
}

LibJoynrRuntime* LibJoynrRuntime::create(JoynrRuntimeExecutor* runtimeExecutor)
{
    LibJoynrRuntime* runtime = runtimeExecutor->getRuntime();
    runtime->setRuntimeExecutor(runtimeExecutor);
    return runtime;
}

} // namespace joynr
<commit_msg>[C++] Ensure the libjoynr runtime is loading persisted subscriptions<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2016 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include "runtimes/libjoynr-runtime/LibJoynrRuntime.h"

#include <cassert>
#include <vector>

#include "joynr/Dispatcher.h"
#include "joynr/InProcessDispatcher.h"
#include "joynr/system/RoutingTypes/CommonApiDbusAddress.h"
#include "joynr/PublicationManager.h"
#include "joynr/SubscriptionManager.h"
#include "joynr/InProcessPublicationSender.h"
#include "joynr/JoynrMessageSender.h"
#include "joynr/MessageRouter.h"
#include "libjoynr/in-process/InProcessLibJoynrMessagingSkeleton.h"
#include "joynr/InProcessMessagingAddress.h"
#include "joynr/MessagingStubFactory.h"
#include "libjoynr/in-process/InProcessMessagingStubFactory.h"
#include "joynr/system/DiscoveryProxy.h"
#include "joynr/TypeUtil.h"
#include "joynr/Util.h"
#include "joynr/Settings.h"

namespace joynr
{

LibJoynrRuntime::LibJoynrRuntime(Settings* settings)
        : JoynrRuntime(*settings),
          subscriptionManager(nullptr),
          inProcessPublicationSender(nullptr),
          inProcessConnectorFactory(nullptr),
          joynrMessagingConnectorFactory(nullptr),
          joynrMessagingSendStub(nullptr),
          joynrMessageSender(nullptr),
          joynrDispatcher(nullptr),
          inProcessDispatcher(nullptr),
          settings(settings),
          libjoynrSettings(new LibjoynrSettings(*settings)),
          dispatcherMessagingSkeleton(nullptr),
          runtimeExecutor(nullptr)
{
    libjoynrSettings->printSettings();
}

LibJoynrRuntime::~LibJoynrRuntime()
{
    delete proxyFactory;
    delete inProcessDispatcher;
    delete joynrMessageSender;
    delete joynrDispatcher;
    delete libjoynrSettings;
    libjoynrSettings = nullptr;
    delete settings;
}

void LibJoynrRuntime::init(
        std::shared_ptr<IMiddlewareMessagingStubFactory> middlewareMessagingStubFactory,
        std::shared_ptr<const joynr::system::RoutingTypes::Address> libjoynrMessagingAddress,
        std::shared_ptr<const joynr::system::RoutingTypes::Address> ccMessagingAddress)
{
    // create messaging stub factory
    auto messagingStubFactory = std::make_shared<MessagingStubFactory>();
    middlewareMessagingStubFactory->registerOnMessagingStubClosedCallback([messagingStubFactory](
            const std::shared_ptr<const joynr::system::RoutingTypes::Address>& destinationAddress) {
        messagingStubFactory->remove(destinationAddress);
    });
    messagingStubFactory->registerStubFactory(middlewareMessagingStubFactory);
    messagingStubFactory->registerStubFactory(std::make_shared<InProcessMessagingStubFactory>());

    // create message router
    messageRouter = std::make_shared<MessageRouter>(std::move(messagingStubFactory),
                                                    libjoynrMessagingAddress,
                                                    singleThreadIOService.getIOService());

    startLibJoynrMessagingSkeleton(messageRouter);

    joynrMessageSender = new JoynrMessageSender(messageRouter);
    joynrDispatcher = new Dispatcher(joynrMessageSender, singleThreadIOService.getIOService());
    joynrMessageSender->registerDispatcher(joynrDispatcher);

    // create the inprocess skeleton for the dispatcher
    dispatcherMessagingSkeleton =
            std::make_shared<InProcessLibJoynrMessagingSkeleton>(joynrDispatcher);
    dispatcherAddress = std::make_shared<InProcessMessagingAddress>(dispatcherMessagingSkeleton);

    publicationManager = new PublicationManager(singleThreadIOService.getIOService());
    publicationManager->loadSavedAttributeSubscriptionRequestsMap(
            libjoynrSettings->getSubscriptionRequestPersistenceFilename());
    publicationManager->loadSavedBroadcastSubscriptionRequestsMap(
            libjoynrSettings->getBroadcastSubscriptionRequestPersistenceFilename());
    subscriptionManager = new SubscriptionManager(singleThreadIOService.getIOService());
    inProcessDispatcher = new InProcessDispatcher(singleThreadIOService.getIOService());

    inProcessPublicationSender = new InProcessPublicationSender(subscriptionManager);
    inProcessConnectorFactory = new InProcessConnectorFactory(
            subscriptionManager,
            publicationManager,
            inProcessPublicationSender,
            dynamic_cast<IRequestCallerDirectory*>(inProcessDispatcher));
    joynrMessagingConnectorFactory =
            new JoynrMessagingConnectorFactory(joynrMessageSender, subscriptionManager);

    auto connectorFactory = std::make_unique<ConnectorFactory>(
            inProcessConnectorFactory, joynrMessagingConnectorFactory);
    proxyFactory = new ProxyFactory(libjoynrMessagingAddress, std::move(connectorFactory), nullptr);

    // Set up the persistence file for storing provider participant ids
    std::string persistenceFilename = libjoynrSettings->getParticipantIdsPersistenceFilename();
    participantIdStorage = std::make_shared<ParticipantIdStorage>(persistenceFilename);

    // initialize the dispatchers
    std::vector<IDispatcher*> dispatcherList;
    dispatcherList.push_back(inProcessDispatcher);
    dispatcherList.push_back(joynrDispatcher);

    joynrDispatcher->registerPublicationManager(publicationManager);
    joynrDispatcher->registerSubscriptionManager(subscriptionManager);

    discoveryProxy = std::make_unique<LocalDiscoveryAggregator>(systemServicesSettings);
    requestCallerDirectory = dynamic_cast<IRequestCallerDirectory*>(inProcessDispatcher);

    std::string systemServicesDomain = systemServicesSettings.getDomain();
    std::string routingProviderParticipantId =
            systemServicesSettings.getCcRoutingProviderParticipantId();

    DiscoveryQos routingProviderDiscoveryQos;
    routingProviderDiscoveryQos.setCacheMaxAgeMs(1000);
    routingProviderDiscoveryQos.setArbitrationStrategy(
            DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
    routingProviderDiscoveryQos.addCustomParameter(
            "fixedParticipantId", routingProviderParticipantId);
    routingProviderDiscoveryQos.setDiscoveryTimeoutMs(50);

    std::unique_ptr<ProxyBuilder<joynr::system::RoutingProxy>> routingProxyBuilder(
            createProxyBuilder<joynr::system::RoutingProxy>(systemServicesDomain));
    auto routingProxy = routingProxyBuilder->setMessagingQos(MessagingQos(10000))
                                ->setCached(false)
                                ->setDiscoveryQos(routingProviderDiscoveryQos)
                                ->build();
    messageRouter->setParentRouter(std::unique_ptr<system::RoutingProxy>(routingProxy),
                                   ccMessagingAddress,
                                   routingProviderParticipantId);

    // setup discovery
    std::string discoveryProviderParticipantId =
            systemServicesSettings.getCcDiscoveryProviderParticipantId();
    DiscoveryQos discoveryProviderDiscoveryQos;
    discoveryProviderDiscoveryQos.setCacheMaxAgeMs(1000);
    discoveryProviderDiscoveryQos.setArbitrationStrategy(
            DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
    discoveryProviderDiscoveryQos.addCustomParameter(
            "fixedParticipantId", discoveryProviderParticipantId);
    discoveryProviderDiscoveryQos.setDiscoveryTimeoutMs(1000);

    std::unique_ptr<ProxyBuilder<joynr::system::DiscoveryProxy>> discoveryProxyBuilder(
            createProxyBuilder<joynr::system::DiscoveryProxy>(systemServicesDomain));
    joynr::system::IDiscoverySync* proxy =
            discoveryProxyBuilder->setMessagingQos(MessagingQos(40000))
                    ->setCached(false)
                    ->setDiscoveryQos(discoveryProviderDiscoveryQos)
                    ->build();
    discoveryProxy->setDiscoveryProxy(std::unique_ptr<joynr::system::IDiscoverySync>(proxy));
    capabilitiesRegistrar = std::make_unique<CapabilitiesRegistrar>(
            dispatcherList,
            *discoveryProxy,
            participantIdStorage,
            dispatcherAddress,
            messageRouter,
            messagingSettings.getDiscoveryEntryExpiryIntervalMs());
}

void LibJoynrRuntime::unregisterProvider(const std::string& participantId)
{
    assert(capabilitiesRegistrar);
    capabilitiesRegistrar->remove(participantId);
}

void LibJoynrRuntime::setRuntimeExecutor(JoynrRuntimeExecutor* runtimeExecutor)
{
    this->runtimeExecutor = std::unique_ptr<JoynrRuntimeExecutor>(runtimeExecutor);
}

LibJoynrRuntime* LibJoynrRuntime::create(JoynrRuntimeExecutor* runtimeExecutor)
{
    LibJoynrRuntime* runtime = runtimeExecutor->getRuntime();
    runtime->setRuntimeExecutor(runtimeExecutor);
    return runtime;
}

} // namespace joynr
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 * Copyright (C) 2006 Justin Haygood <jhaygood@spsu.edu>.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "ScrollView.h"

#include <algorithm>
#include "FloatRect.h"
#include "IntRect.h"
#include <windows.h>

using namespace std;

namespace WebCore {

class ScrollView::ScrollViewPrivate {
public:
    ScrollViewPrivate()
        : hasStaticBackground(false)
        , suppressScrollBars(false)
        , vScrollBarMode(ScrollBarAuto)
        , hScrollBarMode(ScrollBarAuto)
    {
    }
    IntSize scrollOffset;
    IntSize contentsSize;
    bool hasStaticBackground;
    bool suppressScrollBars;
    ScrollBarMode vScrollBarMode;
    ScrollBarMode hScrollBarMode;
};

ScrollView::ScrollView()
    : m_data(new ScrollViewPrivate())
{
}

ScrollView::~ScrollView()
{
    delete m_data;
}

void ScrollView::updateContents(const IntRect& updateRect, bool now)
{
    IntRect adjustedDirtyRect(updateRect);
    adjustedDirtyRect.move(-m_data->scrollOffset);

    RECT dirtyRect = RECT(adjustedDirtyRect);
#if PAINT_FLASHING_DEBUG
    HDC dc = GetDC(containingWindow());
    FillRect(dc, &dirtyRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
    ReleaseDC(containingWindow(), dc);
#endif

    InvalidateRect(containingWindow(), &dirtyRect, true);
    if (now)
        UpdateWindow(containingWindow());
}

int ScrollView::visibleWidth() const
{
    RECT bounds;
    GetClientRect(containingWindow(), &bounds);
    return (bounds.right - bounds.left);
}

int ScrollView::visibleHeight() const
{
    RECT bounds;
    GetClientRect(containingWindow(), &bounds);
    return (bounds.bottom - bounds.top);
}

FloatRect ScrollView::visibleContentRect() const
{
    RECT bounds;
    GetClientRect(containingWindow(), &bounds);
    FloatRect contentRect = bounds;
    contentRect.move(m_data->scrollOffset);
    return contentRect;
}

void ScrollView::setContentsPos(int newX, int newY)
{
    int dx = newX - contentsX();
    int dy = newY - contentsY();
    scrollBy(dx, dy);
}

void ScrollView::resizeContents(int w,int h)
{
    IntSize newSize(w,h);
    if (m_data->contentsSize != newSize) {
        m_data->contentsSize = newSize;
        updateScrollBars(m_data->scrollOffset);
    }
}

int ScrollView::contentsX() const
{
    return scrollOffset().width();
}

int ScrollView::contentsY() const
{
    return scrollOffset().height();
}

int ScrollView::contentsWidth() const
{
    return m_data->contentsSize.width();
}

int ScrollView::contentsHeight() const
{
    return m_data->contentsSize.height();
}

IntPoint ScrollView::convertToContainingWindow(const IntPoint& point) const
{
    return point - scrollOffset();
}

IntPoint ScrollView::convertFromContainingWindow(const IntPoint& point) const
{
    return point + scrollOffset();
}

IntSize ScrollView::scrollOffset() const
{
    return m_data->scrollOffset;
}

IntSize ScrollView::maximumScroll() const
{
    IntSize delta = m_data->contentsSize - m_data->scrollOffset;
    delta.clampNegativeToZero();
    return delta;
}

void ScrollView::scrollBy(int dx, int dy)
{
    IntSize scrollOffset = m_data->scrollOffset;
    IntSize maxScroll = maximumScroll();
    IntSize newScrollOffset = scrollOffset + IntSize(dx, dy);
    newScrollOffset.clampNegativeToZero();

    if (newScrollOffset != scrollOffset) {
        m_data->scrollOffset = newScrollOffset;
        updateScrollBars(m_data->scrollOffset);
        // ScrollBar updates can fail, so we check the final delta before scrolling
        IntSize scrollDelta = m_data->scrollOffset - scrollOffset;
        if (scrollDelta == IntSize())
            return;
        if (!m_data->hasStaticBackground)
            // FIXME: This could be made more efficient by passing a valid clip rect for only the document content.
            ScrollWindowEx(containingWindow(), -scrollDelta.width(), -scrollDelta.height(), 0, 0, 0, 0, SW_INVALIDATE);
        else
            InvalidateRect(containingWindow(), 0, true);
    }
}

WebCore::ScrollBarMode ScrollView::hScrollBarMode() const
{
    return m_data->hScrollBarMode;
}

WebCore::ScrollBarMode ScrollView::vScrollBarMode() const
{
    return m_data->vScrollBarMode;
}

void ScrollView::suppressScrollBars(bool suppressed, bool repaintOnSuppress)
{
    m_data->suppressScrollBars = suppressed;
    if (repaintOnSuppress)
        updateScrollBars(m_data->scrollOffset);
}

void ScrollView::setHScrollBarMode(ScrollBarMode newMode)
{
    if (m_data->hScrollBarMode != newMode) {
        m_data->hScrollBarMode = newMode;
        updateScrollBars(m_data->scrollOffset);
    }
}

void ScrollView::setVScrollBarMode(ScrollBarMode newMode)
{
    if (m_data->vScrollBarMode != newMode) {
        m_data->vScrollBarMode = newMode;
        updateScrollBars(m_data->scrollOffset);
    }
}

void ScrollView::setScrollBarsMode(ScrollBarMode newMode)
{
    m_data->hScrollBarMode = m_data->vScrollBarMode = newMode;
    updateScrollBars(m_data->scrollOffset);
}

void ScrollView::setStaticBackground(bool flag)
{
    m_data->hasStaticBackground = flag;
}

static int updateScrollInfo(ScrollView* view, short type, int current, int max, int pageSize)
{
    SCROLLINFO si;
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = 0;
    si.nMax   = max;
    si.nPage  = pageSize;
    si.nPos   = current;
    SetScrollInfo(view->containingWindow(), type, &si, TRUE);
    GetScrollInfo(view->containingWindow(), type, &si);
    return si.nPos;
}

void ScrollView::updateScrollBars(const IntPoint&)
{
    IntSize maxScrollPosition(contentsWidth(), contentsHeight());
    IntSize scroll = scrollOffset().shrunkTo(maxScrollPosition);
    scroll.clampNegativeToZero();

    m_data->scrollOffset =
        IntSize(updateScrollInfo(this, SB_HORZ, scroll.width(), contentsWidth() - 1, width()),
                updateScrollInfo(this, SB_VERT, scroll.height(), contentsHeight() - 1, height()));

    if (m_data->hScrollBarMode != ScrollBarAuto || m_data->suppressScrollBars)
        ShowScrollBar(containingWindow(), SB_HORZ, (m_data->hScrollBarMode != ScrollBarAlwaysOff) && !m_data->suppressScrollBars);
    if (m_data->vScrollBarMode != ScrollBarAuto || m_data->suppressScrollBars)
        ShowScrollBar(containingWindow(), SB_VERT, (m_data->vScrollBarMode != ScrollBarAlwaysOff) && !m_data->suppressScrollBars);
}

}
<commit_msg>Fix Win32 bustage.<commit_after>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 * Copyright (C) 2006 Justin Haygood <jhaygood@spsu.edu>.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "ScrollView.h"

#include <algorithm>
#include "FloatRect.h"
#include "IntRect.h"
#include <windows.h>

using namespace std;

namespace WebCore {

class ScrollView::ScrollViewPrivate {
public:
    ScrollViewPrivate()
        : hasStaticBackground(false)
        , suppressScrollBars(false)
        , vScrollBarMode(ScrollBarAuto)
        , hScrollBarMode(ScrollBarAuto)
    {
    }
    IntSize scrollOffset;
    IntSize contentsSize;
    bool hasStaticBackground;
    bool suppressScrollBars;
    ScrollBarMode vScrollBarMode;
    ScrollBarMode hScrollBarMode;
};

ScrollView::ScrollView()
    : m_data(new ScrollViewPrivate())
{
}

ScrollView::~ScrollView()
{
    delete m_data;
}

void ScrollView::updateContents(const IntRect& updateRect, bool now)
{
    IntRect adjustedDirtyRect(updateRect);
    adjustedDirtyRect.move(-m_data->scrollOffset);

    RECT dirtyRect = RECT(adjustedDirtyRect);
#if PAINT_FLASHING_DEBUG
    HDC dc = GetDC(containingWindow());
    FillRect(dc, &dirtyRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
    ReleaseDC(containingWindow(), dc);
#endif

    InvalidateRect(containingWindow(), &dirtyRect, true);
    if (now)
        UpdateWindow(containingWindow());
}

int ScrollView::visibleWidth() const
{
    RECT bounds;
    GetClientRect(containingWindow(), &bounds);
    return (bounds.right - bounds.left);
}

int ScrollView::visibleHeight() const
{
    RECT bounds;
    GetClientRect(containingWindow(), &bounds);
    return (bounds.bottom - bounds.top);
}

FloatRect ScrollView::visibleContentRect() const
{
    RECT bounds;
    GetClientRect(containingWindow(), &bounds);
    FloatRect contentRect = bounds;
    contentRect.move(m_data->scrollOffset);
    return contentRect;
}

void ScrollView::setContentsPos(int newX, int newY)
{
    int dx = newX - contentsX();
    int dy = newY - contentsY();
    scrollBy(dx, dy);
}

void ScrollView::resizeContents(int w,int h)
{
    IntSize newSize(w,h);
    if (m_data->contentsSize != newSize) {
        m_data->contentsSize = newSize;
        updateScrollBars(m_data->scrollOffset);
    }
}

int ScrollView::contentsX() const
{
    return scrollOffset().width();
}

int ScrollView::contentsY() const
{
    return scrollOffset().height();
}

int ScrollView::contentsWidth() const
{
    return m_data->contentsSize.width();
}

int ScrollView::contentsHeight() const
{
    return m_data->contentsSize.height();
}

IntPoint ScrollView::contentsToWindow(const IntPoint& point) const
{
    return point - scrollOffset();
}

IntPoint ScrollView::windowToContents(const IntPoint& point) const
{
    return point + scrollOffset();
}

IntSize ScrollView::scrollOffset() const
{
    return m_data->scrollOffset;
}

IntSize ScrollView::maximumScroll() const
{
    IntSize delta = m_data->contentsSize - m_data->scrollOffset;
    delta.clampNegativeToZero();
    return delta;
}

void ScrollView::scrollBy(int dx, int dy)
{
    IntSize scrollOffset = m_data->scrollOffset;
    IntSize maxScroll = maximumScroll();
    IntSize newScrollOffset = scrollOffset + IntSize(dx, dy);
    newScrollOffset.clampNegativeToZero();

    if (newScrollOffset != scrollOffset) {
        m_data->scrollOffset = newScrollOffset;
        updateScrollBars(m_data->scrollOffset);
        // ScrollBar updates can fail, so we check the final delta before scrolling
        IntSize scrollDelta = m_data->scrollOffset - scrollOffset;
        if (scrollDelta == IntSize())
            return;
        if (!m_data->hasStaticBackground)
            // FIXME: This could be made more efficient by passing a valid clip rect for only the document content.
            ScrollWindowEx(containingWindow(), -scrollDelta.width(), -scrollDelta.height(), 0, 0, 0, 0, SW_INVALIDATE);
        else
            InvalidateRect(containingWindow(), 0, true);
    }
}

WebCore::ScrollBarMode ScrollView::hScrollBarMode() const
{
    return m_data->hScrollBarMode;
}

WebCore::ScrollBarMode ScrollView::vScrollBarMode() const
{
    return m_data->vScrollBarMode;
}

void ScrollView::suppressScrollBars(bool suppressed, bool repaintOnSuppress)
{
    m_data->suppressScrollBars = suppressed;
    if (repaintOnSuppress)
        updateScrollBars(m_data->scrollOffset);
}

void ScrollView::setHScrollBarMode(ScrollBarMode newMode)
{
    if (m_data->hScrollBarMode != newMode) {
        m_data->hScrollBarMode = newMode;
        updateScrollBars(m_data->scrollOffset);
    }
}

void ScrollView::setVScrollBarMode(ScrollBarMode newMode)
{
    if (m_data->vScrollBarMode != newMode) {
        m_data->vScrollBarMode = newMode;
        updateScrollBars(m_data->scrollOffset);
    }
}

void ScrollView::setScrollBarsMode(ScrollBarMode newMode)
{
    m_data->hScrollBarMode = m_data->vScrollBarMode = newMode;
    updateScrollBars(m_data->scrollOffset);
}

void ScrollView::setStaticBackground(bool flag)
{
    m_data->hasStaticBackground = flag;
}

static int updateScrollInfo(ScrollView* view, short type, int current, int max, int pageSize)
{
    SCROLLINFO si;
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = 0;
    si.nMax   = max;
    si.nPage  = pageSize;
    si.nPos   = current;
    SetScrollInfo(view->containingWindow(), type, &si, TRUE);
    GetScrollInfo(view->containingWindow(), type, &si);
    return si.nPos;
}

void ScrollView::updateScrollBars(const IntPoint&)
{
    IntSize maxScrollPosition(contentsWidth(), contentsHeight());
    IntSize scroll = scrollOffset().shrunkTo(maxScrollPosition);
    scroll.clampNegativeToZero();

    m_data->scrollOffset =
        IntSize(updateScrollInfo(this, SB_HORZ, scroll.width(), contentsWidth() - 1, width()),
                updateScrollInfo(this, SB_VERT, scroll.height(), contentsHeight() - 1, height()));

    if (m_data->hScrollBarMode != ScrollBarAuto || m_data->suppressScrollBars)
        ShowScrollBar(containingWindow(), SB_HORZ, (m_data->hScrollBarMode != ScrollBarAlwaysOff) && !m_data->suppressScrollBars);
    if (m_data->vScrollBarMode != ScrollBarAuto || m_data->suppressScrollBars)
        ShowScrollBar(containingWindow(), SB_VERT, (m_data->vScrollBarMode != ScrollBarAlwaysOff) && !m_data->suppressScrollBars);
}

}
<|endoftext|>


<commit_before>//
// created by : Timothée Feuillet
// date: 2022-7-10
//
//
// Copyright (c) 2022 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#pragma once

#include <cstdint>
#include <utility>

namespace neam::ct
{
  static constexpr uint64_t combine(uint64_t a, uint64_t b)
  {
    return (a ^ (b + 0x9e3779b97f4a7c15 + (a << 6) + (a >> 2)));
  }
  static constexpr uint32_t combine(uint32_t a, uint32_t b)
  {
    return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2)));
  }

  static constexpr uint32_t fold32(uint64_t id)
  {
    return uint32_t(((id >> 32) ^ id) & 0xFFFFFFFF);
  }
  static constexpr uint32_t fold31(uint64_t id)
  {
    return uint32_t(((id >> 32) * id) & 0x7FFFFFFF);
  }
}

<commit_msg>Add bit scrambles from murmur<commit_after>//
// created by : Timothée Feuillet
// date: 2022-7-10
//
//
// Copyright (c) 2022 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#pragma once

#include <cstdint>
#include <utility>

namespace neam::ct
{
  static constexpr uint64_t combine(uint64_t a, uint64_t b)
  {
    return (a ^ (b + 0x9e3779b97f4a7c15 + (a << 6) + (a >> 2)));
  }
  static constexpr uint32_t combine(uint32_t a, uint32_t b)
  {
    return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2)));
  }

  static constexpr uint32_t fold32(uint64_t id)
  {
    return uint32_t(((id >> 32) ^ id) & 0xFFFFFFFF);
  }
  static constexpr uint32_t fold31(uint64_t id)
  {
    return uint32_t(((id >> 32) ^ id) & 0x7FFFFFFF);
  }

  static constexpr uint64_t murmur_scramble(uint64_t h)
  {
    h ^= h >> 33;
    h *= 0xff51afd7ed558ccd;
    h ^= h >> 33;
    h *= 0xc4ceb9fe1a85ec53;
    h ^= h >> 33;
    return h;
  }
  static constexpr uint32_t murmur_scramble(uint32_t h)
  {
    h ^= h >> 16;
    h *= 0x85ebca6b;
    h ^= h >> 13;
    h *= 0xc2b2ae35;
    h ^= h >> 16;
    return h;
  }
}

<|endoftext|>