<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "qt4projectmanagerplugin.h"

#include "qt4projectmanager.h"
#include "qt4nodes.h"
#include "qmakestep.h"
#include "makestep.h"
#include "wizards/consoleappwizard.h"
#include "wizards/guiappwizard.h"
#include "wizards/mobileappwizard.h"
#include "wizards/librarywizard.h"
#include "wizards/testwizard.h"
#include "wizards/emptyprojectwizard.h"
#include "wizards/subdirsprojectwizard.h"
#include "wizards/qtquickappwizard.h"
#include "wizards/html5appwizard.h"
#include "customwidgetwizard/customwidgetwizard.h"
#include "profileeditorfactory.h"
#include "profilehoverhandler.h"
#include "qt4projectmanagerconstants.h"
#include "qt4project.h"
#include "profileeditor.h"
#include "externaleditors.h"
#include "profilecompletionassist.h"
#include "qt-s60/s60manager.h"
#include "qt-desktop/qt4desktoptargetfactory.h"
#include "qt-desktop/qt4simulatortargetfactory.h"
#include "qt-desktop/qt4runconfiguration.h"
#include "qt-desktop/desktopqtversionfactory.h"
#include "qt-desktop/simulatorqtversionfactory.h"
#include "winceqtversionfactory.h"

#include <coreplugin/id.h>
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/editormanager/editormanager.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h>

#ifdef WITH_TESTS
#    include <QTest>
#endif

#include <QtCore/QtPlugin>
#include <QtGui/QMenu>

using namespace Qt4ProjectManager::Internal;
using namespace Qt4ProjectManager;
using ProjectExplorer::Project;

Qt4ProjectManagerPlugin::~Qt4ProjectManagerPlugin()
{
    //removeObject(m_embeddedPropertiesPage);
    //delete m_embeddedPropertiesPage;

    removeObject(m_proFileEditorFactory);
    delete m_proFileEditorFactory;
    removeObject(m_qt4ProjectManager);
    delete m_qt4ProjectManager;
}

bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
    Q_UNUSED(arguments)
    const Core::Context projectContext(Qt4ProjectManager::Constants::PROJECT_ID);
    Core::Context projecTreeContext(ProjectExplorer::Constants::C_PROJECT_TREE);

    Core::ICore *core = Core::ICore::instance();
    if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":qt4projectmanager/Qt4ProjectManager.mimetypes.xml"), errorMessage))
        return false;

    m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
    Core::ActionManager *am = core->actionManager();

    //create and register objects
    m_qt4ProjectManager = new Qt4Manager(this);
    addObject(m_qt4ProjectManager);

    TextEditor::TextEditorActionHandler *editorHandler
            = new TextEditor::TextEditorActionHandler(Constants::C_PROFILEEDITOR,
                  TextEditor::TextEditorActionHandler::UnCommentSelection);

    m_proFileEditorFactory = new ProFileEditorFactory(m_qt4ProjectManager, editorHandler);
    addObject(m_proFileEditorFactory);

    addAutoReleasedObject(new EmptyProjectWizard);
    addAutoReleasedObject(new SubdirsProjectWizard);
    addAutoReleasedObject(new GuiAppWizard);
    addAutoReleasedObject(new ConsoleAppWizard);
    addAutoReleasedObject(new MobileAppWizard);
    addAutoReleasedObject(new QtQuickAppWizard);
    addAutoReleasedObject(new Html5AppWizard);
    addAutoReleasedObject(new LibraryWizard);
    addAutoReleasedObject(new TestWizard);
    addAutoReleasedObject(new CustomWidgetWizard);

    CustomQt4ProjectWizard::registerSelf();

    addAutoReleasedObject(new QMakeStepFactory);
    addAutoReleasedObject(new MakeStepFactory);

    addAutoReleasedObject(new Qt4RunConfigurationFactory);

#ifdef Q_OS_MAC
    addAutoReleasedObject(new MacDesignerExternalEditor);
#else
    addAutoReleasedObject(new DesignerExternalEditor);
#endif
    addAutoReleasedObject(new LinguistExternalEditor);

    addAutoReleasedObject(new S60Manager);

    addAutoReleasedObject(new Qt4DesktopTargetFactory);
    addAutoReleasedObject(new Qt4SimulatorTargetFactory);

    addAutoReleasedObject(new DesktopQtVersionFactory);
    addAutoReleasedObject(new SimulatorQtVersionFactory);
    addAutoReleasedObject(new WinCeQtVersionFactory);

    addAutoReleasedObject(new ProFileCompletionAssistProvider);
    addAutoReleasedObject(new ProFileHoverHandler(this));

    // TODO reenable
    //m_embeddedPropertiesPage = new EmbeddedPropertiesPage;
    //addObject(m_embeddedPropertiesPage);

    //menus
    Core::ActionContainer *mbuild =
            am->actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
    Core::ActionContainer *mproject =
            am->actionContainer(ProjectExplorer::Constants::M_PROJECTCONTEXT);
    Core::ActionContainer *msubproject =
            am->actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT);

    //register actions
    Core::Command *command;

    QIcon qmakeIcon(QLatin1String(":/qt4projectmanager/images/run_qmake.png"));
    qmakeIcon.addFile(QLatin1String(":/qt4projectmanager/images/run_qmake_small.png"));
    m_runQMakeAction = new QAction(qmakeIcon, tr("Run qmake"), this);
    command = am->registerAction(m_runQMakeAction, Constants::RUNQMAKE, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PROJECT);
    connect(m_runQMakeAction, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMake()));

    m_runQMakeActionContextMenu = new QAction(qmakeIcon, tr("Run qmake"), this);
    command = am->registerAction(m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_runQMakeActionContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMakeContextMenu()));

    QIcon buildIcon = QIcon(QLatin1String(ProjectExplorer::Constants::ICON_BUILD));
    buildIcon.addFile(QLatin1String(ProjectExplorer::Constants::ICON_BUILD_SMALL));
    m_buildSubProjectContextMenu = new QAction(buildIcon, tr("Build"), this);
    command = am->registerAction(m_buildSubProjectContextMenu, Constants::BUILDSUBDIR, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_buildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(buildSubDirContextMenu()));

    QIcon rebuildIcon = QIcon(QLatin1String(ProjectExplorer::Constants::ICON_REBUILD));
    rebuildIcon.addFile(QLatin1String(ProjectExplorer::Constants::ICON_REBUILD_SMALL));
    m_rebuildSubProjectContextMenu = new QAction(rebuildIcon, tr("Rebuild"), this);
    command = am->registerAction(m_rebuildSubProjectContextMenu, Constants::REBUILDSUBDIR, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_rebuildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(rebuildSubDirContextMenu()));

    QIcon cleanIcon = QIcon(QLatin1String(ProjectExplorer::Constants::ICON_CLEAN));
    cleanIcon.addFile(QLatin1String(ProjectExplorer::Constants::ICON_CLEAN_SMALL));
    m_cleanSubProjectContextMenu = new QAction(cleanIcon, tr("Clean"), this);
    command = am->registerAction(m_cleanSubProjectContextMenu, Constants::CLEANSUBDIR, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_cleanSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(cleanSubDirContextMenu()));

    connect(m_projectExplorer,
            SIGNAL(aboutToShowContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)),
            this, SLOT(updateContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)));

    connect(m_projectExplorer->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project *)),
            this, SLOT(buildStateChanged(ProjectExplorer::Project *)));
    connect(m_projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
            this, SLOT(currentProjectChanged()));
    connect(m_projectExplorer, SIGNAL(currentNodeChanged(ProjectExplorer::Node*,ProjectExplorer::Project*)),
            this, SLOT(currentNodeChanged(ProjectExplorer::Node*)));

    Core::ActionContainer *contextMenu = am->createMenu(Qt4ProjectManager::Constants::M_CONTEXT);

    Core::Context proFileEditorContext = Core::Context(Qt4ProjectManager::Constants::C_PROFILEEDITOR);

    QAction *jumpToFile = new QAction(tr("Jump to File Under Cursor"), this);
    command = am->registerAction(jumpToFile,
        Constants::JUMP_TO_FILE, proFileEditorContext);
    command->setDefaultKeySequence(QKeySequence(Qt::Key_F2));
    connect(jumpToFile, SIGNAL(triggered()),
            this, SLOT(jumpToFile()));
    contextMenu->addAction(command);

    m_addLibraryAction = new QAction(tr("Add Library..."), this);
    command = am->registerAction(m_addLibraryAction,
        Constants::ADDLIBRARY, proFileEditorContext);
    connect(m_addLibraryAction, SIGNAL(triggered()),
            m_qt4ProjectManager, SLOT(addLibrary()));
    contextMenu->addAction(command);

    m_addLibraryActionContextMenu = new QAction(tr("Add Library..."), this);
    command = am->registerAction(m_addLibraryActionContextMenu,
        Constants::ADDLIBRARY, projecTreeContext);
    connect(m_addLibraryActionContextMenu, SIGNAL(triggered()),
            m_qt4ProjectManager, SLOT(addLibraryContextMenu()));
    mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES);

    QAction *separator = new QAction(this);
    separator->setSeparator(true);
    contextMenu->addAction(am->registerAction(separator,
                  Core::Id(Constants::SEPARATOR), proFileEditorContext));

    command = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
    contextMenu->addAction(command);

    return true;
}

