<commit_before>/* This file is part of Zanshin Todo.

   Copyright 2008-2010 Kevin Ottens <ervin@kde.org>

   This program 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 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

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

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "actionlisteditor.h"

#if 0
#include <akonadi/item.h>
#include <akonadi/itemdeletejob.h>

#include <boost/shared_ptr.hpp>

#include <KDE/KCalCore/Todo>
#endif

#include <KDE/Akonadi/EntityTreeView>
#include <KDE/Akonadi/ItemCreateJob>

#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KConfigGroup>
#include <KDE/KDebug>
#include <kdescendantsproxymodel.h>
#include <KDE/KIcon>
#include <KDE/KLineEdit>
#include <KDE/KLocale>
#include <KDE/KPassivePopup>

#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtGui/QHBoxLayout>
#include <QtGui/QHeaderView>
#include <QtGui/QToolBar>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>

#include "actionlistcombobox.h"
#include "actionlistdelegate.h"
#include "actionlisteditorpage.h"
#include "modelstack.h"
#include "todomodel.h"
#if 0
#include "quickselectdialog.h"
#endif

ActionListEditor::ActionListEditor(ModelStack *models,
                                   QItemSelectionModel *projectSelection,
                                   QItemSelectionModel *categoriesSelection,
                                   KActionCollection *ac,
                                   QWidget *parent)
    : QWidget(parent),
      m_projectSelection(projectSelection),
      m_categoriesSelection(categoriesSelection)
{
    setLayout(new QVBoxLayout(this));

    m_stack = new QStackedWidget(this);
    layout()->addWidget(m_stack);
    layout()->setContentsMargins(0, 0, 0, 0);

    connect(projectSelection, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(onSideBarSelectionChanged(QModelIndex)));
    connect(categoriesSelection, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(onSideBarSelectionChanged(QModelIndex)));

    createPage(models->treeSelectionModel(projectSelection), models, Zanshin::ProjectMode);
    createPage(models->categoriesSelectionModel(categoriesSelection), models, Zanshin::CategoriesMode);

    QWidget *bottomBar = new QWidget(this);
    layout()->addWidget(bottomBar);
    bottomBar->setLayout(new QHBoxLayout(bottomBar));
    bottomBar->layout()->setContentsMargins(0, 0, 0, 0);

    m_addActionEdit = new KLineEdit(bottomBar);
    m_addActionEdit->installEventFilter(this);
    bottomBar->layout()->addWidget(m_addActionEdit);
    m_addActionEdit->setClickMessage(i18n("Type and press enter to add an action"));
    m_addActionEdit->setClearButtonShown(true);
    connect(m_addActionEdit, SIGNAL(returnPressed()),
            this, SLOT(onAddActionRequested()));

    m_comboBox = new ActionListComboBox(bottomBar);
    m_comboBox->view()->setTextElideMode(Qt::ElideLeft);
    m_comboBox->setMinimumContentsLength(20);
    m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);

    KDescendantsProxyModel *descendantProxyModel = new KDescendantsProxyModel(m_comboBox);
    descendantProxyModel->setSourceModel(models->collectionsModel());
    descendantProxyModel->setDisplayAncestorData(true);

    m_comboBox->setModel(descendantProxyModel);
    bottomBar->layout()->addWidget(m_comboBox);

    setupActions(ac);

    QToolBar *toolBar = new QToolBar(bottomBar);
    toolBar->setIconSize(QSize(16, 16));
    bottomBar->layout()->addWidget(toolBar);
    toolBar->addAction(m_cancelAdd);

    m_cancelAdd->setEnabled(false);

    updateActions(QModelIndex());
    setMode(Zanshin::ProjectMode);
}

void ActionListEditor::setMode(Zanshin::ApplicationMode mode)
{
    switch (mode) {
    case Zanshin::ProjectMode:
        m_stack->setCurrentIndex(0);
        onSideBarSelectionChanged(m_projectSelection->currentIndex());
        break;
    case Zanshin::CategoriesMode:
        m_stack->setCurrentIndex(1);
        onSideBarSelectionChanged(m_categoriesSelection->currentIndex());
        break;
    }
}

void ActionListEditor::onSideBarSelectionChanged(const QModelIndex &index)
{
    int type = index.data(TodoModel::ItemTypeRole).toInt();

    m_comboBox->setVisible(type == TodoModel::Inbox
                        || type == TodoModel::Category
                        || type == TodoModel::CategoryRoot);
}

void ActionListEditor::createPage(QAbstractItemModel *model, ModelStack *models, Zanshin::ApplicationMode mode)
{
    ActionListEditorPage *page = new ActionListEditorPage(model, models, mode, m_stack);

    connect(page->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(updateActions(QModelIndex)));

    m_stack->addWidget(page);
}

void ActionListEditor::setupActions(KActionCollection *ac)
{
    m_add = ac->addAction("editor_add_action", this, SLOT(focusActionEdit()));
    m_add->setText(i18n("New Action"));
    m_add->setIcon(KIcon("list-add"));
    m_add->setShortcut(Qt::CTRL | Qt::Key_N);

    m_cancelAdd = ac->addAction("editor_cancel_action", m_stack, SLOT(setFocus()));
    connect(m_cancelAdd, SIGNAL(activated()), m_addActionEdit, SLOT(clear()));
    m_cancelAdd->setText(i18n("Cancel New Action"));
    m_cancelAdd->setIcon(KIcon("edit-undo"));
    m_cancelAdd->setShortcut(Qt::Key_Escape);

    m_remove = ac->addAction("editor_remove_action", this, SLOT(onRemoveAction()));
    m_remove->setText(i18n("Remove Action"));
    m_remove->setIcon(KIcon("list-remove"));
    m_remove->setShortcut(Qt::Key_Delete);

    m_move = ac->addAction("editor_move_action", this, SLOT(onMoveAction()));
    m_move->setText(i18n("Move Action..."));
    m_move->setShortcut(Qt::Key_M);
}

void ActionListEditor::updateActions(const QModelIndex &index)
{
    if (!index.isValid()) {
        m_remove->setEnabled(false);
        m_move->setEnabled(false);
    } else {
        m_remove->setEnabled(true);
        m_move->setEnabled(true);
    }
}

void ActionListEditor::onAddActionRequested()
{
    QString summary = m_addActionEdit->text().trimmed();
    m_addActionEdit->setText(QString());

    if (summary.isEmpty()) return;

    QModelIndex current = currentPage()->selectionModel()->currentIndex();

    if (!current.isValid()) {
        kWarning() << "Oops, nothing selected in the list!";
        return;
    }

    int type = current.data(TodoModel::ItemTypeRole).toInt();

    while (current.isValid() && type==TodoModel::StandardTodo) {
        current = current.parent();
        type = current.data(TodoModel::ItemTypeRole).toInt();
    }

    Akonadi::Collection collection;
    QString parentUid;
    QString category;

    switch (type) {
    case TodoModel::StandardTodo:
        kFatal() << "Can't possibly happen!";
        break;

    case TodoModel::ProjectTodo:
        parentUid = current.data(TodoModel::UidRole).toString();
        collection = current.data(Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Collection:
        collection = current.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Category:
        category = current.data(Qt::EditRole).toString();
        // fallthrough
    case TodoModel::Inbox:
    case TodoModel::CategoryRoot:
        QModelIndex collectionIndex = m_comboBox->model()->index( m_comboBox->currentIndex(), 0 );
        collection = collectionIndex.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
        break;
    }

    KCalCore::Todo::Ptr todo(new KCalCore::Todo);
    todo->setSummary(summary);
    if (!parentUid.isEmpty()) {
        todo->setRelatedTo(parentUid);
    }
    if (!category.isEmpty()) {
        todo->setCategories(category);
    }

    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<KCalCore::Todo::Ptr>(todo);

    new Akonadi::ItemCreateJob(item, collection);
}

void ActionListEditor::onRemoveAction()
{
#if 0
    QModelIndex current = m_view->currentIndex();

    if (m_model->rowCount(current)>0) {
        return;
    }

    Akonadi::Item item;
    QAbstractItemModel *source = m_model->sourceModel();

    TodoFlatModel *flat = dynamic_cast<TodoFlatModel*>(source);
    if (flat != 0) {
        item = flat->itemForIndex(m_model->mapToSource(current));
    }

    TodoTreeModel *tree = dynamic_cast<TodoTreeModel*>(source);
    if (tree != 0) {
        item = tree->itemForIndex(m_model->mapToSource(current));
    }

    TodoCategoriesModel *categories = dynamic_cast<TodoCategoriesModel*>(source);
    if (categories != 0) {
        item = categories->itemForIndex(m_model->mapToSource(current));
    }

    if (!item.isValid()) {
        return;
    }

    new Akonadi::ItemDeleteJob(item, this);
#endif
}

void ActionListEditor::onMoveAction()
{
#if 0
    QModelIndex current = m_view->currentIndex();

    if (m_model->rowCount(current)>0) {
        return;
    }

    QAbstractItemModel *source = m_model->sourceModel();
    QModelIndex movedIndex;

    TodoFlatModel *flat = dynamic_cast<TodoFlatModel*>(source);
    if (flat != 0) {
        movedIndex = m_model->mapToSource(current);
    }

    TodoTreeModel *tree = dynamic_cast<TodoTreeModel*>(source);
    if (tree != 0) {
        movedIndex = m_model->mapToSource(current);
    }

    TodoCategoriesModel *categories = dynamic_cast<TodoCategoriesModel*>(source);
    if (categories != 0) {
        movedIndex = m_model->mapToSource(current);
    }

    if (!movedIndex.isValid()) {
        return;
    }

    QuickSelectDialog::Mode mode = QuickSelectDialog::ProjectMode;
    if (m_model->mode()==ActionListModel::NoContextMode
     || m_model->mode()==ActionListModel::ContextMode) {
        mode = QuickSelectDialog::ContextMode;
    }

    QuickSelectDialog dlg(this, mode,
                          QuickSelectDialog::MoveAction);
    if (dlg.exec()==QDialog::Accepted) {
        QString selectedId = dlg.selectedId();
        if (mode==QuickSelectDialog::ProjectMode) {
            QModelIndex index = movedIndex.sibling(movedIndex.row(), TodoFlatModel::ParentRemoteId);
            source->setData(index, selectedId);
        } else {
            QModelIndex index = movedIndex.sibling(movedIndex.row(), TodoFlatModel::Categories);
            source->setData(index, selectedId);
        }
    }
#endif
}

void ActionListEditor::focusActionEdit()
{
    QPoint pos = m_addActionEdit->geometry().topLeft();
    pos = m_addActionEdit->parentWidget()->mapToGlobal(pos);

    KPassivePopup *popup = KPassivePopup::message(i18n("Type and press enter to add an action"), m_addActionEdit);
    popup->move(pos-QPoint(0, popup->height()));
    m_addActionEdit->setFocus();
}

bool ActionListEditor::eventFilter(QObject *watched, QEvent *event)
{
    if (watched==m_addActionEdit) {
        if (event->type()==QEvent::FocusIn) {
            m_cancelAdd->setEnabled(true);
        } else  if (event->type()==QEvent::FocusOut) {
            m_cancelAdd->setEnabled(false);
        }
    }

    return QWidget::eventFilter(watched, event);
}

void ActionListEditor::saveColumnsState(KConfigGroup &config) const
{
    page(0)->saveColumnsState(config, "ProjectHeaderState");
    page(1)->saveColumnsState(config, "CategoriesHeaderState");
}

void ActionListEditor::restoreColumnsState(const KConfigGroup &config)
{
    page(0)->restoreColumnsState(config, "ProjectHeaderState");
    page(1)->restoreColumnsState(config, "CategoriesHeaderState");
}

ActionListEditorPage *ActionListEditor::currentPage() const
{
    return static_cast<ActionListEditorPage*>(m_stack->currentWidget());
}

ActionListEditorPage *ActionListEditor::page(int idx) const
{
    return static_cast<ActionListEditorPage*>(m_stack->widget(idx));
}

void ActionListEditor::hideColumns()
{
    for (int i = 0; i < m_stack->count(); ++i) {
       ActionListEditorPage *page = static_cast<ActionListEditorPage*>(m_stack->widget(i));
       if (page->mode() == Zanshin::ProjectMode) {
           page->hideColumn(1);
       } else {
           page->hideColumn(2);
       }
    }
}
<commit_msg>Reenable removing standard todos.<commit_after>/* This file is part of Zanshin Todo.

   Copyright 2008-2010 Kevin Ottens <ervin@kde.org>

   This program 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 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

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

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "actionlisteditor.h"

#if 0
#include <akonadi/item.h>

#include <boost/shared_ptr.hpp>

#include <KDE/KCalCore/Todo>
#endif

#include <KDE/Akonadi/EntityTreeView>
#include <KDE/Akonadi/ItemCreateJob>
#include <KDE/Akonadi/ItemDeleteJob>

#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KConfigGroup>
#include <KDE/KDebug>
#include <kdescendantsproxymodel.h>
#include <KDE/KIcon>
#include <KDE/KLineEdit>
#include <KDE/KLocale>
#include <KDE/KPassivePopup>

#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtGui/QHBoxLayout>
#include <QtGui/QHeaderView>
#include <QtGui/QToolBar>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>

#include "actionlistcombobox.h"
#include "actionlistdelegate.h"
#include "actionlisteditorpage.h"
#include "modelstack.h"
#include "todomodel.h"
#if 0
#include "quickselectdialog.h"
#endif

ActionListEditor::ActionListEditor(ModelStack *models,
                                   QItemSelectionModel *projectSelection,
                                   QItemSelectionModel *categoriesSelection,
                                   KActionCollection *ac,
                                   QWidget *parent)
    : QWidget(parent),
      m_projectSelection(projectSelection),
      m_categoriesSelection(categoriesSelection)
{
    setLayout(new QVBoxLayout(this));

    m_stack = new QStackedWidget(this);
    layout()->addWidget(m_stack);
    layout()->setContentsMargins(0, 0, 0, 0);

    connect(projectSelection, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(onSideBarSelectionChanged(QModelIndex)));
    connect(categoriesSelection, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(onSideBarSelectionChanged(QModelIndex)));

    createPage(models->treeSelectionModel(projectSelection), models, Zanshin::ProjectMode);
    createPage(models->categoriesSelectionModel(categoriesSelection), models, Zanshin::CategoriesMode);

    QWidget *bottomBar = new QWidget(this);
    layout()->addWidget(bottomBar);
    bottomBar->setLayout(new QHBoxLayout(bottomBar));
    bottomBar->layout()->setContentsMargins(0, 0, 0, 0);

    m_addActionEdit = new KLineEdit(bottomBar);
    m_addActionEdit->installEventFilter(this);
    bottomBar->layout()->addWidget(m_addActionEdit);
    m_addActionEdit->setClickMessage(i18n("Type and press enter to add an action"));
    m_addActionEdit->setClearButtonShown(true);
    connect(m_addActionEdit, SIGNAL(returnPressed()),
            this, SLOT(onAddActionRequested()));

    m_comboBox = new ActionListComboBox(bottomBar);
    m_comboBox->view()->setTextElideMode(Qt::ElideLeft);
    m_comboBox->setMinimumContentsLength(20);
    m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);

    KDescendantsProxyModel *descendantProxyModel = new KDescendantsProxyModel(m_comboBox);
    descendantProxyModel->setSourceModel(models->collectionsModel());
    descendantProxyModel->setDisplayAncestorData(true);

    m_comboBox->setModel(descendantProxyModel);
    bottomBar->layout()->addWidget(m_comboBox);

    setupActions(ac);

    QToolBar *toolBar = new QToolBar(bottomBar);
    toolBar->setIconSize(QSize(16, 16));
    bottomBar->layout()->addWidget(toolBar);
    toolBar->addAction(m_cancelAdd);

    m_cancelAdd->setEnabled(false);

    updateActions(QModelIndex());
    setMode(Zanshin::ProjectMode);
}

void ActionListEditor::setMode(Zanshin::ApplicationMode mode)
{
    switch (mode) {
    case Zanshin::ProjectMode:
        m_stack->setCurrentIndex(0);
        onSideBarSelectionChanged(m_projectSelection->currentIndex());
        break;
    case Zanshin::CategoriesMode:
        m_stack->setCurrentIndex(1);
        onSideBarSelectionChanged(m_categoriesSelection->currentIndex());
        break;
    }
}

void ActionListEditor::onSideBarSelectionChanged(const QModelIndex &index)
{
    int type = index.data(TodoModel::ItemTypeRole).toInt();

    m_comboBox->setVisible(type == TodoModel::Inbox
                        || type == TodoModel::Category
                        || type == TodoModel::CategoryRoot);
}

void ActionListEditor::createPage(QAbstractItemModel *model, ModelStack *models, Zanshin::ApplicationMode mode)
{
    ActionListEditorPage *page = new ActionListEditorPage(model, models, mode, m_stack);

    connect(page->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
            this, SLOT(updateActions(QModelIndex)));

    m_stack->addWidget(page);
}

void ActionListEditor::setupActions(KActionCollection *ac)
{
    m_add = ac->addAction("editor_add_action", this, SLOT(focusActionEdit()));
    m_add->setText(i18n("New Action"));
    m_add->setIcon(KIcon("list-add"));
    m_add->setShortcut(Qt::CTRL | Qt::Key_N);

    m_cancelAdd = ac->addAction("editor_cancel_action", m_stack, SLOT(setFocus()));
    connect(m_cancelAdd, SIGNAL(activated()), m_addActionEdit, SLOT(clear()));
    m_cancelAdd->setText(i18n("Cancel New Action"));
    m_cancelAdd->setIcon(KIcon("edit-undo"));
    m_cancelAdd->setShortcut(Qt::Key_Escape);

    m_remove = ac->addAction("editor_remove_action", this, SLOT(onRemoveAction()));
    m_remove->setText(i18n("Remove Action"));
    m_remove->setIcon(KIcon("list-remove"));
    m_remove->setShortcut(Qt::Key_Delete);

    m_move = ac->addAction("editor_move_action", this, SLOT(onMoveAction()));
    m_move->setText(i18n("Move Action..."));
    m_move->setShortcut(Qt::Key_M);
}

void ActionListEditor::updateActions(const QModelIndex &index)
{
    int type = index.data(TodoModel::ItemTypeRole).toInt();

    m_remove->setEnabled(index.isValid() && (type==TodoModel::StandardTodo));
    m_move->setEnabled(index.isValid() && (type==TodoModel::StandardTodo));
}

void ActionListEditor::onAddActionRequested()
{
    QString summary = m_addActionEdit->text().trimmed();
    m_addActionEdit->setText(QString());

    if (summary.isEmpty()) return;

    QModelIndex current = currentPage()->selectionModel()->currentIndex();

    if (!current.isValid()) {
        kWarning() << "Oops, nothing selected in the list!";
        return;
    }

    int type = current.data(TodoModel::ItemTypeRole).toInt();

    while (current.isValid() && type==TodoModel::StandardTodo) {
        current = current.parent();
        type = current.data(TodoModel::ItemTypeRole).toInt();
    }

    Akonadi::Collection collection;
    QString parentUid;
    QString category;

    switch (type) {
    case TodoModel::StandardTodo:
        kFatal() << "Can't possibly happen!";
        break;

    case TodoModel::ProjectTodo:
        parentUid = current.data(TodoModel::UidRole).toString();
        collection = current.data(Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Collection:
        collection = current.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Category:
        category = current.data(Qt::EditRole).toString();
        // fallthrough
    case TodoModel::Inbox:
    case TodoModel::CategoryRoot:
        QModelIndex collectionIndex = m_comboBox->model()->index( m_comboBox->currentIndex(), 0 );
        collection = collectionIndex.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
        break;
    }

    KCalCore::Todo::Ptr todo(new KCalCore::Todo);
    todo->setSummary(summary);
    if (!parentUid.isEmpty()) {
        todo->setRelatedTo(parentUid);
    }
    if (!category.isEmpty()) {
        todo->setCategories(category);
    }

    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<KCalCore::Todo::Ptr>(todo);

    new Akonadi::ItemCreateJob(item, collection);
}

void ActionListEditor::onRemoveAction()
{
    QModelIndex current = currentPage()->selectionModel()->currentIndex();
    int type = current.data(TodoModel::ItemTypeRole).toInt();

    if (!current.isValid() || type!=TodoModel::StandardTodo) {
        return;
    }

    Akonadi::Item item = current.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
    if (!item.isValid()) {
        return;
    }

    new Akonadi::ItemDeleteJob(item, this);
}

void ActionListEditor::onMoveAction()
{
#if 0
    QModelIndex current = m_view->currentIndex();

    if (m_model->rowCount(current)>0) {
        return;
    }

    QAbstractItemModel *source = m_model->sourceModel();
    QModelIndex movedIndex;

    TodoFlatModel *flat = dynamic_cast<TodoFlatModel*>(source);
    if (flat != 0) {
        movedIndex = m_model->mapToSource(current);
    }

    TodoTreeModel *tree = dynamic_cast<TodoTreeModel*>(source);
    if (tree != 0) {
        movedIndex = m_model->mapToSource(current);
    }

    TodoCategoriesModel *categories = dynamic_cast<TodoCategoriesModel*>(source);
    if (categories != 0) {
        movedIndex = m_model->mapToSource(current);
    }

    if (!movedIndex.isValid()) {
        return;
    }

    QuickSelectDialog::Mode mode = QuickSelectDialog::ProjectMode;
    if (m_model->mode()==ActionListModel::NoContextMode
     || m_model->mode()==ActionListModel::ContextMode) {
        mode = QuickSelectDialog::ContextMode;
    }

    QuickSelectDialog dlg(this, mode,
                          QuickSelectDialog::MoveAction);
    if (dlg.exec()==QDialog::Accepted) {
        QString selectedId = dlg.selectedId();
        if (mode==QuickSelectDialog::ProjectMode) {
            QModelIndex index = movedIndex.sibling(movedIndex.row(), TodoFlatModel::ParentRemoteId);
            source->setData(index, selectedId);
        } else {
            QModelIndex index = movedIndex.sibling(movedIndex.row(), TodoFlatModel::Categories);
            source->setData(index, selectedId);
        }
    }
#endif
}

void ActionListEditor::focusActionEdit()
{
    QPoint pos = m_addActionEdit->geometry().topLeft();
    pos = m_addActionEdit->parentWidget()->mapToGlobal(pos);

    KPassivePopup *popup = KPassivePopup::message(i18n("Type and press enter to add an action"), m_addActionEdit);
    popup->move(pos-QPoint(0, popup->height()));
    m_addActionEdit->setFocus();
}

bool ActionListEditor::eventFilter(QObject *watched, QEvent *event)
{
    if (watched==m_addActionEdit) {
        if (event->type()==QEvent::FocusIn) {
            m_cancelAdd->setEnabled(true);
        } else  if (event->type()==QEvent::FocusOut) {
            m_cancelAdd->setEnabled(false);
        }
    }

    return QWidget::eventFilter(watched, event);
}

void ActionListEditor::saveColumnsState(KConfigGroup &config) const
{
    page(0)->saveColumnsState(config, "ProjectHeaderState");
    page(1)->saveColumnsState(config, "CategoriesHeaderState");
}

void ActionListEditor::restoreColumnsState(const KConfigGroup &config)
{
    page(0)->restoreColumnsState(config, "ProjectHeaderState");
    page(1)->restoreColumnsState(config, "CategoriesHeaderState");
}

ActionListEditorPage *ActionListEditor::currentPage() const
{
    return static_cast<ActionListEditorPage*>(m_stack->currentWidget());
}

ActionListEditorPage *ActionListEditor::page(int idx) const
{
    return static_cast<ActionListEditorPage*>(m_stack->widget(idx));
}

void ActionListEditor::hideColumns()
{
    for (int i = 0; i < m_stack->count(); ++i) {
       ActionListEditorPage *page = static_cast<ActionListEditorPage*>(m_stack->widget(i));
       if (page->mode() == Zanshin::ProjectMode) {
           page->hideColumn(1);
       } else {
           page->hideColumn(2);
       }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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 "cpu/rubytest/RubyTester.hh"
#include "mem/physical.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/system/RubyPort.hh"

RubyPort::RubyPort(const Params *p)
    : MemObject(p)
{
    m_version = p->version;
    assert(m_version != -1);

    physmem = p->physmem;

    m_controller = NULL;
    m_mandatory_q_ptr = NULL;

    m_request_cnt = 0;
    pio_port = NULL;
    physMemPort = NULL;
}

void
RubyPort::init()
{
    assert(m_controller != NULL);
    m_mandatory_q_ptr = m_controller->getMandatoryQueue();
}

Port *
RubyPort::getPort(const std::string &if_name, int idx)
{
    if (if_name == "port") {
        return new M5Port(csprintf("%s-port%d", name(), idx), this);
    }

    if (if_name == "pio_port") {
        // ensure there is only one pio port
        assert(pio_port == NULL);

        pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this);

        return pio_port;
    }

    if (if_name == "physMemPort") {
        // RubyPort should only have one port to physical memory
        assert (physMemPort == NULL);

        physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this);

        return physMemPort;
    }

    if (if_name == "functional") {
        // Calls for the functional port only want to access
        // functional memory.  Therefore, directly pass these calls
        // ports to physmem.
        assert(physmem != NULL);
        return physmem->getPort(if_name, idx);
    }

    return NULL;
}

RubyPort::PioPort::PioPort(const std::string &_name,
                           RubyPort *_port)
    : SimpleTimingPort(_name, _port)
{
    DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name);
    ruby_port = _port;
}

RubyPort::M5Port::M5Port(const std::string &_name,
                         RubyPort *_port)
    : SimpleTimingPort(_name, _port)
{
    DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name);
    ruby_port = _port;
}

Tick
RubyPort::PioPort::recvAtomic(PacketPtr pkt)
{
    panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
    return 0;
}

Tick
RubyPort::M5Port::recvAtomic(PacketPtr pkt)
{
    panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
    return 0;
}

bool
RubyPort::PioPort::recvTiming(PacketPtr pkt)
{
    // In FS mode, ruby memory will receive pio responses from devices
    // and it must forward these responses back to the particular CPU.
    DPRINTF(MemoryAccess,  "Pio response for address %#x\n", pkt->getAddr());

    assert(pkt->isResponse());

    // First we must retrieve the request port from the sender State
    RubyPort::SenderState *senderState =
      safe_cast<RubyPort::SenderState *>(pkt->senderState);
    M5Port *port = senderState->port;
    assert(port != NULL);

    // pop the sender state from the packet
    pkt->senderState = senderState->saved;
    delete senderState;

    port->sendTiming(pkt);

    return true;
}

bool
RubyPort::M5Port::recvTiming(PacketPtr pkt)
{
    DPRINTF(MemoryAccess,
            "Timing access caught for address %#x\n", pkt->getAddr());

    //dsm: based on SimpleTimingPort::recvTiming(pkt);

    // The received packets should only be M5 requests, which should never
    // get nacked.  There used to be code to hanldle nacks here, but
    // I'm pretty sure it didn't work correctly with the drain code,
    // so that would need to be fixed if we ever added it back.
    assert(pkt->isRequest());

    if (pkt->memInhibitAsserted()) {
        warn("memInhibitAsserted???");
        // snooper will supply based on copy of packet
        // still target's responsibility to delete packet
        delete pkt;
        return true;
    }

    // Save the port in the sender state object to be used later to
    // route the response
    pkt->senderState = new SenderState(this, pkt->senderState);

    // Check for pio requests and directly send them to the dedicated
    // pio port.
    if (!isPhysMemAddress(pkt->getAddr())) {
        assert(ruby_port->pio_port != NULL);
        DPRINTF(MemoryAccess,
                "Request for address 0x%#x is assumed to be a pio request\n",
                pkt->getAddr());

        return ruby_port->pio_port->sendTiming(pkt);
    }

    // For DMA and CPU requests, translate them to ruby requests before
    // sending them to our assigned ruby port.
    RubyRequestType type = RubyRequestType_NULL;

    // If valid, copy the pc to the ruby request
    Addr pc = 0;
    if (pkt->req->hasPC()) {
        pc = pkt->req->getPC();
    }

    if (pkt->isLLSC()) {
        if (pkt->isWrite()) {
            DPRINTF(MemoryAccess, "Issuing SC\n");
            type = RubyRequestType_Locked_Write;
        } else {
            DPRINTF(MemoryAccess, "Issuing LL\n");
            assert(pkt->isRead());
            type = RubyRequestType_Locked_Read;
        }
    } else {
        if (pkt->isRead()) {
            if (pkt->req->isInstFetch()) {
                type = RubyRequestType_IFETCH;
            } else {
                type = RubyRequestType_LD;
            }
        } else if (pkt->isWrite()) {
            type = RubyRequestType_ST;
        } else if (pkt->isReadWrite()) {
            // Fix me.  This conditional will never be executed
            // because isReadWrite() is just an OR of isRead() and
            // isWrite().  Furthermore, just because the packet is a
            // read/write request does not necessary mean it is a
            // read-modify-write atomic operation.
            type = RubyRequestType_RMW_Write;
        } else {
            panic("Unsupported ruby packet type\n");
        }
    }

    RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
                             pkt->getSize(), pc, type,
                             RubyAccessMode_Supervisor, pkt);

    // Submit the ruby request
    RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);

    // If the request successfully issued then we should return true.
    // Otherwise, we need to delete the senderStatus we just created and return
    // false.
    if (requestStatus == RequestStatus_Issued) {
        return true;
    }

    DPRINTF(MemoryAccess,
            "Request for address #x did not issue because %s\n",
            pkt->getAddr(), RequestStatus_to_string(requestStatus));

    SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
    pkt->senderState = senderState->saved;
    delete senderState;
    return false;
}

void
RubyPort::ruby_hit_callback(PacketPtr pkt)
{
    // Retrieve the request port from the sender State
    RubyPort::SenderState *senderState =
        safe_cast<RubyPort::SenderState *>(pkt->senderState);
    M5Port *port = senderState->port;
    assert(port != NULL);

    // pop the sender state from the packet
    pkt->senderState = senderState->saved;
    delete senderState;

    port->hitCallback(pkt);
}

void
RubyPort::M5Port::hitCallback(PacketPtr pkt)
{
    bool needsResponse = pkt->needsResponse();

    //
    // All responses except failed SC operations access M5 physical memory
    //
    bool accessPhysMem = true;

    if (pkt->isLLSC()) {
        if (pkt->isWrite()) {
            if (pkt->req->getExtraData() != 0) {
                //
                // Successful SC packets convert to normal writes
                //
                pkt->convertScToWrite();
            } else {
                //
                // Failed SC packets don't access physical memory and thus
                // the RubyPort itself must convert it to a response.
                //
                accessPhysMem = false;
                pkt->makeAtomicResponse();
            }
        } else {
            //
            // All LL packets convert to normal loads so that M5 PhysMem does
            // not lock the blocks.
            //
            pkt->convertLlToRead();
        }
    }
    DPRINTF(MemoryAccess, "Hit callback needs response %d\n", needsResponse);

    if (accessPhysMem) {
        ruby_port->physMemPort->sendAtomic(pkt);
    }

    // turn packet around to go back to requester if response expected
    if (needsResponse) {
        // sendAtomic() should already have turned packet into
        // atomic response
        assert(pkt->isResponse());
        DPRINTF(MemoryAccess, "Sending packet back over port\n");
        sendTiming(pkt);
    } else {
        delete pkt;
    }
    DPRINTF(MemoryAccess, "Hit callback done!\n");
}

bool
RubyPort::M5Port::sendTiming(PacketPtr pkt)
{
    schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
    return true;
}

bool
RubyPort::PioPort::sendTiming(PacketPtr pkt)
{
    schedSendTiming(pkt, curTick + 1); //minimum latency, must be > 0
    return true;
}

bool
RubyPort::M5Port::isPhysMemAddress(Addr addr)
{
    AddrRangeList physMemAddrList;
    bool snoop = false;
    ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
    for (AddrRangeIter iter = physMemAddrList.begin();
         iter != physMemAddrList.end();
         iter++) {
        if (addr >= iter->start && addr <= iter->end) {
            DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n",
                    iter->start, iter->end);
            return true;
        }
    }
    return false;
}
<commit_msg>ruby: Fixed RubyPort sendTiming callbacks<commit_after>/*
 * Copyright (c) 2009 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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 "cpu/rubytest/RubyTester.hh"
#include "mem/physical.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/system/RubyPort.hh"

RubyPort::RubyPort(const Params *p)
    : MemObject(p)
{
    m_version = p->version;
    assert(m_version != -1);

    physmem = p->physmem;

    m_controller = NULL;
    m_mandatory_q_ptr = NULL;

    m_request_cnt = 0;
    pio_port = NULL;
    physMemPort = NULL;
}

void
RubyPort::init()
{
    assert(m_controller != NULL);
    m_mandatory_q_ptr = m_controller->getMandatoryQueue();
}

Port *
RubyPort::getPort(const std::string &if_name, int idx)
{
    if (if_name == "port") {
        return new M5Port(csprintf("%s-port%d", name(), idx), this);
    }

    if (if_name == "pio_port") {
        // ensure there is only one pio port
        assert(pio_port == NULL);

        pio_port = new PioPort(csprintf("%s-pio-port%d", name(), idx), this);

        return pio_port;
    }

    if (if_name == "physMemPort") {
        // RubyPort should only have one port to physical memory
        assert (physMemPort == NULL);

        physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this);

        return physMemPort;
    }

    if (if_name == "functional") {
        // Calls for the functional port only want to access
        // functional memory.  Therefore, directly pass these calls
        // ports to physmem.
        assert(physmem != NULL);
        return physmem->getPort(if_name, idx);
    }

    return NULL;
}

RubyPort::PioPort::PioPort(const std::string &_name,
                           RubyPort *_port)
    : SimpleTimingPort(_name, _port)
{
    DPRINTF(Ruby, "creating port to ruby sequencer to cpu %s\n", _name);
    ruby_port = _port;
}

RubyPort::M5Port::M5Port(const std::string &_name,
                         RubyPort *_port)
    : SimpleTimingPort(_name, _port)
{
    DPRINTF(Ruby, "creating port from ruby sequcner to cpu %s\n", _name);
    ruby_port = _port;
}

Tick
RubyPort::PioPort::recvAtomic(PacketPtr pkt)
{
    panic("RubyPort::PioPort::recvAtomic() not implemented!\n");
    return 0;
}

Tick
RubyPort::M5Port::recvAtomic(PacketPtr pkt)
{
    panic("RubyPort::M5Port::recvAtomic() not implemented!\n");
    return 0;
}

bool
RubyPort::PioPort::recvTiming(PacketPtr pkt)
{
    // In FS mode, ruby memory will receive pio responses from devices
    // and it must forward these responses back to the particular CPU.
    DPRINTF(MemoryAccess,  "Pio response for address %#x\n", pkt->getAddr());

    assert(pkt->isResponse());

    // First we must retrieve the request port from the sender State
    RubyPort::SenderState *senderState =
      safe_cast<RubyPort::SenderState *>(pkt->senderState);
    M5Port *port = senderState->port;
    assert(port != NULL);

    // pop the sender state from the packet
    pkt->senderState = senderState->saved;
    delete senderState;

    port->sendTiming(pkt);

    return true;
}

bool
RubyPort::M5Port::recvTiming(PacketPtr pkt)
{
    DPRINTF(MemoryAccess,
            "Timing access caught for address %#x\n", pkt->getAddr());

    //dsm: based on SimpleTimingPort::recvTiming(pkt);

    // The received packets should only be M5 requests, which should never
    // get nacked.  There used to be code to hanldle nacks here, but
    // I'm pretty sure it didn't work correctly with the drain code,
    // so that would need to be fixed if we ever added it back.
    assert(pkt->isRequest());

    if (pkt->memInhibitAsserted()) {
        warn("memInhibitAsserted???");
        // snooper will supply based on copy of packet
        // still target's responsibility to delete packet
        delete pkt;
        return true;
    }

    // Save the port in the sender state object to be used later to
    // route the response
    pkt->senderState = new SenderState(this, pkt->senderState);

    // Check for pio requests and directly send them to the dedicated
    // pio port.
    if (!isPhysMemAddress(pkt->getAddr())) {
        assert(ruby_port->pio_port != NULL);
        DPRINTF(MemoryAccess,
                "Request for address 0x%#x is assumed to be a pio request\n",
                pkt->getAddr());

        return ruby_port->pio_port->sendTiming(pkt);
    }

    // For DMA and CPU requests, translate them to ruby requests before
    // sending them to our assigned ruby port.
    RubyRequestType type = RubyRequestType_NULL;

    // If valid, copy the pc to the ruby request
    Addr pc = 0;
    if (pkt->req->hasPC()) {
        pc = pkt->req->getPC();
    }

    if (pkt->isLLSC()) {
        if (pkt->isWrite()) {
            DPRINTF(MemoryAccess, "Issuing SC\n");
            type = RubyRequestType_Locked_Write;
        } else {
            DPRINTF(MemoryAccess, "Issuing LL\n");
            assert(pkt->isRead());
            type = RubyRequestType_Locked_Read;
        }
    } else {
        if (pkt->isRead()) {
            if (pkt->req->isInstFetch()) {
                type = RubyRequestType_IFETCH;
            } else {
                type = RubyRequestType_LD;
            }
        } else if (pkt->isWrite()) {
            type = RubyRequestType_ST;
        } else if (pkt->isReadWrite()) {
            // Fix me.  This conditional will never be executed
            // because isReadWrite() is just an OR of isRead() and
            // isWrite().  Furthermore, just because the packet is a
            // read/write request does not necessary mean it is a
            // read-modify-write atomic operation.
            type = RubyRequestType_RMW_Write;
        } else {
            panic("Unsupported ruby packet type\n");
        }
    }

    RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
                             pkt->getSize(), pc, type,
                             RubyAccessMode_Supervisor, pkt);

    // Submit the ruby request
    RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);

    // If the request successfully issued then we should return true.
    // Otherwise, we need to delete the senderStatus we just created and return
    // false.
    if (requestStatus == RequestStatus_Issued) {
        return true;
    }

    DPRINTF(MemoryAccess,
            "Request for address #x did not issue because %s\n",
            pkt->getAddr(), RequestStatus_to_string(requestStatus));

    SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
    pkt->senderState = senderState->saved;
    delete senderState;
    return false;
}

void
RubyPort::ruby_hit_callback(PacketPtr pkt)
{
    // Retrieve the request port from the sender State
    RubyPort::SenderState *senderState =
        safe_cast<RubyPort::SenderState *>(pkt->senderState);
    M5Port *port = senderState->port;
    assert(port != NULL);

    // pop the sender state from the packet
    pkt->senderState = senderState->saved;
    delete senderState;

    port->hitCallback(pkt);
}

void
RubyPort::M5Port::hitCallback(PacketPtr pkt)
{
    bool needsResponse = pkt->needsResponse();

    //
    // All responses except failed SC operations access M5 physical memory
    //
    bool accessPhysMem = true;

    if (pkt->isLLSC()) {
        if (pkt->isWrite()) {
            if (pkt->req->getExtraData() != 0) {
                //
                // Successful SC packets convert to normal writes
                //
                pkt->convertScToWrite();
            } else {
                //
                // Failed SC packets don't access physical memory and thus
                // the RubyPort itself must convert it to a response.
                //
                accessPhysMem = false;
                pkt->makeAtomicResponse();
            }
        } else {
            //
            // All LL packets convert to normal loads so that M5 PhysMem does
            // not lock the blocks.
            //
            pkt->convertLlToRead();
        }
    }
    DPRINTF(MemoryAccess, "Hit callback needs response %d\n", needsResponse);

    if (accessPhysMem) {
        ruby_port->physMemPort->sendAtomic(pkt);
    }

    // turn packet around to go back to requester if response expected
    if (needsResponse) {
        // sendAtomic() should already have turned packet into
        // atomic response
        assert(pkt->isResponse());
        DPRINTF(MemoryAccess, "Sending packet back over port\n");
        sendTiming(pkt);
    } else {
        delete pkt;
    }
    DPRINTF(MemoryAccess, "Hit callback done!\n");
}

bool
RubyPort::M5Port::sendTiming(PacketPtr pkt)
{
    //minimum latency, must be > 0
    schedSendTiming(pkt, curTick + (1 * g_eventQueue_ptr->getClock()));
    return true;
}

bool
RubyPort::PioPort::sendTiming(PacketPtr pkt)
{
    //minimum latency, must be > 0
    schedSendTiming(pkt, curTick + (1 * g_eventQueue_ptr->getClock()));
    return true;
}

bool
RubyPort::M5Port::isPhysMemAddress(Addr addr)
{
    AddrRangeList physMemAddrList;
    bool snoop = false;
    ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
    for (AddrRangeIter iter = physMemAddrList.begin();
         iter != physMemAddrList.end();
         iter++) {
        if (addr >= iter->start && addr <= iter->end) {
            DPRINTF(MemoryAccess, "Request found in %#llx - %#llx range\n",
                    iter->start, iter->end);
            return true;
        }
    }
    return false;
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   SVGTesselator.cpp
    created:    1st August 2013
    author:     Lukas Meindl
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/svg/SVGTesselator.h"

#include "CEGUI/svg/SVGBasicShape.h"
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/System.h"
#include "CEGUI/Vertex.h"

// Start of CEGUI namespace section
namespace CEGUI
{

//----------------------------------------------------------------------------//
void SVGTesselator::tesselateAndRenderPolyline(const SVGPolyline* polyline,
                                               std::vector<GeometryBuffer*>& geometry_buffers,
                                               const SVGImage::SVGImageRenderSettings& render_settings)
{
    CEGUI::GeometryBuffer& geometry_buffer = System::getSingleton().getRenderer()->createGeometryBufferColoured();
    geometry_buffers.push_back(&geometry_buffer);

    if(render_settings.d_clipArea)
    {
        geometry_buffer.setClippingActive(true);
        geometry_buffer.setClippingRegion(*render_settings.d_clipArea);
    }
    geometry_buffer.setScale(render_settings.d_scaleFactor);

    const CEGUI::Colour& stroke_colour = polyline->d_shapeStyle.d_stroke.d_colour;
    const SVGPolyline::PolylinePointsList& points = polyline->d_points;
    const float& stroke_width_length_half = polyline->d_shapeStyle.d_strokeWidthLength * 0.5f;

    //Draw the line segments TODO Ident: Draw them seamlessly connected with bevels and stuff provided optionally
    size_t points_count = points.size();
    for (size_t j = 1; j < points_count; ++j)
    {
        const glm::vec2& prevPos = points.at(j - 1);
        const glm::vec2& currentPos = points.at(j);

        // Normalize and tilt the 2D direction vector by 90 to get the vector pointing in the offset direction
        glm::vec2 offsetVector = currentPos - prevPos;
        offsetVector = glm::normalize(offsetVector);
        offsetVector = glm::vec2(offsetVector.y, -offsetVector.x) * 0.5f;

        CEGUI::ColouredVertex linePositionVertex;
        glm::vec2 vertexPosition;
        linePositionVertex.colour_val = stroke_colour;

        linePositionVertex.position = glm::vec3(prevPos - offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(currentPos - offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(currentPos + offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(currentPos + offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(prevPos - offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(prevPos + offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);
    }
}

//----------------------------------------------------------------------------//
void SVGTesselator::tesselateAndRenderRect(const SVGRect* rect,
                                           std::vector<GeometryBuffer*>& geometry_buffers,
                                           const SVGImage::SVGImageRenderSettings& render_settings)
{
    CEGUI::GeometryBuffer& geometry_buffer = System::getSingleton().getRenderer()->createGeometryBufferColoured();
    geometry_buffers.push_back(&geometry_buffer);

    if(render_settings.d_clipArea)
    {
        geometry_buffer.setClippingActive(true);
        geometry_buffer.setClippingRegion(*render_settings.d_clipArea);
    }

    geometry_buffer.setScale(render_settings.d_scaleFactor);

    const CEGUI::Colour& fill_colour = rect->d_shapeStyle.d_fill.d_colour;

    //Draw the rectangle
    CEGUI::ColouredVertex rectFillVertex;
    glm::vec2 vertexPosition;
    rectFillVertex.colour_val = fill_colour;

    const float& rectX1 = rect->d_x;
    const float& rectY1 = rect->d_y;
    const float rectX2 = rect->d_x + rect->d_width;
    const float rectY2 = rect->d_y + rect->d_height;

    rectFillVertex.position = glm::vec3(rectX1, rectY1, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX1, rectY2, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX2, rectY2, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX2, rectY2, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX1, rectY1, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX2, rectY1, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);
}
//----------------------------------------------------------------------------//
}

<commit_msg>MOD: Adapted SVGTesselator for the changed colour type in PaintStyle<commit_after>/***********************************************************************
    filename:   SVGTesselator.cpp
    created:    1st August 2013
    author:     Lukas Meindl
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/svg/SVGTesselator.h"

#include "CEGUI/svg/SVGBasicShape.h"
#include "CEGUI/GeometryBuffer.h"
#include "CEGUI/System.h"
#include "CEGUI/Vertex.h"

// Start of CEGUI namespace section
namespace CEGUI
{

//----------------------------------------------------------------------------//
void SVGTesselator::tesselateAndRenderPolyline(const SVGPolyline* polyline,
                                               std::vector<GeometryBuffer*>& geometry_buffers,
                                               const SVGImage::SVGImageRenderSettings& render_settings)
{
    CEGUI::GeometryBuffer& geometry_buffer = System::getSingleton().getRenderer()->createGeometryBufferColoured();
    geometry_buffers.push_back(&geometry_buffer);

    if(render_settings.d_clipArea)
    {
        geometry_buffer.setClippingActive(true);
        geometry_buffer.setClippingRegion(*render_settings.d_clipArea);
    }
    geometry_buffer.setScale(render_settings.d_scaleFactor);

    const glm::vec3& strokeColourValues = polyline->d_paintStyle.d_stroke.d_colour;
    const CEGUI::Colour stroke_colour(strokeColourValues.x, strokeColourValues.y, strokeColourValues.z, polyline->d_paintStyle.d_strokeOpacity);
    const SVGPolyline::PolylinePointsList& points = polyline->d_points;
    const float& stroke_width_length_half = polyline->d_paintStyle.d_strokeWidth * 0.5f;

    //Draw the line segments TODO Ident: Draw them seamlessly connected with bevels and stuff provided optionally
    size_t points_count = points.size();
    for (size_t j = 1; j < points_count; ++j)
    {
        const glm::vec2& prevPos = points.at(j - 1);
        const glm::vec2& currentPos = points.at(j);

        // Normalize and tilt the 2D direction vector by 90 to get the vector pointing in the offset direction
        glm::vec2 offsetVector = currentPos - prevPos;
        offsetVector = glm::normalize(offsetVector);
        offsetVector = glm::vec2(offsetVector.y, -offsetVector.x) * stroke_width_length_half;

        CEGUI::ColouredVertex linePositionVertex;
        glm::vec2 vertexPosition;
        linePositionVertex.colour_val = stroke_colour;

        linePositionVertex.position = glm::vec3(prevPos - offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(currentPos - offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(currentPos + offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(currentPos + offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(prevPos - offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);

        linePositionVertex.position = glm::vec3(prevPos + offsetVector, 0.0f);
        geometry_buffer.appendVertex(linePositionVertex);
    }
}

//----------------------------------------------------------------------------//
void SVGTesselator::tesselateAndRenderRect(const SVGRect* rect,
                                           std::vector<GeometryBuffer*>& geometry_buffers,
                                           const SVGImage::SVGImageRenderSettings& render_settings)
{
    CEGUI::GeometryBuffer& geometry_buffer = System::getSingleton().getRenderer()->createGeometryBufferColoured();
    geometry_buffers.push_back(&geometry_buffer);

    if(render_settings.d_clipArea)
    {
        geometry_buffer.setClippingActive(true);
        geometry_buffer.setClippingRegion(*render_settings.d_clipArea);
    }

    geometry_buffer.setScale(render_settings.d_scaleFactor);

    const glm::vec3& colourValues = rect->d_paintStyle.d_fill.d_colour;
    const CEGUI::Colour fill_colour(colourValues.x, colourValues.y, colourValues.z, rect->d_paintStyle.d_fillOpacity);

    //Draw the rectangle
    CEGUI::ColouredVertex rectFillVertex;
    glm::vec2 vertexPosition;
    rectFillVertex.colour_val = fill_colour;

    const float& rectX1 = rect->d_x;
    const float& rectY1 = rect->d_y;
    const float rectX2 = rect->d_x + rect->d_width;
    const float rectY2 = rect->d_y + rect->d_height;

    rectFillVertex.position = glm::vec3(rectX1, rectY1, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX1, rectY2, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX2, rectY2, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX2, rectY2, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX1, rectY1, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);

    rectFillVertex.position = glm::vec3(rectX2, rectY1, 0.0f);
    geometry_buffer.appendVertex(rectFillVertex);
}
//----------------------------------------------------------------------------//
}

<|endoftext|>


<commit_before>#include <iostream>
#include <chrono>
using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main ( int argc, char** argv )
{
    // 读取argv[1]指定的图像
    cv::Mat image;
    image = cv::imread ( argv[1] ); //cv::imread函数读取指定路径下的图像
    // 判断图像文件是否正确读取
    if ( image.data == nullptr ) //数据不存在,可能是文件不存在
    {
        cerr<<"文件"<<argv[1]<<"不存在."<<endl;
        return 0;
    }

    // 文件顺利读取, 首先输出一些基本信息
    cout<<"图像宽为"<<image.cols<<",高为"<<image.rows<<",通道数为"<<image.channels()<<endl;
    cv::imshow ( "image", image );      // 用cv::imshow显示图像
    cv::waitKey ( 0 );                  // 暂停程序,等待一个按键输入
    // 判断image的类型
    if ( image.type() != CV_8UC1 || image.type() != CV_8UC3 )
    {
        // 图像类型不符合要求
        cout<<"请输入一张彩色图或灰度图."<<endl;
        return 0;
    }

    // 遍历图像, 请注意以下遍历方式亦可使用于随机像素访问
    // 使用 std::chrono 来给算法计时
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for ( size_t y=0; y<image.rows; y++ )
    {
        for ( size_t x=0; x<image.cols; x++ )
        {
            // 访问位于 x,y 处的像素
            // 用cv::Mat::ptr获得图像的行指针
            unsigned char* row_ptr = image.ptr<unsigned char> ( y );  // row_ptr是第y行的头指针
            unsigned char* data_ptr = &row_ptr[ x*image.channels() ]; // data_ptr 指向待访问的像素数据
            // 输出该像素的每个通道,如果是灰度图就只有一个通道
            for ( int c = 0; c != image.channels(); c++ )
            {
                unsigned char data = data_ptr[c]; // data为I(x,y)第c个通道的值
            }
        }
    }
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 );
    cout<<"遍历图像用时："<<time_used.count()<<" 秒。"<<endl;

    // 关于 cv::Mat 的拷贝
    // 直接赋值并不会拷贝数据
    cv::Mat image_another = image;
    // 修改 image_another 会导致 image 发生变化
    image_another ( cv::Rect ( 0,0,100,100 ) ).setTo ( 0 ); // 将左上角100*100的块置零
    cv::imshow ( "image", image );
    cv::waitKey ( 0 );

    // 使用clone函数来拷贝数据
    cv::Mat image_clone = image.clone();
    image_clone ( cv::Rect ( 0,0,100,100 ) ).setTo ( 255 );
    cv::imshow ( "image", image );
    cv::imshow ( "image_clone", image_clone );
    cv::waitKey ( 0 );

    // 对于图像还有很多基本的操作,如剪切,旋转,缩放等,限于篇幅就不一一介绍了,请参看OpenCV官方文档查询每个函数的调用方法.
    cv::destroyAllWindows();
    return 0;
}
<commit_msg>Update imageBasics.cpp<commit_after>#include <iostream>
#include <chrono>
using namespace std;

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main ( int argc, char** argv )
{
    // 读取argv[1]指定的图像
    cv::Mat image;
    image = cv::imread ( argv[1] ); //cv::imread函数读取指定路径下的图像
    // 判断图像文件是否正确读取
    if ( image.data == nullptr ) //数据不存在,可能是文件不存在
    {
        cerr<<"文件"<<argv[1]<<"不存在."<<endl;
        return 0;
    }

    // 文件顺利读取, 首先输出一些基本信息
    cout<<"图像宽为"<<image.cols<<",高为"<<image.rows<<",通道数为"<<image.channels()<<endl;
    cv::imshow ( "image", image );      // 用cv::imshow显示图像
    cv::waitKey ( 0 );                  // 暂停程序,等待一个按键输入
    // 判断image的类型
    if ( image.type() != CV_8UC1 && image.type() != CV_8UC3 )
    {
        // 图像类型不符合要求
        cout<<"请输入一张彩色图或灰度图."<<endl;
        return 0;
    }

    // 遍历图像, 请注意以下遍历方式亦可使用于随机像素访问
    // 使用 std::chrono 来给算法计时
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    for ( size_t y=0; y<image.rows; y++ )
    {
        for ( size_t x=0; x<image.cols; x++ )
        {
            // 访问位于 x,y 处的像素
            // 用cv::Mat::ptr获得图像的行指针
            unsigned char* row_ptr = image.ptr<unsigned char> ( y );  // row_ptr是第y行的头指针
            unsigned char* data_ptr = &row_ptr[ x*image.channels() ]; // data_ptr 指向待访问的像素数据
            // 输出该像素的每个通道,如果是灰度图就只有一个通道
            for ( int c = 0; c != image.channels(); c++ )
            {
                unsigned char data = data_ptr[c]; // data为I(x,y)第c个通道的值
            }
        }
    }
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 );
    cout<<"遍历图像用时："<<time_used.count()<<" 秒。"<<endl;

    // 关于 cv::Mat 的拷贝
    // 直接赋值并不会拷贝数据
    cv::Mat image_another = image;
    // 修改 image_another 会导致 image 发生变化
    image_another ( cv::Rect ( 0,0,100,100 ) ).setTo ( 0 ); // 将左上角100*100的块置零
    cv::imshow ( "image", image );
    cv::waitKey ( 0 );

    // 使用clone函数来拷贝数据
    cv::Mat image_clone = image.clone();
    image_clone ( cv::Rect ( 0,0,100,100 ) ).setTo ( 255 );
    cv::imshow ( "image", image );
    cv::imshow ( "image_clone", image_clone );
    cv::waitKey ( 0 );

    // 对于图像还有很多基本的操作,如剪切,旋转,缩放等,限于篇幅就不一一介绍了,请参看OpenCV官方文档查询每个函数的调用方法.
    cv::destroyAllWindows();
    return 0;
}
<|endoftext|>


<commit_before>#if !defined(_WIN32)
// This file will only be compiled with clang into llvm bitcode
// Generated bitcode will likely get inline for performance.

#include <atomic>
#include <cmath>
#include <type_traits>

#define STRUCT_FIELD(S, F)                                                     \
  extern "C" decltype(S::F) S##_get_##F(S *s) { return s->F; }                 \
  extern "C" decltype(S::F) *S##_get_ptr_##F(S *s) { return &(s->F); }         \
  extern "C" void S##_set_##F(S *s, decltype(S::F) f) { s->F = f; }

#define STRUCT_FIELD_ARRAY(S, F)                                               \
  extern "C" std::remove_all_extents_t<decltype(S::F)> S##_get_##F(S *s,       \
                                                                   int i) {    \
    return s->F[i];                                                            \
  }                                                                            \
  extern "C" void S##_set_##F(S *s, int i,                                     \
                              std::remove_all_extents_t<decltype(S::F)> f) {   \
    s->F[i] = f;                                                               \
  }

using int8 = int8_t;
using int16 = int16_t;
using int32 = int32_t;
using int64 = int64_t;
using uint8 = uint8_t;
using uint16 = uint16_t;
using uint32 = uint32_t;
using uint64 = uint64_t;
using float32 = float;
using float64 = double;

using i8 = int8;
using i32 = int32;
using f32 = float32;
using f64 = float64;

// TODO: DRY. merge this with taichi_core
constexpr int taichi_max_num_indices = 4;
constexpr int taichi_max_num_args = 8;
constexpr int taichi_max_num_snodes = 1024;

using uint8 = uint8_t;
using Ptr = uint8 *;

using ContextArgType = long long;

extern "C" {

void vprintf(Ptr format, Ptr arg);
i32 printf(const char *, ...);

#define DEFINE_UNARY_REAL_FUNC(F)                                              \
  f32 F##_f32(f32 x) { return std::F(x); }                                     \
  f64 F##_f64(f64 x) { return std::F(x); }

// sin and cos are already included in llvm intrinsics
DEFINE_UNARY_REAL_FUNC(exp)
DEFINE_UNARY_REAL_FUNC(log)
DEFINE_UNARY_REAL_FUNC(tan)
DEFINE_UNARY_REAL_FUNC(tanh)
DEFINE_UNARY_REAL_FUNC(abs)

int abs_i32(int a) {
  if (a > 0) {
    return a;
  } else {
    return -a;
  }
}

int max_i32(int a, int b) { return a > b ? a : b; }

int min_i32(int a, int b) { return a < b ? a : b; }

int32 logic_not_i32(int32 a) { return !a; }

float32 sgn_f32(float32 a) {
  float32 b;
  if (a > 0)
    b = 1;
  else if (a < 0)
    b = -1;
  else
    b = 0;
  return b;
}

float64 sgn_f64(float64 a) {
  float32 b;
  if (a > 0)
    b = 1;
  else if (a < 0)
    b = -1;
  else
    b = 0;
  return b;
}

f32 __nv_sgnf(f32 x) { return sgn_f32(x); }

f64 __nv_sgn(f64 x) { return sgn_f64(x); }

struct PhysicalCoordinates {
  int val[taichi_max_num_indices];
};

STRUCT_FIELD_ARRAY(PhysicalCoordinates, val);

struct Context {
  void *buffer;
  ContextArgType args[taichi_max_num_args];
  void *leaves;
  int num_leaves;
  void *cpu_profiler;
  Ptr runtime;
};

STRUCT_FIELD_ARRAY(Context, args);
STRUCT_FIELD(Context, runtime);
STRUCT_FIELD(Context, buffer);

#include "atomic.h"

// These structures are accessible by both the LLVM backend and this C++ runtime
// file here (for building complex runtime functions in C++)

// These structs contain some "template parameters"

// Common Attributes
struct StructMeta {
  int snode_id;
  std::size_t element_size;
  int max_num_elements;
  Ptr (*lookup_element)(Ptr, Ptr, int i);
  Ptr (*from_parent_element)(Ptr);
  bool (*is_active)(Ptr, Ptr, int i);
  int (*get_num_elements)(Ptr, Ptr);
  void (*refine_coordinates)(PhysicalCoordinates *inp_coord,
                             PhysicalCoordinates *refined_coord, int index);
  Context *context;
};

STRUCT_FIELD(StructMeta, snode_id)
STRUCT_FIELD(StructMeta, element_size)
STRUCT_FIELD(StructMeta, max_num_elements)
STRUCT_FIELD(StructMeta, get_num_elements);
STRUCT_FIELD(StructMeta, lookup_element);
STRUCT_FIELD(StructMeta, from_parent_element);
STRUCT_FIELD(StructMeta, refine_coordinates);
STRUCT_FIELD(StructMeta, is_active);
STRUCT_FIELD(StructMeta, context);

void *taichi_allocate_aligned(std::size_t size, int alignment);

void *taichi_allocate(std::size_t size) {
  return taichi_allocate_aligned(size, 1);
}

void ___stubs___() {
  printf("");
  vprintf(nullptr, nullptr);
  taichi_allocate(1);
  taichi_allocate_aligned(1, 1);
}

struct Element {
  uint8 *element;
  int loop_bounds[2];
  PhysicalCoordinates pcoord;
};

STRUCT_FIELD(Element, element);
STRUCT_FIELD(Element, pcoord);
STRUCT_FIELD_ARRAY(Element, loop_bounds);

struct ElementList {
  Element *elements;
  int head;
  int tail;
};

void ElementList_initialize(ElementList *element_list) {
  element_list->elements = (Element *)taichi_allocate(1024 * 1024 * 1024);
  element_list->tail = 0;
}

void ElementList_insert(ElementList *element_list, Element *element) {
  element_list->elements[element_list->tail] = *element;
  element_list->tail++;
}

void ElementList_clear(ElementList *element_list) { element_list->tail = 0; }

struct NodeAllocator {
  Ptr pool;
  std::size_t node_size;
  int tail;
};

void NodeAllocator_initialize(NodeAllocator *node_allocator,
                              std::size_t node_size) {
  node_allocator->pool = (Ptr)taichi_allocate_aligned(1024 * 1024 * 1024, 4096);
  node_allocator->node_size = node_size;
  node_allocator->tail = 0;
}

Ptr NodeAllocator_allocate(NodeAllocator *node_allocator) {
  int p = atomic_add_i32(&node_allocator->tail, 1);
  return node_allocator->pool + node_allocator->node_size * p;
}

// Is "runtime" a correct name, even if it is created after the data layout is
// materialized?
struct Runtime {
  ElementList *element_lists[taichi_max_num_snodes];
  NodeAllocator *node_allocators[taichi_max_num_snodes];
  Ptr ambient_elements[taichi_max_num_snodes];
};

STRUCT_FIELD_ARRAY(Runtime, element_lists);
STRUCT_FIELD_ARRAY(Runtime, node_allocators);

Ptr Runtime_initialize(Runtime **runtime_ptr, int num_snodes,
                       uint64_t root_size, int root_id) {
  *runtime_ptr = (Runtime *)taichi_allocate(sizeof(Runtime));
  Runtime *runtime = *runtime_ptr;
  printf("Initializing runtime with %d elements\n", num_snodes);
  for (int i = 0; i < num_snodes; i++) {
    runtime->element_lists[i] =
        (ElementList *)taichi_allocate(sizeof(ElementList));
    ElementList_initialize(runtime->element_lists[i]);

    runtime->node_allocators[i] =
        (NodeAllocator *)taichi_allocate(sizeof(NodeAllocator));
  }
  // Assuming num_snodes - 1 is the root
  auto root_ptr = taichi_allocate_aligned(root_size, 4096);
  Element elem;
  elem.loop_bounds[0] = 0;
  elem.loop_bounds[1] = 1;
  elem.element = (Ptr)root_ptr;
  for (int i = 0; i < taichi_max_num_indices; i++) {
    elem.pcoord.val[i] = 0;
  }
  ElementList_insert(runtime->element_lists[root_id], &elem);
  printf("Runtime initialized.\n");
  return (Ptr)root_ptr;
}

void Runtime_allocate_ambient(Runtime *runtime, int snode_id) {
  runtime->ambient_elements[snode_id] =
      NodeAllocator_allocate(runtime->node_allocators[snode_id]);
}

// "Element", "component" are different concepts

// ultimately all function calls here will be inlined
void element_listgen(Runtime *runtime, StructMeta *parent, StructMeta *child) {
  auto parent_list = runtime->element_lists[parent->snode_id];
  int num_parent_elements = parent_list->tail;
  auto child_list = runtime->element_lists[child->snode_id];
  child_list->head = 0;
  child_list->tail = 0;
  for (int i = 0; i < num_parent_elements; i++) {
    auto element = parent_list->elements[i];
    auto ch_component = child->from_parent_element(element.element);
    int ch_num_elements = child->get_num_elements((Ptr)child, ch_component);
    for (int j = 0; j < ch_num_elements; j++) {
      if (child->is_active((Ptr)child, ch_component, j)) {
        auto ch_element = child->lookup_element((Ptr)child, element.element, j);
        Element elem;
        elem.element = ch_element;
        elem.loop_bounds[0] = 0;
        elem.loop_bounds[1] = child->get_num_elements((Ptr)child, ch_element);
        PhysicalCoordinates refined_coord;
        child->refine_coordinates(&element.pcoord, &refined_coord, j);
        elem.pcoord = refined_coord;
        ElementList_insert(child_list, &elem);
      }
    }
  }
}

int32 thread_idx() { return 0; }

int32 block_idx() { return 0; }

int32 block_dim() { return 0; }

int32 grid_dim() { return 0; }

void block_barrier() {}

void for_each_block(Context *context, int snode_id, int element_size,
                    int element_split,
                    void (*task)(Context *, Element *, int, int)) {
  auto list = ((Runtime *)context->runtime)->element_lists[snode_id];
  auto list_tail = list->tail;
#if ARCH_cuda
  int i = block_idx();
  const auto part_size = element_size / element_split;
  while (true) {
    int element_id = i / element_split;
    if (element_id >= list_tail)
      break;
    auto part_id = i % element_split;
    auto lower = part_size * part_id;
    auto upper = part_size * (part_id + 1);
    task(context, &list->elements[element_id], lower, upper);
    i += grid_dim();
  }
#else
  for (int i = 0; i < list_tail; i++) {
    task(context, &list->elements[i], 0, element_size);
  }
#endif
}

#include "node_dense.h"
#include "node_pointer.h"
#include "node_root.h"
}
#endif
<commit_msg>update runtime for windows build<commit_after>#if !defined(TC_INCLUDED)
// This file will only be compiled with clang into llvm bitcode
// Generated bitcode will likely get inline for performance.

#include <atomic>
#include <cmath>
#include <type_traits>

#define STRUCT_FIELD(S, F)                                                     \
  extern "C" decltype(S::F) S##_get_##F(S *s) { return s->F; }                 \
  extern "C" decltype(S::F) *S##_get_ptr_##F(S *s) { return &(s->F); }         \
  extern "C" void S##_set_##F(S *s, decltype(S::F) f) { s->F = f; }

#define STRUCT_FIELD_ARRAY(S, F)                                               \
  extern "C" std::remove_all_extents_t<decltype(S::F)> S##_get_##F(S *s,       \
                                                                   int i) {    \
    return s->F[i];                                                            \
  }                                                                            \
  extern "C" void S##_set_##F(S *s, int i,                                     \
                              std::remove_all_extents_t<decltype(S::F)> f) {   \
    s->F[i] = f;                                                               \
  }

using int8 = int8_t;
using int16 = int16_t;
using int32 = int32_t;
using int64 = int64_t;
using uint8 = uint8_t;
using uint16 = uint16_t;
using uint32 = uint32_t;
using uint64 = uint64_t;
using float32 = float;
using float64 = double;

using i8 = int8;
using i32 = int32;
using f32 = float32;
using f64 = float64;

// TODO: DRY. merge this with taichi_core
constexpr int taichi_max_num_indices = 4;
constexpr int taichi_max_num_args = 8;
constexpr int taichi_max_num_snodes = 1024;

using uint8 = uint8_t;
using Ptr = uint8 *;

using ContextArgType = long long;

extern "C" {

#if ARCH_cuda
void vprintf(Ptr format, Ptr arg);
#endif
i32 printf(const char *, ...);

#define DEFINE_UNARY_REAL_FUNC(F)                                              \
  f32 F##_f32(f32 x) { return std::F(x); }                                     \
  f64 F##_f64(f64 x) { return std::F(x); }

// sin and cos are already included in llvm intrinsics
DEFINE_UNARY_REAL_FUNC(exp)
DEFINE_UNARY_REAL_FUNC(log)
DEFINE_UNARY_REAL_FUNC(tan)
DEFINE_UNARY_REAL_FUNC(tanh)
DEFINE_UNARY_REAL_FUNC(abs)

int abs_i32(int a) {
  if (a > 0) {
    return a;
  } else {
    return -a;
  }
}

int max_i32(int a, int b) { return a > b ? a : b; }

int min_i32(int a, int b) { return a < b ? a : b; }

int32 logic_not_i32(int32 a) { return !a; }

float32 sgn_f32(float32 a) {
  float32 b;
  if (a > 0)
    b = 1;
  else if (a < 0)
    b = -1;
  else
    b = 0;
  return b;
}

float64 sgn_f64(float64 a) {
  float32 b;
  if (a > 0)
    b = 1;
  else if (a < 0)
    b = -1;
  else
    b = 0;
  return b;
}

f32 __nv_sgnf(f32 x) { return sgn_f32(x); }

f64 __nv_sgn(f64 x) { return sgn_f64(x); }

struct PhysicalCoordinates {
  int val[taichi_max_num_indices];
};

STRUCT_FIELD_ARRAY(PhysicalCoordinates, val);

struct Context {
  void *buffer;
  ContextArgType args[taichi_max_num_args];
  void *leaves;
  int num_leaves;
  void *cpu_profiler;
  Ptr runtime;
};

STRUCT_FIELD_ARRAY(Context, args);
STRUCT_FIELD(Context, runtime);
STRUCT_FIELD(Context, buffer);

#include "atomic.h"

// These structures are accessible by both the LLVM backend and this C++ runtime
// file here (for building complex runtime functions in C++)

// These structs contain some "template parameters"

// Common Attributes
struct StructMeta {
  int snode_id;
  std::size_t element_size;
  int max_num_elements;
  Ptr (*lookup_element)(Ptr, Ptr, int i);
  Ptr (*from_parent_element)(Ptr);
  bool (*is_active)(Ptr, Ptr, int i);
  int (*get_num_elements)(Ptr, Ptr);
  void (*refine_coordinates)(PhysicalCoordinates *inp_coord,
                             PhysicalCoordinates *refined_coord, int index);
  Context *context;
};

STRUCT_FIELD(StructMeta, snode_id)
STRUCT_FIELD(StructMeta, element_size)
STRUCT_FIELD(StructMeta, max_num_elements)
STRUCT_FIELD(StructMeta, get_num_elements);
STRUCT_FIELD(StructMeta, lookup_element);
STRUCT_FIELD(StructMeta, from_parent_element);
STRUCT_FIELD(StructMeta, refine_coordinates);
STRUCT_FIELD(StructMeta, is_active);
STRUCT_FIELD(StructMeta, context);

void *taichi_allocate_aligned(std::size_t size, int alignment);

void *taichi_allocate(std::size_t size) {
  return taichi_allocate_aligned(size, 1);
}

void ___stubs___() {
  printf("");
#if ARCH_cuda
  vprintf(nullptr, nullptr);
#endif
  taichi_allocate(1);
  taichi_allocate_aligned(1, 1);
}

struct Element {
  uint8 *element;
  int loop_bounds[2];
  PhysicalCoordinates pcoord;
};

STRUCT_FIELD(Element, element);
STRUCT_FIELD(Element, pcoord);
STRUCT_FIELD_ARRAY(Element, loop_bounds);

struct ElementList {
  Element *elements;
  int head;
  int tail;
};

void ElementList_initialize(ElementList *element_list) {
  element_list->elements = (Element *)taichi_allocate(1024 * 1024 * 1024);
  element_list->tail = 0;
}

void ElementList_insert(ElementList *element_list, Element *element) {
  element_list->elements[element_list->tail] = *element;
  element_list->tail++;
}

void ElementList_clear(ElementList *element_list) { element_list->tail = 0; }

struct NodeAllocator {
  Ptr pool;
  std::size_t node_size;
  int tail;
};

void NodeAllocator_initialize(NodeAllocator *node_allocator,
                              std::size_t node_size) {
  node_allocator->pool = (Ptr)taichi_allocate_aligned(1024 * 1024 * 1024, 4096);
  node_allocator->node_size = node_size;
  node_allocator->tail = 0;
}

Ptr NodeAllocator_allocate(NodeAllocator *node_allocator) {
  int p = atomic_add_i32(&node_allocator->tail, 1);
  return node_allocator->pool + node_allocator->node_size * p;
}

// Is "runtime" a correct name, even if it is created after the data layout is
// materialized?
struct Runtime {
  ElementList *element_lists[taichi_max_num_snodes];
  NodeAllocator *node_allocators[taichi_max_num_snodes];
  Ptr ambient_elements[taichi_max_num_snodes];
};

STRUCT_FIELD_ARRAY(Runtime, element_lists);
STRUCT_FIELD_ARRAY(Runtime, node_allocators);

Ptr Runtime_initialize(Runtime **runtime_ptr, int num_snodes,
                       uint64_t root_size, int root_id) {
  *runtime_ptr = (Runtime *)taichi_allocate(sizeof(Runtime));
  Runtime *runtime = *runtime_ptr;
  printf("Initializing runtime with %d elements\n", num_snodes);
  for (int i = 0; i < num_snodes; i++) {
    runtime->element_lists[i] =
        (ElementList *)taichi_allocate(sizeof(ElementList));
    ElementList_initialize(runtime->element_lists[i]);

    runtime->node_allocators[i] =
        (NodeAllocator *)taichi_allocate(sizeof(NodeAllocator));
  }
  // Assuming num_snodes - 1 is the root
  auto root_ptr = taichi_allocate_aligned(root_size, 4096);
  Element elem;
  elem.loop_bounds[0] = 0;
  elem.loop_bounds[1] = 1;
  elem.element = (Ptr)root_ptr;
  for (int i = 0; i < taichi_max_num_indices; i++) {
    elem.pcoord.val[i] = 0;
  }
  ElementList_insert(runtime->element_lists[root_id], &elem);
  printf("Runtime initialized.\n");
  return (Ptr)root_ptr;
}

void Runtime_allocate_ambient(Runtime *runtime, int snode_id) {
  runtime->ambient_elements[snode_id] =
      NodeAllocator_allocate(runtime->node_allocators[snode_id]);
}

// "Element", "component" are different concepts

// ultimately all function calls here will be inlined
void element_listgen(Runtime *runtime, StructMeta *parent, StructMeta *child) {
  auto parent_list = runtime->element_lists[parent->snode_id];
  int num_parent_elements = parent_list->tail;
  auto child_list = runtime->element_lists[child->snode_id];
  child_list->head = 0;
  child_list->tail = 0;
  for (int i = 0; i < num_parent_elements; i++) {
    auto element = parent_list->elements[i];
    auto ch_component = child->from_parent_element(element.element);
    int ch_num_elements = child->get_num_elements((Ptr)child, ch_component);
    for (int j = 0; j < ch_num_elements; j++) {
      if (child->is_active((Ptr)child, ch_component, j)) {
        auto ch_element = child->lookup_element((Ptr)child, element.element, j);
        Element elem;
        elem.element = ch_element;
        elem.loop_bounds[0] = 0;
        elem.loop_bounds[1] = child->get_num_elements((Ptr)child, ch_element);
        PhysicalCoordinates refined_coord;
        child->refine_coordinates(&element.pcoord, &refined_coord, j);
        elem.pcoord = refined_coord;
        ElementList_insert(child_list, &elem);
      }
    }
  }
}

int32 thread_idx() { return 0; }

int32 block_idx() { return 0; }

int32 block_dim() { return 0; }

int32 grid_dim() { return 0; }

void block_barrier() {}

void for_each_block(Context *context, int snode_id, int element_size,
                    int element_split,
                    void (*task)(Context *, Element *, int, int)) {
  auto list = ((Runtime *)context->runtime)->element_lists[snode_id];
  auto list_tail = list->tail;
#if ARCH_cuda
  int i = block_idx();
  const auto part_size = element_size / element_split;
  while (true) {
    int element_id = i / element_split;
    if (element_id >= list_tail)
      break;
    auto part_id = i % element_split;
    auto lower = part_size * part_id;
    auto upper = part_size * (part_id + 1);
    task(context, &list->elements[element_id], lower, upper);
    i += grid_dim();
  }
#else
  for (int i = 0; i < list_tail; i++) {
    task(context, &list->elements[i], 0, element_size);
  }
#endif
}

#include "node_dense.h"
#include "node_pointer.h"
#include "node_root.h"
}
#endif
<|endoftext|>