void Qt4ProjectManagerPlugin::extensionsInitialized()
{
    m_qt4ProjectManager->init();
}

void Qt4ProjectManagerPlugin::updateContextMenu(Project *project,
                                                ProjectExplorer::Node *node)
{
    m_qt4ProjectManager->setContextProject(project);
    m_qt4ProjectManager->setContextNode(node);
    m_runQMakeActionContextMenu->setEnabled(false);
    m_buildSubProjectContextMenu->setEnabled(false);
    m_rebuildSubProjectContextMenu->setEnabled(false);
    m_cleanSubProjectContextMenu->setEnabled(false);

    Qt4ProFileNode *proFileNode = qobject_cast<Qt4ProFileNode *>(node);
    if (qobject_cast<Qt4Project *>(project) && proFileNode) {
        m_runQMakeActionContextMenu->setVisible(true);
        m_buildSubProjectContextMenu->setVisible(true);
        m_rebuildSubProjectContextMenu->setVisible(true);
        m_cleanSubProjectContextMenu->setVisible(true);

        if (!m_projectExplorer->buildManager()->isBuilding(project)) {
            m_runQMakeActionContextMenu->setEnabled(true);
            m_buildSubProjectContextMenu->setEnabled(true);
            m_rebuildSubProjectContextMenu->setEnabled(true);
            m_cleanSubProjectContextMenu->setEnabled(true);
        }
    } else {
        m_runQMakeActionContextMenu->setVisible(false);
        m_buildSubProjectContextMenu->setVisible(false);
        m_rebuildSubProjectContextMenu->setVisible(false);
        m_cleanSubProjectContextMenu->setVisible(false);
    }
}

void Qt4ProjectManagerPlugin::currentProjectChanged()
{
    m_runQMakeAction->setEnabled(!m_projectExplorer->buildManager()->isBuilding(m_projectExplorer->currentProject()));
}

void Qt4ProjectManagerPlugin::currentNodeChanged(ProjectExplorer::Node *node)
{
    m_addLibraryActionContextMenu->setEnabled(qobject_cast<Qt4ProFileNode *>(node));
}

void Qt4ProjectManagerPlugin::buildStateChanged(ProjectExplorer::Project *pro)
{
    ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
    if (pro == currentProject)
        m_runQMakeAction->setEnabled(!m_projectExplorer->buildManager()->isBuilding(currentProject));
    if (pro == m_qt4ProjectManager->contextProject())
        m_runQMakeActionContextMenu->setEnabled(!m_projectExplorer->buildManager()->isBuilding(pro));
}

void Qt4ProjectManagerPlugin::jumpToFile()
{
    Core::EditorManager *em = Core::EditorManager::instance();
    ProFileEditorWidget *editor = qobject_cast<ProFileEditorWidget*>(em->currentEditor()->widget());
    if (editor)
        editor->jumpToFile();
}

Q_EXPORT_PLUGIN(Qt4ProjectManagerPlugin)
<commit_msg>Remove dead code<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "qt4projectmanagerplugin.h"

#include "qt4projectmanager.h"
#include "qt4nodes.h"
#include "qmakestep.h"
#include "makestep.h"
#include "wizards/consoleappwizard.h"
#include "wizards/guiappwizard.h"
#include "wizards/mobileappwizard.h"
#include "wizards/librarywizard.h"
#include "wizards/testwizard.h"
#include "wizards/emptyprojectwizard.h"
#include "wizards/subdirsprojectwizard.h"
#include "wizards/qtquickappwizard.h"
#include "wizards/html5appwizard.h"
#include "customwidgetwizard/customwidgetwizard.h"
#include "profileeditorfactory.h"
#include "profilehoverhandler.h"
#include "qt4projectmanagerconstants.h"
#include "qt4project.h"
#include "profileeditor.h"
#include "externaleditors.h"
#include "profilecompletionassist.h"
#include "qt-s60/s60manager.h"
#include "qt-desktop/qt4desktoptargetfactory.h"
#include "qt-desktop/qt4simulatortargetfactory.h"
#include "qt-desktop/qt4runconfiguration.h"
#include "qt-desktop/desktopqtversionfactory.h"
#include "qt-desktop/simulatorqtversionfactory.h"
#include "winceqtversionfactory.h"

#include <coreplugin/id.h>
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/editormanager/editormanager.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h>

#ifdef WITH_TESTS
#    include <QTest>
#endif

#include <QtCore/QtPlugin>
#include <QtGui/QMenu>

using namespace Qt4ProjectManager::Internal;
using namespace Qt4ProjectManager;
using ProjectExplorer::Project;

Qt4ProjectManagerPlugin::~Qt4ProjectManagerPlugin()
{
    //removeObject(m_embeddedPropertiesPage);
    //delete m_embeddedPropertiesPage;

    removeObject(m_proFileEditorFactory);
    delete m_proFileEditorFactory;
    removeObject(m_qt4ProjectManager);
    delete m_qt4ProjectManager;
}

bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
    Q_UNUSED(arguments)
    const Core::Context projectContext(Qt4ProjectManager::Constants::PROJECT_ID);
    Core::Context projecTreeContext(ProjectExplorer::Constants::C_PROJECT_TREE);

    Core::ICore *core = Core::ICore::instance();
    if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":qt4projectmanager/Qt4ProjectManager.mimetypes.xml"), errorMessage))
        return false;

    m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
    Core::ActionManager *am = core->actionManager();

    //create and register objects
    m_qt4ProjectManager = new Qt4Manager(this);
    addObject(m_qt4ProjectManager);

    TextEditor::TextEditorActionHandler *editorHandler
            = new TextEditor::TextEditorActionHandler(Constants::C_PROFILEEDITOR,
                  TextEditor::TextEditorActionHandler::UnCommentSelection);

    m_proFileEditorFactory = new ProFileEditorFactory(m_qt4ProjectManager, editorHandler);
    addObject(m_proFileEditorFactory);

    addAutoReleasedObject(new EmptyProjectWizard);
    addAutoReleasedObject(new SubdirsProjectWizard);
    addAutoReleasedObject(new GuiAppWizard);
    addAutoReleasedObject(new ConsoleAppWizard);
    addAutoReleasedObject(new MobileAppWizard);
    addAutoReleasedObject(new QtQuickAppWizard);
    addAutoReleasedObject(new Html5AppWizard);
    addAutoReleasedObject(new LibraryWizard);
    addAutoReleasedObject(new TestWizard);
    addAutoReleasedObject(new CustomWidgetWizard);

    CustomQt4ProjectWizard::registerSelf();

    addAutoReleasedObject(new QMakeStepFactory);
    addAutoReleasedObject(new MakeStepFactory);

    addAutoReleasedObject(new Qt4RunConfigurationFactory);

#ifdef Q_OS_MAC
    addAutoReleasedObject(new MacDesignerExternalEditor);
#else
    addAutoReleasedObject(new DesignerExternalEditor);
#endif
    addAutoReleasedObject(new LinguistExternalEditor);

    addAutoReleasedObject(new S60Manager);

    addAutoReleasedObject(new Qt4DesktopTargetFactory);
    addAutoReleasedObject(new Qt4SimulatorTargetFactory);

    addAutoReleasedObject(new DesktopQtVersionFactory);
    addAutoReleasedObject(new SimulatorQtVersionFactory);
    addAutoReleasedObject(new WinCeQtVersionFactory);

    addAutoReleasedObject(new ProFileCompletionAssistProvider);
    addAutoReleasedObject(new ProFileHoverHandler(this));

    //menus
    Core::ActionContainer *mbuild =
            am->actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
    Core::ActionContainer *mproject =
            am->actionContainer(ProjectExplorer::Constants::M_PROJECTCONTEXT);
    Core::ActionContainer *msubproject =
            am->actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT);

    //register actions
    Core::Command *command;

    QIcon qmakeIcon(QLatin1String(":/qt4projectmanager/images/run_qmake.png"));
    qmakeIcon.addFile(QLatin1String(":/qt4projectmanager/images/run_qmake_small.png"));
    m_runQMakeAction = new QAction(qmakeIcon, tr("Run qmake"), this);
    command = am->registerAction(m_runQMakeAction, Constants::RUNQMAKE, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_PROJECT);
    connect(m_runQMakeAction, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMake()));

    m_runQMakeActionContextMenu = new QAction(qmakeIcon, tr("Run qmake"), this);
    command = am->registerAction(m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_runQMakeActionContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(runQMakeContextMenu()));

    QIcon buildIcon = QIcon(QLatin1String(ProjectExplorer::Constants::ICON_BUILD));
    buildIcon.addFile(QLatin1String(ProjectExplorer::Constants::ICON_BUILD_SMALL));
    m_buildSubProjectContextMenu = new QAction(buildIcon, tr("Build"), this);
    command = am->registerAction(m_buildSubProjectContextMenu, Constants::BUILDSUBDIR, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_buildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(buildSubDirContextMenu()));

    QIcon rebuildIcon = QIcon(QLatin1String(ProjectExplorer::Constants::ICON_REBUILD));
    rebuildIcon.addFile(QLatin1String(ProjectExplorer::Constants::ICON_REBUILD_SMALL));
    m_rebuildSubProjectContextMenu = new QAction(rebuildIcon, tr("Rebuild"), this);
    command = am->registerAction(m_rebuildSubProjectContextMenu, Constants::REBUILDSUBDIR, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_rebuildSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(rebuildSubDirContextMenu()));

    QIcon cleanIcon = QIcon(QLatin1String(ProjectExplorer::Constants::ICON_CLEAN));
    cleanIcon.addFile(QLatin1String(ProjectExplorer::Constants::ICON_CLEAN_SMALL));
    m_cleanSubProjectContextMenu = new QAction(cleanIcon, tr("Clean"), this);
    command = am->registerAction(m_cleanSubProjectContextMenu, Constants::CLEANSUBDIR, projectContext);
    command->setAttribute(Core::Command::CA_Hide);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
    connect(m_cleanSubProjectContextMenu, SIGNAL(triggered()), m_qt4ProjectManager, SLOT(cleanSubDirContextMenu()));

    connect(m_projectExplorer,
            SIGNAL(aboutToShowContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)),
            this, SLOT(updateContextMenu(ProjectExplorer::Project*, ProjectExplorer::Node*)));

    connect(m_projectExplorer->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project *)),
            this, SLOT(buildStateChanged(ProjectExplorer::Project *)));
    connect(m_projectExplorer, SIGNAL(currentProjectChanged(ProjectExplorer::Project *)),
            this, SLOT(currentProjectChanged()));
    connect(m_projectExplorer, SIGNAL(currentNodeChanged(ProjectExplorer::Node*,ProjectExplorer::Project*)),
            this, SLOT(currentNodeChanged(ProjectExplorer::Node*)));

    Core::ActionContainer *contextMenu = am->createMenu(Qt4ProjectManager::Constants::M_CONTEXT);

    Core::Context proFileEditorContext = Core::Context(Qt4ProjectManager::Constants::C_PROFILEEDITOR);

    QAction *jumpToFile = new QAction(tr("Jump to File Under Cursor"), this);
    command = am->registerAction(jumpToFile,
        Constants::JUMP_TO_FILE, proFileEditorContext);
    command->setDefaultKeySequence(QKeySequence(Qt::Key_F2));
    connect(jumpToFile, SIGNAL(triggered()),
            this, SLOT(jumpToFile()));
    contextMenu->addAction(command);

    m_addLibraryAction = new QAction(tr("Add Library..."), this);
    command = am->registerAction(m_addLibraryAction,
        Constants::ADDLIBRARY, proFileEditorContext);
    connect(m_addLibraryAction, SIGNAL(triggered()),
            m_qt4ProjectManager, SLOT(addLibrary()));
    contextMenu->addAction(command);

    m_addLibraryActionContextMenu = new QAction(tr("Add Library..."), this);
    command = am->registerAction(m_addLibraryActionContextMenu,
        Constants::ADDLIBRARY, projecTreeContext);
    connect(m_addLibraryActionContextMenu, SIGNAL(triggered()),
            m_qt4ProjectManager, SLOT(addLibraryContextMenu()));
    mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES);
    msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES);

    QAction *separator = new QAction(this);
    separator->setSeparator(true);
    contextMenu->addAction(am->registerAction(separator,
                  Core::Id(Constants::SEPARATOR), proFileEditorContext));

    command = am->command(TextEditor::Constants::UN_COMMENT_SELECTION);
    contextMenu->addAction(command);

    return true;
}

void Qt4ProjectManagerPlugin::extensionsInitialized()
{
    m_qt4ProjectManager->init();
}

void Qt4ProjectManagerPlugin::updateContextMenu(Project *project,
                                                ProjectExplorer::Node *node)
{
    m_qt4ProjectManager->setContextProject(project);
    m_qt4ProjectManager->setContextNode(node);
    m_runQMakeActionContextMenu->setEnabled(false);
    m_buildSubProjectContextMenu->setEnabled(false);
    m_rebuildSubProjectContextMenu->setEnabled(false);
    m_cleanSubProjectContextMenu->setEnabled(false);

    Qt4ProFileNode *proFileNode = qobject_cast<Qt4ProFileNode *>(node);
    if (qobject_cast<Qt4Project *>(project) && proFileNode) {
        m_runQMakeActionContextMenu->setVisible(true);
        m_buildSubProjectContextMenu->setVisible(true);
        m_rebuildSubProjectContextMenu->setVisible(true);
        m_cleanSubProjectContextMenu->setVisible(true);

        if (!m_projectExplorer->buildManager()->isBuilding(project)) {
            m_runQMakeActionContextMenu->setEnabled(true);
            m_buildSubProjectContextMenu->setEnabled(true);
            m_rebuildSubProjectContextMenu->setEnabled(true);
            m_cleanSubProjectContextMenu->setEnabled(true);
        }
    } else {
        m_runQMakeActionContextMenu->setVisible(false);
        m_buildSubProjectContextMenu->setVisible(false);
        m_rebuildSubProjectContextMenu->setVisible(false);
        m_cleanSubProjectContextMenu->setVisible(false);
    }
}

void Qt4ProjectManagerPlugin::currentProjectChanged()
{
    m_runQMakeAction->setEnabled(!m_projectExplorer->buildManager()->isBuilding(m_projectExplorer->currentProject()));
}

void Qt4ProjectManagerPlugin::currentNodeChanged(ProjectExplorer::Node *node)
{
    m_addLibraryActionContextMenu->setEnabled(qobject_cast<Qt4ProFileNode *>(node));
}

void Qt4ProjectManagerPlugin::buildStateChanged(ProjectExplorer::Project *pro)
{
    ProjectExplorer::Project *currentProject = m_projectExplorer->currentProject();
    if (pro == currentProject)
        m_runQMakeAction->setEnabled(!m_projectExplorer->buildManager()->isBuilding(currentProject));
    if (pro == m_qt4ProjectManager->contextProject())
        m_runQMakeActionContextMenu->setEnabled(!m_projectExplorer->buildManager()->isBuilding(pro));
}

void Qt4ProjectManagerPlugin::jumpToFile()
{
    Core::EditorManager *em = Core::EditorManager::instance();
    ProFileEditorWidget *editor = qobject_cast<ProFileEditorWidget*>(em->currentEditor()->widget());
    if (editor)
        editor->jumpToFile();
}

Q_EXPORT_PLUGIN(Qt4ProjectManagerPlugin)
<|endoftext|>


<commit_before>// SwiftShader Software Renderer
//
// Copyright(c) 2005-2013 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

// Config.cpp: Implements the egl::Config class, describing the format, type
// and size for an egl::Surface. Implements EGLConfig and related functionality.
// [EGL 1.4] section 3.4 page 15.

#include "Config.h"

#include "common/debug.h"

#include <algorithm>
#include <vector>

using namespace std;

namespace egl
{
Config::Config(const DisplayMode &displayMode, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
    : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
{
    mBindToTextureRGB = EGL_FALSE;
    mBindToTextureRGBA = EGL_FALSE;

    switch (renderTargetFormat)
    {
      case sw::FORMAT_A1R5G5B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 5;
        mBlueSize = 5;
        mAlphaSize = 1;
        break;
      case sw::FORMAT_A2R10G10B10:
        mBufferSize = 32;
        mRedSize = 10;
        mGreenSize = 10;
        mBlueSize = 10;
        mAlphaSize = 2;
        break;
      case sw::FORMAT_A8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 8;
        mBindToTextureRGBA = true;
        break;
      case sw::FORMAT_R5G6B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 6;
        mBlueSize = 5;
        mAlphaSize = 0;
        break;
      case sw::FORMAT_X8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 0;
        mBindToTextureRGB = true;
        break;
      default:
        UNREACHABLE();   // Other formats should not be valid
    }

    mLuminanceSize = 0;
    mAlphaMaskSize = 0;
    mColorBufferType = EGL_RGB_BUFFER;
    mConfigCaveat = isSlowConfig() ? EGL_SLOW_CONFIG : EGL_NONE;
    mConfigID = 0;
    mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;

	switch (depthStencilFormat)
	{
	case sw::FORMAT_NULL:
		mDepthSize = 0;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D16_LOCKABLE:
//      mDepthSize = 16;
//      mStencilSize = 0;
//      break;
	case sw::FORMAT_D32:
		mDepthSize = 32;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D15S1:
//		mDepthSize = 15;
//		mStencilSize = 1;
//		break;
	case sw::FORMAT_D24S8:
		mDepthSize = 24;
		mStencilSize = 8;
		break;
	case sw::FORMAT_D24X8:
		mDepthSize = 24;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D24X4S4:
//		mDepthSize = 24;
//		mStencilSize = 4;
//		break;
	case sw::FORMAT_D16:
		mDepthSize = 16;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D32F_LOCKABLE:
//      mDepthSize = 32;
//      mStencilSize = 0;
//      break;
//  case sw::FORMAT_D24FS8:
//      mDepthSize = 24;
//      mStencilSize = 8;
//      break;
	  default:
		UNREACHABLE();
	}

    mLevel = 0;
    mMatchNativePixmap = EGL_NONE;
    mMaxPBufferWidth = 4096;
    mMaxPBufferHeight = 4096;
    mMaxPBufferPixels = mMaxPBufferWidth * mMaxPBufferHeight;
    mMaxSwapInterval = maxInterval;
    mMinSwapInterval = minInterval;
    mNativeRenderable = EGL_FALSE;
    mNativeVisualID = 0;
    mNativeVisualType = 0;
    mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;
    mSampleBuffers = multiSample ? 1 : 0;
    mSamples = multiSample;
    mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    mTransparentType = EGL_NONE;
    mTransparentRedValue = 0;
    mTransparentGreenValue = 0;
    mTransparentBlueValue = 0;
}

EGLConfig Config::getHandle() const
{
    return (EGLConfig)(size_t)mConfigID;
}

bool Config::isSlowConfig() const
{
    if(mDisplayMode.format == sw::FORMAT_X8R8G8B8 && mRenderTargetFormat == sw::FORMAT_A8R8G8B8)
	{
		return false;
	}

    return mDisplayMode.format != mRenderTargetFormat;
}

SortConfig::SortConfig(const EGLint *attribList)
    : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
{
    scanForWantedComponents(attribList);
}

void SortConfig::scanForWantedComponents(const EGLint *attribList)
{
    // [EGL] section 3.4.1 page 24
    // Sorting rule #3: by larger total number of color bits, not considering
    // components that are 0 or don't-care.
    for(const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
    {
        if(attr[1] != 0 && attr[1] != EGL_DONT_CARE)
        {
            switch (attr[0])
            {
              case EGL_RED_SIZE:       mWantRed = true; break;
              case EGL_GREEN_SIZE:     mWantGreen = true; break;
              case EGL_BLUE_SIZE:      mWantBlue = true; break;
              case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
              case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
            }
        }
    }
}

EGLint SortConfig::wantedComponentsSize(const Config &config) const
{
    EGLint total = 0;

    if(mWantRed)       total += config.mRedSize;
    if(mWantGreen)     total += config.mGreenSize;
    if(mWantBlue)      total += config.mBlueSize;
    if(mWantAlpha)     total += config.mAlphaSize;
    if(mWantLuminance) total += config.mLuminanceSize;

    return total;
}

bool SortConfig::operator()(const Config *x, const Config *y) const
{
    return (*this)(*x, *y);
}

bool SortConfig::operator()(const Config &x, const Config &y) const
{
    #define SORT(attribute)                        \
        if(x.attribute != y.attribute)             \
        {                                          \
            return x.attribute < y.attribute;      \
        }

    META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
    SORT(mConfigCaveat);

    META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
    SORT(mColorBufferType);

    // By larger total number of color bits, only considering those that are requested to be > 0.
    EGLint xComponentsSize = wantedComponentsSize(x);
    EGLint yComponentsSize = wantedComponentsSize(y);
    if(xComponentsSize != yComponentsSize)
    {
        return xComponentsSize > yComponentsSize;
    }

    SORT(mBufferSize);
    SORT(mSampleBuffers);
    SORT(mSamples);
    SORT(mDepthSize);
    SORT(mStencilSize);
    SORT(mAlphaMaskSize);
    SORT(mNativeVisualType);
    SORT(mConfigID);

    #undef SORT

    return false;
}

// We'd like to use SortConfig to also eliminate duplicate configs.
// This works as long as we never have two configs with different per-RGB-component layouts,
// but the same total.
// 5551 and 565 are different because R+G+B is different.
// 5551 and 555 are different because bufferSize is different.
const EGLint ConfigSet::mSortAttribs[] =
{
    EGL_RED_SIZE, 1,
    EGL_GREEN_SIZE, 1,
    EGL_BLUE_SIZE, 1,
    EGL_LUMINANCE_SIZE, 1,
    // BUT NOT ALPHA
    EGL_NONE
};

ConfigSet::ConfigSet()
    : mSet(SortConfig(mSortAttribs))
{
}

void ConfigSet::add(const DisplayMode &displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
{
    Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample);

    mSet.insert(config);
}

size_t ConfigSet::size() const
{
    return mSet.size();
}

bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
{
    vector<const Config*> passed;
    passed.reserve(mSet.size());

    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        bool match = true;
        const EGLint *attribute = attribList;

        while(attribute[0] != EGL_NONE)
        {
            switch(attribute[0])
            {
            case EGL_BUFFER_SIZE:             match = config->mBufferSize >= attribute[1];                      break;
            case EGL_ALPHA_SIZE:              match = config->mAlphaSize >= attribute[1];                       break;
            case EGL_BLUE_SIZE:               match = config->mBlueSize >= attribute[1];                        break;
            case EGL_GREEN_SIZE:              match = config->mGreenSize >= attribute[1];                       break;
            case EGL_RED_SIZE:                match = config->mRedSize >= attribute[1];                         break;
            case EGL_DEPTH_SIZE:              match = config->mDepthSize >= attribute[1];                       break;
            case EGL_STENCIL_SIZE:            match = config->mStencilSize >= attribute[1];                     break;
            case EGL_CONFIG_CAVEAT:           match = config->mConfigCaveat == attribute[1];                    break;
            case EGL_CONFIG_ID:               match = config->mConfigID == attribute[1];                        break;
            case EGL_LEVEL:                   match = config->mLevel >= attribute[1];                           break;
            case EGL_NATIVE_RENDERABLE:       match = config->mNativeRenderable == attribute[1];                break;
            case EGL_NATIVE_VISUAL_ID:        match = config->mNativeVisualID == attribute[1];                  break;
            case EGL_NATIVE_VISUAL_TYPE:      match = config->mNativeVisualType == attribute[1];                break;
            case EGL_SAMPLES:                 match = config->mSamples >= attribute[1];                         break;
            case EGL_SAMPLE_BUFFERS:          match = config->mSampleBuffers >= attribute[1];                   break;
            case EGL_SURFACE_TYPE:            match = (config->mSurfaceType & attribute[1]) == attribute[1];    break;
            case EGL_TRANSPARENT_TYPE:        match = config->mTransparentType == attribute[1];                 break;
            case EGL_TRANSPARENT_BLUE_VALUE:  match = config->mTransparentBlueValue == attribute[1];            break;
            case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1];           break;
            case EGL_TRANSPARENT_RED_VALUE:   match = config->mTransparentRedValue == attribute[1];             break;
            case EGL_BIND_TO_TEXTURE_RGB:     match = config->mBindToTextureRGB == attribute[1];                break;
            case EGL_BIND_TO_TEXTURE_RGBA:    match = config->mBindToTextureRGBA == attribute[1];               break;
            case EGL_MIN_SWAP_INTERVAL:       match = config->mMinSwapInterval == attribute[1];                 break;
            case EGL_MAX_SWAP_INTERVAL:       match = config->mMaxSwapInterval == attribute[1];                 break;
            case EGL_LUMINANCE_SIZE:          match = config->mLuminanceSize >= attribute[1];                   break;
            case EGL_ALPHA_MASK_SIZE:         match = config->mAlphaMaskSize >= attribute[1];                   break;
            case EGL_COLOR_BUFFER_TYPE:       match = config->mColorBufferType == attribute[1];                 break;
            case EGL_RENDERABLE_TYPE:         match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
            case EGL_MATCH_NATIVE_PIXMAP:     match = false; UNIMPLEMENTED();                                   break;
            case EGL_CONFORMANT:              match = (config->mConformant & attribute[1]) == attribute[1];     break;
            case EGL_MAX_PBUFFER_WIDTH:       match = config->mMaxPBufferWidth >= attribute[1];                 break;
            case EGL_MAX_PBUFFER_HEIGHT:      match = config->mMaxPBufferHeight >= attribute[1];                break;
            case EGL_MAX_PBUFFER_PIXELS:      match = config->mMaxPBufferPixels >= attribute[1];                break;
			default:
				UNIMPLEMENTED();
				match = false;
            }

            if(!match)
            {
                break;
            }

            attribute += 2;
        }

        if(match)
        {
            passed.push_back(&*config);
        }
    }

    if(configs)
    {
        sort(passed.begin(), passed.end(), SortConfig(attribList));

        EGLint index;
        for(index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
        {
            configs[index] = passed[index]->getHandle();
        }

        *numConfig = index;
    }
    else
    {
        *numConfig = static_cast<EGLint>(passed.size());
    }

    return true;
}

const egl::Config *ConfigSet::get(EGLConfig configHandle)
{
    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        if(config->getHandle() == configHandle)
        {
            return &(*config);
        }
    }

    return NULL;
}
}
<commit_msg>Ignore Android EGL config attributes.<commit_after>// SwiftShader Software Renderer
//
// Copyright(c) 2005-2013 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

// Config.cpp: Implements the egl::Config class, describing the format, type
// and size for an egl::Surface. Implements EGLConfig and related functionality.
// [EGL 1.4] section 3.4 page 15.

#include "Config.h"

#include "common/debug.h"

#define EGLAPI
#include <EGL/eglext.h>

#include <algorithm>
#include <vector>

using namespace std;

namespace egl
{
Config::Config(const DisplayMode &displayMode, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
    : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
{
    mBindToTextureRGB = EGL_FALSE;
    mBindToTextureRGBA = EGL_FALSE;

    switch (renderTargetFormat)
    {
      case sw::FORMAT_A1R5G5B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 5;
        mBlueSize = 5;
        mAlphaSize = 1;
        break;
      case sw::FORMAT_A2R10G10B10:
        mBufferSize = 32;
        mRedSize = 10;
        mGreenSize = 10;
        mBlueSize = 10;
        mAlphaSize = 2;
        break;
      case sw::FORMAT_A8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 8;
        mBindToTextureRGBA = true;
        break;
      case sw::FORMAT_R5G6B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 6;
        mBlueSize = 5;
        mAlphaSize = 0;
        break;
      case sw::FORMAT_X8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 0;
        mBindToTextureRGB = true;
        break;
      default:
        UNREACHABLE();   // Other formats should not be valid
    }

    mLuminanceSize = 0;
    mAlphaMaskSize = 0;
    mColorBufferType = EGL_RGB_BUFFER;
    mConfigCaveat = isSlowConfig() ? EGL_SLOW_CONFIG : EGL_NONE;
    mConfigID = 0;
    mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;

	switch (depthStencilFormat)
	{
	case sw::FORMAT_NULL:
		mDepthSize = 0;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D16_LOCKABLE:
//      mDepthSize = 16;
//      mStencilSize = 0;
//      break;
	case sw::FORMAT_D32:
		mDepthSize = 32;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D15S1:
//		mDepthSize = 15;
//		mStencilSize = 1;
//		break;
	case sw::FORMAT_D24S8:
		mDepthSize = 24;
		mStencilSize = 8;
		break;
	case sw::FORMAT_D24X8:
		mDepthSize = 24;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D24X4S4:
//		mDepthSize = 24;
//		mStencilSize = 4;
//		break;
	case sw::FORMAT_D16:
		mDepthSize = 16;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D32F_LOCKABLE:
//      mDepthSize = 32;
//      mStencilSize = 0;
//      break;
//  case sw::FORMAT_D24FS8:
//      mDepthSize = 24;
//      mStencilSize = 8;
//      break;
	  default:
		UNREACHABLE();
	}

    mLevel = 0;
    mMatchNativePixmap = EGL_NONE;
    mMaxPBufferWidth = 4096;
    mMaxPBufferHeight = 4096;
    mMaxPBufferPixels = mMaxPBufferWidth * mMaxPBufferHeight;
    mMaxSwapInterval = maxInterval;
    mMinSwapInterval = minInterval;
    mNativeRenderable = EGL_FALSE;
    mNativeVisualID = 0;
    mNativeVisualType = 0;
    mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT;
    mSampleBuffers = multiSample ? 1 : 0;
    mSamples = multiSample;
    mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    mTransparentType = EGL_NONE;
    mTransparentRedValue = 0;
    mTransparentGreenValue = 0;
    mTransparentBlueValue = 0;
}

EGLConfig Config::getHandle() const
{
    return (EGLConfig)(size_t)mConfigID;
}

bool Config::isSlowConfig() const
{
    if(mDisplayMode.format == sw::FORMAT_X8R8G8B8 && mRenderTargetFormat == sw::FORMAT_A8R8G8B8)
	{
		return false;
	}

    return mDisplayMode.format != mRenderTargetFormat;
}

SortConfig::SortConfig(const EGLint *attribList)
    : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
{
    scanForWantedComponents(attribList);
}

void SortConfig::scanForWantedComponents(const EGLint *attribList)
{
    // [EGL] section 3.4.1 page 24
    // Sorting rule #3: by larger total number of color bits, not considering
    // components that are 0 or don't-care.
    for(const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
    {
        if(attr[1] != 0 && attr[1] != EGL_DONT_CARE)
        {
            switch (attr[0])
            {
              case EGL_RED_SIZE:       mWantRed = true; break;
              case EGL_GREEN_SIZE:     mWantGreen = true; break;
              case EGL_BLUE_SIZE:      mWantBlue = true; break;
              case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
              case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
            }
        }
    }
}

EGLint SortConfig::wantedComponentsSize(const Config &config) const
{
    EGLint total = 0;

    if(mWantRed)       total += config.mRedSize;
    if(mWantGreen)     total += config.mGreenSize;
    if(mWantBlue)      total += config.mBlueSize;
    if(mWantAlpha)     total += config.mAlphaSize;
    if(mWantLuminance) total += config.mLuminanceSize;

    return total;
}

bool SortConfig::operator()(const Config *x, const Config *y) const
{
    return (*this)(*x, *y);
}

bool SortConfig::operator()(const Config &x, const Config &y) const
{
    #define SORT(attribute)                        \
        if(x.attribute != y.attribute)             \
        {                                          \
            return x.attribute < y.attribute;      \
        }

    META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
    SORT(mConfigCaveat);

    META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
    SORT(mColorBufferType);

    // By larger total number of color bits, only considering those that are requested to be > 0.
    EGLint xComponentsSize = wantedComponentsSize(x);
    EGLint yComponentsSize = wantedComponentsSize(y);
    if(xComponentsSize != yComponentsSize)
    {
        return xComponentsSize > yComponentsSize;
    }

    SORT(mBufferSize);
    SORT(mSampleBuffers);
    SORT(mSamples);
    SORT(mDepthSize);
    SORT(mStencilSize);
    SORT(mAlphaMaskSize);
    SORT(mNativeVisualType);
    SORT(mConfigID);

    #undef SORT

    return false;
}

// We'd like to use SortConfig to also eliminate duplicate configs.
// This works as long as we never have two configs with different per-RGB-component layouts,
// but the same total.
// 5551 and 565 are different because R+G+B is different.
// 5551 and 555 are different because bufferSize is different.
const EGLint ConfigSet::mSortAttribs[] =
{
    EGL_RED_SIZE, 1,
    EGL_GREEN_SIZE, 1,
    EGL_BLUE_SIZE, 1,
    EGL_LUMINANCE_SIZE, 1,
    // BUT NOT ALPHA
    EGL_NONE
};

ConfigSet::ConfigSet()
    : mSet(SortConfig(mSortAttribs))
{
}

void ConfigSet::add(const DisplayMode &displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
{
    Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample);

    mSet.insert(config);
}

size_t ConfigSet::size() const
{
    return mSet.size();
}

bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
{
    vector<const Config*> passed;
    passed.reserve(mSet.size());

    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        bool match = true;
        const EGLint *attribute = attribList;

        while(attribute[0] != EGL_NONE)
        {
            switch(attribute[0])
            {
            case EGL_BUFFER_SIZE:                match = config->mBufferSize >= attribute[1];                      break;
            case EGL_ALPHA_SIZE:                 match = config->mAlphaSize >= attribute[1];                       break;
            case EGL_BLUE_SIZE:                  match = config->mBlueSize >= attribute[1];                        break;
            case EGL_GREEN_SIZE:                 match = config->mGreenSize >= attribute[1];                       break;
            case EGL_RED_SIZE:                   match = config->mRedSize >= attribute[1];                         break;
            case EGL_DEPTH_SIZE:                 match = config->mDepthSize >= attribute[1];                       break;
            case EGL_STENCIL_SIZE:               match = config->mStencilSize >= attribute[1];                     break;
            case EGL_CONFIG_CAVEAT:              match = config->mConfigCaveat == attribute[1];                    break;
            case EGL_CONFIG_ID:                  match = config->mConfigID == attribute[1];                        break;
            case EGL_LEVEL:                      match = config->mLevel >= attribute[1];                           break;
            case EGL_NATIVE_RENDERABLE:          match = config->mNativeRenderable == attribute[1];                break;
            case EGL_NATIVE_VISUAL_ID:           match = config->mNativeVisualID == attribute[1];                  break;
            case EGL_NATIVE_VISUAL_TYPE:         match = config->mNativeVisualType == attribute[1];                break;
            case EGL_SAMPLES:                    match = config->mSamples >= attribute[1];                         break;
            case EGL_SAMPLE_BUFFERS:             match = config->mSampleBuffers >= attribute[1];                   break;
            case EGL_SURFACE_TYPE:               match = (config->mSurfaceType & attribute[1]) == attribute[1];    break;
            case EGL_TRANSPARENT_TYPE:           match = config->mTransparentType == attribute[1];                 break;
            case EGL_TRANSPARENT_BLUE_VALUE:     match = config->mTransparentBlueValue == attribute[1];            break;
            case EGL_TRANSPARENT_GREEN_VALUE:    match = config->mTransparentGreenValue == attribute[1];           break;
            case EGL_TRANSPARENT_RED_VALUE:      match = config->mTransparentRedValue == attribute[1];             break;
            case EGL_BIND_TO_TEXTURE_RGB:        match = config->mBindToTextureRGB == attribute[1];                break;
            case EGL_BIND_TO_TEXTURE_RGBA:       match = config->mBindToTextureRGBA == attribute[1];               break;
            case EGL_MIN_SWAP_INTERVAL:          match = config->mMinSwapInterval == attribute[1];                 break;
            case EGL_MAX_SWAP_INTERVAL:          match = config->mMaxSwapInterval == attribute[1];                 break;
            case EGL_LUMINANCE_SIZE:             match = config->mLuminanceSize >= attribute[1];                   break;
            case EGL_ALPHA_MASK_SIZE:            match = config->mAlphaMaskSize >= attribute[1];                   break;
            case EGL_COLOR_BUFFER_TYPE:          match = config->mColorBufferType == attribute[1];                 break;
            case EGL_RENDERABLE_TYPE:            match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
            case EGL_MATCH_NATIVE_PIXMAP:        match = false; UNIMPLEMENTED();                                   break;
            case EGL_CONFORMANT:                 match = (config->mConformant & attribute[1]) == attribute[1];     break;
            case EGL_MAX_PBUFFER_WIDTH:          match = config->mMaxPBufferWidth >= attribute[1];                 break;
            case EGL_MAX_PBUFFER_HEIGHT:         match = config->mMaxPBufferHeight >= attribute[1];                break;
            case EGL_MAX_PBUFFER_PIXELS:         match = config->mMaxPBufferPixels >= attribute[1];                break;
			case EGL_RECORDABLE_ANDROID:         match = false; /* UNIMPLEMENTED(); */                             break;
			case EGL_FRAMEBUFFER_TARGET_ANDROID: match = false; /* UNIMPLEMENTED(); */                             break;
			default:
				UNIMPLEMENTED();
				match = false;
            }

            if(!match)
            {
                break;
            }

            attribute += 2;
        }

        if(match)
        {
            passed.push_back(&*config);
        }
    }

    if(configs)
    {
        sort(passed.begin(), passed.end(), SortConfig(attribList));

        EGLint index;
        for(index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
        {
            configs[index] = passed[index]->getHandle();
        }

        *numConfig = index;
    }
    else
    {
        *numConfig = static_cast<EGLint>(passed.size());
    }

    return true;
}

const egl::Config *ConfigSet::get(EGLConfig configHandle)
{
    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        if(config->getHandle() == configHandle)
        {
            return &(*config);
        }
    }

    return NULL;
}
}
<|endoftext|>


<commit_before>/*
example of using cnot gate in QCPP library
*/
#include <iostream>
#include <cmath>
#include <QCPP.h>

int main() {

	// init state
	double prob = 1 / sqrt(2.0 * 4);
	Quantum qubits(3, {{1, prob}, {3, prob}, {5, prob}, {7, prob}});

	std::cout << "Before apply cnot gate" << std::endl;
	for(int i = 0;i < (1 << qubits.size());i++) {
		std::cout << "Probability of being " << i << " : " << qubits.getProbability(i) << std::endl;
	}

	qubits.controlled([&](Quantum::__qubit_index__ idx1, size_t idx2) {
		qubits.Not(idx1, idx2);
	}, 2, 0);

	std::cout << "After apply cnot gate" << std::endl;
	for(int i = 0;i < (1 << qubits.size());i++) {
		std::cout << "Probability of being " << i << " : " << qubits.getProbability(i) << std::endl;
	}

	return 0;
}<commit_msg>change controlled function<commit_after>/*
example of using cnot gate in QCPP library
*/
#include <iostream>
#include <cmath>
#include <QCPP.h>

int main() {

	// init state
	double prob = 1 / sqrt(2.0 * 4);
	Quantum qubits(3, {{1, prob}, {3, prob}, {5, prob}, {7, prob}});

	std::cout << "Before apply cnot gate" << std::endl;
	for(int i = 0;i < (1 << qubits.size());i++) {
		std::cout << "Probability of being " << i << " : " << qubits.getProbability(i) << std::endl;
	}

	qubits.controlled(qubits.Not(), 2, 0);

	std::cout << "After apply cnot gate" << std::endl;
	for(int i = 0;i < (1 << qubits.size());i++) {
		std::cout << "Probability of being " << i << " : " << qubits.getProbability(i) << std::endl;
	}

	return 0;
}<|endoftext|>


<commit_before>#include <array>
#include <iostream>
#include "immintrin.h"
#include "smmintrin.h"

struct vec4d {
    union {
        __m256d raw;
        double val[4];
    } data;

    vec4d(double x, double y, double z, double w) : data{x, y, z, w} {}
    vec4d(__m256d raw) : data{raw} {}
};

struct vec4f {
    union {
        __m128 raw;
        float val[4];
    } data;

    vec4f(float x, float y, float z, float w) : data{x, y, z, w} {}
    vec4f(__m128 raw) : data{raw} {}
};

std::ostream& operator<<(std::ostream& os, const vec4f& vec) {
    std::string delimiter = "";
    os << "(";
    for (const auto& val : vec.data.val) {
        os << delimiter << val;
        delimiter = ", ";
    }
    os << ")";
    return os;
}

std::ostream& operator<<(std::ostream& os, const vec4d& vec) {
    std::string delimiter = "";
    os << "(";
    for (const auto& val : vec.data.val) {
        os << delimiter << val;
        delimiter = ", ";
    }
    os << ")";
    return os;
}

float dot(const vec4f& a, const vec4f& b) {
    __m128 dp = _mm_dp_ps(a.data.raw, b.data.raw, 0xF1);
    return _mm_cvtss_f32(dp);
}

vec4f dot4(const std::array<vec4f,4>& a, const std::array<vec4f, 4>& b) {
    __m128 dp = _mm_or_ps(_mm_dp_ps(a[0].data.raw, b[0].data.raw, 0xF1),
                _mm_or_ps(_mm_dp_ps(a[1].data.raw, b[1].data.raw, 0xF2),
                _mm_or_ps(_mm_dp_ps(a[2].data.raw, b[2].data.raw, 0xF4),
                          _mm_dp_ps(a[3].data.raw, b[3].data.raw, 0xF8))));
    return dp;
}

void testDot() {
    std::cout << "dot: " << dot(vec4f{1.0f, 1.0f, 0.0f, 0.0f}, vec4f{1.0f, 1.0f, 0.0f, 0.0f}) << std::endl;
    std::cout << "dot: " << dot(vec4f{2.0f, 3.0f, 0.0f, 0.0f}, vec4f{5.0f, 5.0f, 0.0f, 0.0f}) << std::endl;
}

void testDot4() {
    std::array<vec4f, 4> dotInA{{
        vec4f{1.0f, 1.0f, 1.0f, 1.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f}
    }};
    std::array<vec4f, 4> dotInB{{
        vec4f{1.0f, 0.0f, 0.0f, 0.0f},
        vec4f{1.0f, 1.0f, 0.0f, 0.0f},
        vec4f{1.0f, 1.0f, 1.0f, 0.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f}
    }};
    vec4f dot4Res{dot4(dotInA, dotInB)};

    std::cout << "dot4: " << dot4Res << std::endl;
}

void testSetLoadMulAdd() {
    __m256d v1 = _mm256_set_pd(1.0, 2.0, 3.0, 4.0);
    __m256d v2 = _mm256_set_pd(2.0, 3.0, 4.0, 5.0);

    double values[4] __attribute__((aligned(32))) = {0.0, 1.0, 0.0, 1.0};
    double values2[4] __attribute__((aligned(32))) = {0.0, 1.0, 0.0, 1.0};
    __m256d v3 = _mm256_load_pd(values);
    __m256d v4 = _mm256_load_pd(values2);

    vec4d res{_mm256_mul_pd(v1, v2)};
    res.data.raw = _mm256_add_pd(res.data.raw, v3);
    res.data.raw = _mm256_add_pd(res.data.raw, v4);

    std::cout << "SetLoadMulAdd: " << res << std::endl;
}

int main() {
    testDot();
    testDot4();
    testSetLoadMulAdd();

    return 0;
}
<commit_msg>add matrix and matrix vector multiplication operator<commit_after>#include <array>
#include <iostream>
#include "immintrin.h"
#include "smmintrin.h"

struct vec4d {
    union {
        __m256d raw;
        double val[4];
    } data;

    vec4d(double x, double y, double z, double w) : data{x, y, z, w} {}
    vec4d(__m256d raw) : data{raw} {}
};

struct vec4f {
    union {
        __m128 raw;
        float val[4];
    } data;

    vec4f(float x, float y, float z, float w) : data{x, y, z, w} {}
    vec4f(__m128 raw) : data{raw} {}
};

std::ostream& operator<<(std::ostream& os, const vec4f& vec) {
    std::string delimiter = "";
    os << "(";
    for (const auto& val : vec.data.val) {
        os << delimiter << val;
        delimiter = ", ";
    }
    os << ")";
    return os;
}

std::ostream& operator<<(std::ostream& os, const vec4d& vec) {
    std::string delimiter = "";
    os << "(";
    for (const auto& val : vec.data.val) {
        os << delimiter << val;
        delimiter = ", ";
    }
    os << ")";
    return os;
}

struct mat4f {
    __m128 row0;
    __m128 row1;
    __m128 row2;
    __m128 row3;

    explicit mat4f(__m128 row0, __m128 row1, __m128 row2, __m128 row3) :
        row0(row0), row1(row1), row2(row2), row3(row3) {}
    explicit mat4f(vec4f row0, vec4f row1, vec4f row2, vec4f row3) :
        row0(row0.data.raw), row1(row1.data.raw), row2(row2.data.raw), row3(row3.data.raw) {}
    vec4f operator*(const vec4f& vec) const {
        return _mm_or_ps(_mm_dp_ps(row0, vec.data.raw, 0xF1),
               _mm_or_ps(_mm_dp_ps(row1, vec.data.raw, 0xF2),
               _mm_or_ps(_mm_dp_ps(row2, vec.data.raw, 0xF4),
                         _mm_dp_ps(row3, vec.data.raw, 0xF8))));
    }
};

float dot(const vec4f& a, const vec4f& b) {
    __m128 dp = _mm_dp_ps(a.data.raw, b.data.raw, 0xF1);
    return _mm_cvtss_f32(dp);
}

vec4f dot4(const std::array<vec4f,4>& a, const std::array<vec4f, 4>& b) {
    __m128 dp = _mm_or_ps(_mm_dp_ps(a[0].data.raw, b[0].data.raw, 0xF1),
                _mm_or_ps(_mm_dp_ps(a[1].data.raw, b[1].data.raw, 0xF2),
                _mm_or_ps(_mm_dp_ps(a[2].data.raw, b[2].data.raw, 0xF4),
                          _mm_dp_ps(a[3].data.raw, b[3].data.raw, 0xF8))));
    return dp;
}

void testDot() {
    std::cout << "dot: " << dot(vec4f{1.0f, 1.0f, 0.0f, 0.0f}, vec4f{1.0f, 1.0f, 0.0f, 0.0f}) << std::endl;
    std::cout << "dot: " << dot(vec4f{2.0f, 3.0f, 0.0f, 0.0f}, vec4f{5.0f, 5.0f, 0.0f, 0.0f}) << std::endl;
}

void testMat4f() {
    const mat4f id {{1.0f, 0.0f, 0.0f, 0.0f},
                    {0.0f, 1.0f, 0.0f, 0.0f},
                    {0.0f, 0.0f, 1.0f, 0.0f},
                    {0.0f, 0.0f, 0.0f, 1.0f}};

    const mat4f shuffle {{0.0f, 0.0f, 1.0f, 0.0f},
                         {0.0f, 0.0f, 0.0f, 1.0f},
                         {0.0f, 1.0f, 0.0f, 0.0f},
                         {1.0f, 0.0f, 0.0f, 0.0f}};

    const vec4f vec{1.0f, 2.0f, 3.0f, 4.0f};
    const vec4f unchanged = id * vec;
    const vec4f shuffled = shuffle * vec;

    std::cout << "testMat4f: " << unchanged << std::endl;
    std::cout << "testMat4f: " << shuffled << std::endl;
}

void testDot4() {
    std::array<vec4f, 4> dotInA{{
        vec4f{1.0f, 1.0f, 1.0f, 1.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f}
    }};
    std::array<vec4f, 4> dotInB{{
        vec4f{1.0f, 0.0f, 0.0f, 0.0f},
        vec4f{1.0f, 1.0f, 0.0f, 0.0f},
        vec4f{1.0f, 1.0f, 1.0f, 0.0f},
        vec4f{1.0f, 1.0f, 1.0f, 1.0f}
    }};
    vec4f dot4Res{dot4(dotInA, dotInB)};

    std::cout << "dot4: " << dot4Res << std::endl;
}

void testSetLoadMulAdd() {
    __m256d v1 = _mm256_set_pd(1.0, 2.0, 3.0, 4.0);
    __m256d v2 = _mm256_set_pd(2.0, 3.0, 4.0, 5.0);

    double values[4] __attribute__((aligned(32))) = {0.0, 1.0, 0.0, 1.0};
    double values2[4] __attribute__((aligned(32))) = {0.0, 1.0, 0.0, 1.0};
    __m256d v3 = _mm256_load_pd(values);
    __m256d v4 = _mm256_load_pd(values2);

    vec4d res{_mm256_mul_pd(v1, v2)};
    res.data.raw = _mm256_add_pd(res.data.raw, v3);
    res.data.raw = _mm256_add_pd(res.data.raw, v4);

    std::cout << "SetLoadMulAdd: " << res << std::endl;
}

int main() {
    testDot();
    testDot4();
    testSetLoadMulAdd();
    testMat4f();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * An istream which duplicates data.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_tee.hxx"
#include "istream_oo.hxx"
#include "istream_pointer.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <assert.h>

struct TeeIstream {
    struct Output {
        struct istream istream;

        /**
         * A weak output is one which is closed automatically when all
         * "strong" outputs have been closed - it will not keep up the
         * istream_tee object alone.
         */
        bool weak;

        bool enabled = true;

        explicit Output(bool _weak):weak(_weak) {}

        Output(const Output &) = delete;
        Output &operator=(const Output &) = delete;

        struct pool &GetPool() {
            return *istream.pool;
        }
    };

    struct FirstOutput : Output {
        explicit FirstOutput(bool _weak):Output(_weak) {}
    };

    struct SecondOutput : Output {
        explicit SecondOutput(bool _weak):Output(_weak) {}
    };

    FirstOutput first_output;
    SecondOutput second_output;

    IstreamPointer input;

    /**
     * These flags control whether istream_tee_close[12]() may restart
     * reading for the other output.
     */
    bool reading = false, in_data = false;

#ifndef NDEBUG
    bool closed_while_reading = false, closed_while_data = false;
#endif

    /**
     * The number of bytes to skip for output 0.  The first output has
     * already consumed this many bytes, but the second output
     * blocked.
     */
    size_t skip = 0;

    TeeIstream(struct istream &_input,
               bool first_weak, bool second_weak)
        :first_output(first_weak),
         second_output(second_weak),
         input(_input, MakeIstreamHandler<TeeIstream>::handler, this)
    {
    }

    struct pool &GetPool() {
        return first_output.GetPool();
    }

    size_t Feed0(const char *data, size_t length);
    size_t Feed1(const void *data, size_t length);
    size_t Feed(const void *data, size_t length);

    /* handler */

    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        // TODO: implement that using sys_tee()
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);
};

static GQuark
tee_quark(void)
{
    return g_quark_from_static_string("tee");
}

inline size_t
TeeIstream::Feed0(const char *data, size_t length)
{
    if (!first_output.enabled)
        return length;

    if (length <= skip)
        /* all of this has already been sent to the first input, but
           the second one didn't accept it yet */
        return length;

    /* skip the part which was already sent */
    data += skip;
    length -= skip;

    size_t nbytes = istream_invoke_data(&first_output.istream,
                                        data, length);
    if (nbytes > 0) {
        skip += nbytes;
        return skip;
    }

    if (first_output.enabled || !second_output.enabled)
        /* first output is blocking, or both closed: give up */
        return 0;

    /* the first output has been closed inside the data() callback,
       but the second is still alive: continue with the second
       output */
    return length;
}

inline size_t
TeeIstream::Feed1(const void *data, size_t length)
{
    if (!second_output.enabled)
        return length;

    size_t nbytes = istream_invoke_data(&second_output.istream, data, length);
    if (nbytes == 0 && !second_output.enabled &&
        first_output.enabled)
        /* during the data callback, second_output has been closed,
           but first_output continues; instead of returning 0 here,
           use first_output's result */
        return length;

    return nbytes;
}

inline size_t
TeeIstream::Feed(const void *data, size_t length)
{
    size_t nbytes0 = Feed0((const char *)data, length);
    if (nbytes0 == 0)
        return 0;

    size_t nbytes1 = Feed1(data, nbytes0);
    if (nbytes1 > 0 && first_output.enabled) {
        assert(nbytes1 <= skip);
        skip -= nbytes1;
    }

    return nbytes1;
}

/*
 * istream handler
 *
 */

inline size_t
TeeIstream::OnData(const void *data, size_t length)
{
    assert(input.IsDefined());
    assert(!in_data);

    const ScopePoolRef ref(GetPool() TRACE_ARGS);
    in_data = true;
    size_t nbytes = Feed(data, length);
    in_data = false;
    return nbytes;
}

inline void
TeeIstream::OnEof()
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    /* clean up in reverse order */

    if (second_output.enabled) {
        second_output.enabled = false;
        istream_deinit_eof(&second_output.istream);
    }

    if (first_output.enabled) {
        first_output.enabled = false;
        istream_deinit_eof(&first_output.istream);
    }
}

inline void
TeeIstream::OnError(GError *error)
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    /* clean up in reverse order */

    if (second_output.enabled) {
        second_output.enabled = false;
        istream_deinit_abort(&second_output.istream, g_error_copy(error));
    }

    if (first_output.enabled) {
        first_output.enabled = false;
        istream_deinit_abort(&first_output.istream, g_error_copy(error));
    }

    g_error_free(error);
}

/*
 * istream implementation 0
 *
 */

#ifdef __clang__
#pragma GCC diagnostic ignored "-Wextended-offsetof"
#endif

static inline TeeIstream &
istream_to_tee0(struct istream *istream)
{
    return *ContainerCast(istream, TeeIstream, first_output.istream);
}

static off_t
istream_tee_available0(struct istream *istream, bool partial)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.first_output.enabled);

    return tee.input.GetAvailable(partial);
}

static void
istream_tee_read0(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.first_output.enabled);
    assert(!tee.reading);

    const ScopePoolRef ref(tee.GetPool() TRACE_ARGS);
    tee.reading = true;
    tee.input.Read();
    tee.reading = false;
}

static void
istream_tee_close0(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    assert(tee.first_output.enabled);

    tee.first_output.enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.second_output.enabled)
            tee.input.ClearAndClose();
        else if (tee.second_output.weak) {
            const ScopePoolRef ref(tee.GetPool() TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.second_output.enabled) {
                tee.second_output.enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak second output");
                istream_deinit_abort(&tee.second_output.istream, error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.second_output.enabled &&
        istream_has_handler(&tee.second_output.istream) &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    istream_deinit(&tee.first_output.istream);
}

static const struct istream_class istream_tee0 = {
    .available = istream_tee_available0,
    .read = istream_tee_read0,
    .close = istream_tee_close0,
};

/*
 * istream implementation 2
 *
 */

static inline TeeIstream &
istream_to_tee1(struct istream *istream)
{
    return *ContainerCast(istream, TeeIstream, second_output.istream);
}

static off_t
istream_tee_available1(struct istream *istream, bool partial)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(tee.second_output.enabled);

    return tee.input.GetAvailable(partial);
}

static void
istream_tee_read1(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(!tee.reading);

    const ScopePoolRef ref(tee.GetPool() TRACE_ARGS);
    tee.reading = true;
    tee.input.Read();
    tee.reading = false;
}

static void
istream_tee_close1(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee1(istream);

    assert(tee.second_output.enabled);

    tee.second_output.enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.first_output.enabled)
            tee.input.ClearAndClose();
        else if (tee.first_output.weak) {
            const ScopePoolRef ref(tee.GetPool() TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.first_output.enabled) {
                tee.first_output.enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak first output");
                istream_deinit_abort(&tee.first_output.istream, error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.first_output.enabled &&
        istream_has_handler(&tee.first_output.istream) &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    istream_deinit(&tee.second_output.istream);
}

static const struct istream_class istream_tee1 = {
    .available = istream_tee_available1,
    .read = istream_tee_read1,
    .close = istream_tee_close1,
};

/*
 * constructor
 *
 */

struct istream *
istream_tee_new(struct pool *pool, struct istream *input,
                bool first_weak, bool second_weak)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    auto tee = NewFromPool<TeeIstream>(*pool, *input,
                                       first_weak, second_weak);
    istream_init(&tee->first_output.istream, &istream_tee0, pool);
    istream_init(&tee->second_output.istream, &istream_tee1, pool);

    return &tee->first_output.istream;
}

struct istream *
istream_tee_second(struct istream *istream)
{
    TeeIstream &tee = istream_to_tee0(istream);

    return &tee.second_output.istream;
}

<commit_msg>istream_tee: use class Istream<commit_after>/*
 * An istream which duplicates data.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_tee.hxx"
#include "istream_oo.hxx"
#include "istream_pointer.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <assert.h>

struct TeeIstream {
    struct Output : Istream {
        /**
         * A weak output is one which is closed automatically when all
         * "strong" outputs have been closed - it will not keep up the
         * istream_tee object alone.
         */
        bool weak;

        bool enabled = true;

        Output(struct pool &p, bool _weak):Istream(p), weak(_weak) {}

        Output(const Output &) = delete;
        Output &operator=(const Output &) = delete;

        friend struct TeeIstream;
    };

    struct FirstOutput : Output {
        explicit FirstOutput(struct pool &p, bool _weak):Output(p, _weak) {}

        TeeIstream &GetParent() {
            return ContainerCast2(*this, &TeeIstream::first_output);
        }

        off_t GetAvailable(bool partial) override {
            assert(enabled);

            return GetParent().input.GetAvailable(partial);
        }

        //off_t Skip(off_t length) override;

        void Read() override {
            TeeIstream &tee = GetParent();

            assert(enabled);
            assert(!tee.reading);

            const ScopePoolRef ref(GetPool() TRACE_ARGS);
            tee.reading = true;
            tee.input.Read();
            tee.reading = false;
        }

        void Close() override;
    };

    struct SecondOutput : Output {
        explicit SecondOutput(struct pool &p, bool _weak):Output(p, _weak) {}

        TeeIstream &GetParent() {
            return ContainerCast2(*this, &TeeIstream::second_output);
        }

        off_t GetAvailable(bool partial) override {
            assert(enabled);

            return GetParent().input.GetAvailable(partial);
        }

        //off_t Skip(off_t length) override;

        void Read() override {
            TeeIstream &tee = GetParent();

            assert(enabled);
            assert(!tee.reading);

            const ScopePoolRef ref(GetPool() TRACE_ARGS);
            tee.reading = true;
            tee.input.Read();
            tee.reading = false;
        }

        void Close() override;
    };

    FirstOutput first_output;
    SecondOutput second_output;

    IstreamPointer input;

    /**
     * These flags control whether istream_tee_close[12]() may restart
     * reading for the other output.
     */
    bool reading = false, in_data = false;

#ifndef NDEBUG
    bool closed_while_reading = false, closed_while_data = false;
#endif

    /**
     * The number of bytes to skip for output 0.  The first output has
     * already consumed this many bytes, but the second output
     * blocked.
     */
    size_t skip = 0;

    TeeIstream(struct pool &p, struct istream &_input,
               bool first_weak, bool second_weak)
        :first_output(p, first_weak),
         second_output(p, second_weak),
         input(_input, MakeIstreamHandler<TeeIstream>::handler, this)
    {
    }

    static TeeIstream &Cast2(struct istream &first) {
        return ContainerCast2((FirstOutput &)FirstOutput::Cast(first),
                              &TeeIstream::first_output);
    }

    struct pool &GetPool() {
        return first_output.GetPool();
    }

    size_t Feed0(const char *data, size_t length);
    size_t Feed1(const void *data, size_t length);
    size_t Feed(const void *data, size_t length);

    /* handler */

    size_t OnData(const void *data, size_t length);

    ssize_t OnDirect(gcc_unused FdType type, gcc_unused int fd,
                     gcc_unused size_t max_length) {
        // TODO: implement that using sys_tee()
        gcc_unreachable();
    }

    void OnEof();
    void OnError(GError *error);
};

static GQuark
tee_quark(void)
{
    return g_quark_from_static_string("tee");
}

inline size_t
TeeIstream::Feed0(const char *data, size_t length)
{
    if (!first_output.enabled)
        return length;

    if (length <= skip)
        /* all of this has already been sent to the first input, but
           the second one didn't accept it yet */
        return length;

    /* skip the part which was already sent */
    data += skip;
    length -= skip;

    size_t nbytes = first_output.InvokeData(data, length);
    if (nbytes > 0) {
        skip += nbytes;
        return skip;
    }

    if (first_output.enabled || !second_output.enabled)
        /* first output is blocking, or both closed: give up */
        return 0;

    /* the first output has been closed inside the data() callback,
       but the second is still alive: continue with the second
       output */
    return length;
}

inline size_t
TeeIstream::Feed1(const void *data, size_t length)
{
    if (!second_output.enabled)
        return length;

    size_t nbytes = second_output.InvokeData(data, length);
    if (nbytes == 0 && !second_output.enabled &&
        first_output.enabled)
        /* during the data callback, second_output has been closed,
           but first_output continues; instead of returning 0 here,
           use first_output's result */
        return length;

    return nbytes;
}

inline size_t
TeeIstream::Feed(const void *data, size_t length)
{
    size_t nbytes0 = Feed0((const char *)data, length);
    if (nbytes0 == 0)
        return 0;

    size_t nbytes1 = Feed1(data, nbytes0);
    if (nbytes1 > 0 && first_output.enabled) {
        assert(nbytes1 <= skip);
        skip -= nbytes1;
    }

    return nbytes1;
}

/*
 * istream handler
 *
 */

inline size_t
TeeIstream::OnData(const void *data, size_t length)
{
    assert(input.IsDefined());
    assert(!in_data);

    const ScopePoolRef ref(GetPool() TRACE_ARGS);
    in_data = true;
    size_t nbytes = Feed(data, length);
    in_data = false;
    return nbytes;
}

inline void
TeeIstream::OnEof()
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    /* clean up in reverse order */

    if (second_output.enabled) {
        second_output.enabled = false;
        second_output.DestroyEof();
    }

    if (first_output.enabled) {
        first_output.enabled = false;
        first_output.DestroyEof();
    }
}

inline void
TeeIstream::OnError(GError *error)
{
    assert(input.IsDefined());
    input.Clear();

    const ScopePoolRef ref(GetPool() TRACE_ARGS);

    /* clean up in reverse order */

    if (second_output.enabled) {
        second_output.enabled = false;
        second_output.DestroyError(g_error_copy(error));
    }

    if (first_output.enabled) {
        first_output.enabled = false;
        first_output.DestroyError(g_error_copy(error));
    }

    g_error_free(error);
}

/*
 * istream implementation 0
 *
 */

void
TeeIstream::FirstOutput::Close()
{
    TeeIstream &tee = GetParent();

    assert(enabled);

    enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.second_output.enabled)
            tee.input.ClearAndClose();
        else if (tee.second_output.weak) {
            const ScopePoolRef ref(GetPool() TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.second_output.enabled) {
                tee.second_output.enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak second output");
                tee.second_output.DestroyError(error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.second_output.enabled &&
        tee.second_output.HasHandler() &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    Destroy();
}

/*
 * istream implementation 2
 *
 */

void
TeeIstream::SecondOutput::Close()
{
    TeeIstream &tee = GetParent();

    assert(enabled);

    enabled = false;

#ifndef NDEBUG
    if (tee.reading)
        tee.closed_while_reading = true;
    if (tee.in_data)
        tee.closed_while_data = true;
#endif

    if (tee.input.IsDefined()) {
        if (!tee.first_output.enabled)
            tee.input.ClearAndClose();
        else if (tee.first_output.weak) {
            const ScopePoolRef ref(tee.GetPool() TRACE_ARGS);

            tee.input.ClearAndClose();

            if (tee.first_output.enabled) {
                tee.first_output.enabled = false;

                GError *error =
                    g_error_new_literal(tee_quark(), 0,
                                        "closing the weak first output");
                tee.first_output.DestroyError(error);
            }
        }
    }

    if (tee.input.IsDefined() && tee.first_output.enabled &&
        tee.first_output.HasHandler() &&
        !tee.in_data && !tee.reading)
        tee.input.Read();

    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_tee_new(struct pool *pool, struct istream *input,
                bool first_weak, bool second_weak)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    auto tee = NewFromPool<TeeIstream>(*pool, *pool, *input,
                                       first_weak, second_weak);
    return tee->first_output.Cast();
}

struct istream *
istream_tee_second(struct istream *istream)
{
    auto &tee = TeeIstream::Cast2(*istream);
    return tee.second_output.Cast();
}

<|endoftext|>