<commit_before>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "LookupContext.h"
#include "ResolveExpression.h"
#include "Overview.h"

#include <CoreTypes.h>
#include <Symbols.h>
#include <Literals.h>
#include <Names.h>
#include <Scope.h>
#include <Control.h>

#include <QtDebug>

using namespace CPlusPlus;

bool LookupContext::isNameCompatibleWithIdentifier(Name *name, Identifier *id)
{
    if (! name) {
        return false;
    } else if (NameId *nameId = name->asNameId()) {
        Identifier *identifier = nameId->identifier();
        return identifier->isEqualTo(id);
    } else if (DestructorNameId *nameId = name->asDestructorNameId()) {
        Identifier *identifier = nameId->identifier();
        return identifier->isEqualTo(id);
    } else if (TemplateNameId *templNameId = name->asTemplateNameId()) {
        Identifier *identifier = templNameId->identifier();
        return identifier->isEqualTo(id);
    }

    return false;
}

/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext(Control *control)
    : _control(control),
      _symbol(0)
{ }

LookupContext::LookupContext(Symbol *symbol,
                             Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
                             const Snapshot &documents)
    : _symbol(symbol),
      _expressionDocument(expressionDocument),
      _thisDocument(thisDocument),
      _documents(documents)
{
    _control = _expressionDocument->control();
    _visibleScopes = buildVisibleScopes();
}

LookupContext::LookupContext(Symbol *symbol,
                             const LookupContext &context)
    : _control(context._control),
      _symbol(symbol),
      _expressionDocument(context._expressionDocument),
      _documents(context._documents)
{
    const QString fn = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
    _thisDocument = _documents.value(fn);
    _visibleScopes = buildVisibleScopes();
}

LookupContext::LookupContext(Symbol *symbol,
              Document::Ptr thisDocument,
              const LookupContext &context)
    : _control(context._control),
      _symbol(symbol),
      _expressionDocument(context._expressionDocument),
      _thisDocument(thisDocument),
      _documents(context._documents)
{
    _visibleScopes = buildVisibleScopes();
}

bool LookupContext::isValid() const
{ return _control != 0; }

LookupContext::operator bool() const
{ return _control != 0; }

Control *LookupContext::control() const
{ return _control; }

Symbol *LookupContext::symbol() const
{ return _symbol; }

Document::Ptr LookupContext::expressionDocument() const
{ return _expressionDocument; }

Document::Ptr LookupContext::thisDocument() const
{ return _thisDocument; }

Document::Ptr LookupContext::document(const QString &fileName) const
{ return _documents.value(fileName); }

Identifier *LookupContext::identifier(Name *name) const
{
    if (NameId *nameId = name->asNameId())
        return nameId->identifier();
    else if (TemplateNameId *templId = name->asTemplateNameId())
        return templId->identifier();
    else if (DestructorNameId *dtorId = name->asDestructorNameId())
        return dtorId->identifier();
    else if (QualifiedNameId *q = name->asQualifiedNameId())
        return identifier(q->unqualifiedNameId());
    return 0;
}

bool LookupContext::maybeValidSymbol(Symbol *symbol,
                                     ResolveMode mode,
                                     const QList<Symbol *> &candidates)
{
    if (((mode & ResolveNamespace) && symbol->isNamespace()) ||
        ((mode & ResolveClass)     && symbol->isClass())     ||
         (mode & ResolveSymbol)) {
        return ! candidates.contains(symbol);
    }

    return false;
}

QList<Symbol *> LookupContext::resolve(Name *name, const QList<Scope *> &visibleScopes,
                                       ResolveMode mode) const
{
    if (QualifiedNameId *q = name->asQualifiedNameId()) {
        QList<Symbol *> candidates;
        QList<Scope *> scopes = visibleScopes;
        for (unsigned i = 0; i < q->nameCount(); ++i) {
            Name *name = q->nameAt(i);

            if (i + 1 == q->nameCount())
                candidates = resolve(name, scopes, mode);
            else
                candidates = resolveClassOrNamespace(name, scopes);

            if (candidates.isEmpty() || i + 1 == q->nameCount())
                break;

            scopes.clear();
            foreach (Symbol *candidate, candidates) {
                if (ScopedSymbol *scoped = candidate->asScopedSymbol()) {
                    expand(scoped->members(), visibleScopes, &scopes);
                }
            }
        }

        Identifier *id = identifier(name);
        foreach (Scope *scope, visibleScopes) {
            Symbol *symbol = scope->lookat(id);
            for (; symbol; symbol = symbol->next()) {
                if (! symbol->name())
                    continue;
                else if (! maybeValidSymbol(symbol, mode, candidates))
                    continue;
                QualifiedNameId *qq = symbol->name()->asQualifiedNameId();
                if (! qq)
                    continue;
                if (q->nameCount() > qq->nameCount())
                    continue;

                for (int i = q->nameCount() - 1; i != -1; --i) {
                    Name *a = q->nameAt(i);
                    Name *b = qq->nameAt(i);

                    if (! a->isEqualTo(b))
                        break;
                    else if (i == 0)
                        candidates.append(symbol);
                }
            }
        }

        return candidates;
    }

    QList<Symbol *> candidates;
    if (Identifier *id = identifier(name)) {
        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
            Scope *scope = visibleScopes.at(scopeIndex);
            for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
                if (! symbol->name()) {
                    continue;
                } else if (! maybeValidSymbol(symbol, mode, candidates)) {
                    continue;
                } else if (QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
                    if (! q->unqualifiedNameId()->isEqualTo(name))
                        continue;

                    if (q->nameCount() > 1) {
                        Name *classOrNamespaceName =
                                control()->qualifiedNameId(q->names(),
                                                           q->nameCount() - 1);

                        const QList<Symbol *> resolvedClassOrNamespace =
                                resolveClassOrNamespace(classOrNamespaceName, visibleScopes);

                        bool good = false;
                        foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) {
                            ScopedSymbol *scoped = classOrNamespace->asScopedSymbol();
                            if (visibleScopes.contains(scoped->members())) {
                                good = true;
                                break;
                            }
                        }

                        if (! good)
                            continue;
                    }
                } else if (! isNameCompatibleWithIdentifier(symbol->name(), id)) {
                    continue;
                } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) {
                    continue;
                }

                candidates.append(symbol);
            }
        }
    } else if (OperatorNameId *opId = name->asOperatorNameId()) {
        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
            Scope *scope = visibleScopes.at(scopeIndex);
            for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
                if (! opId->isEqualTo(symbol->name()))
                    continue;
                else if (! candidates.contains(symbol))
                    candidates.append(symbol);
            }
        }
    }

    return candidates;
}

QList<Scope *> LookupContext::buildVisibleScopes()
{
    QList<Scope *> scopes;

    if (_symbol) {
        for (Scope *scope = _symbol->scope(); scope; scope = scope->enclosingScope()) {
            scopes.append(scope);
        }
    }

    QSet<QString> processed;
    processed.insert(_thisDocument->fileName());

    QList<QString> todo = _thisDocument->includedFiles();
    while (! todo.isEmpty()) {
        QString fn = todo.last();
        todo.removeLast();

        if (processed.contains(fn))
            continue;

        processed.insert(fn);
        if (Document::Ptr doc = document(fn)) {
            scopes.append(doc->globalNamespace()->members());
            todo += doc->includedFiles();
        }
    }

    while (true) {
        QList<Scope *> expandedScopes;
        expand(scopes, &expandedScopes);

        if (expandedScopes.size() == scopes.size())
            return expandedScopes;

        scopes = expandedScopes;
    }

    return scopes;
}

QList<Scope *> LookupContext::visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const
{
    Symbol *symbol = result.second;
    QList<Scope *> scopes;
    for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
        scopes.append(scope);
    scopes += visibleScopes();
    scopes = expand(scopes);
    return scopes;
}

QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
{
    QList<Scope *> expanded;
    expand(scopes, &expanded);
    return expanded;
}

void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
{
    for (int i = 0; i < scopes.size(); ++i) {
        expand(scopes.at(i), scopes, expandedScopes);
    }
}

void LookupContext::expandNamespace(Scope *scope,
                                    const QList<Scope *> &visibleScopes,
                                    QList<Scope *> *expandedScopes) const
{
    Namespace *ns = scope->owner()->asNamespace();
    if (! ns)
        return;

    if (Name *nsName = ns->name()) {
        const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
        foreach (Symbol *otherNs, namespaceList) {
            if (otherNs == ns)
                continue;
            expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
        }
    }

    for (unsigned i = 0; i < scope->symbolCount(); ++i) { // ### make me fast
        Symbol *symbol = scope->symbolAt(i);
        if (Namespace *ns = symbol->asNamespace()) {
            if (! ns->name()) {
                expand(ns->members(), visibleScopes, expandedScopes);
            }
        } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
            const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
            for (int j = 0; j < candidates.size(); ++j) {
                expand(candidates.at(j)->asNamespace()->members(),
                       visibleScopes, expandedScopes);
            }
        } else if (Enum *e = symbol->asEnum()) {
            expand(e->members(), visibleScopes, expandedScopes);
        }
    }
}

void LookupContext::expandClass(Scope *scope,
                                const QList<Scope *> &visibleScopes,
                                QList<Scope *> *expandedScopes) const
{
    Class *klass = scope->owner()->asClass();
    if (! klass)
        return;

    for (unsigned i = 0; i < scope->symbolCount(); ++i) {
        Symbol *symbol = scope->symbolAt(i);
        if (Class *nestedClass = symbol->asClass()) {
            if (! nestedClass->name()) {
                expand(nestedClass->members(), visibleScopes, expandedScopes);
            }
        } else if (Enum *e = symbol->asEnum()) {
            expand(e->members(), visibleScopes, expandedScopes);
        }
    }

    if (klass->baseClassCount()) {
        QList<Scope *> classVisibleScopes = visibleScopes;
        for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
            if (scope->isNamespaceScope()) {
                Namespace *enclosingNamespace = scope->owner()->asNamespace();
                if (enclosingNamespace->name()) {
                    const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
                                                                    visibleScopes);
                    foreach (Symbol *ns, nsList) {
                        expand(ns->asNamespace()->members(), classVisibleScopes,
                               &classVisibleScopes);
                    }
                }
            }
        }

        for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
            BaseClass *baseClass = klass->baseClassAt(i);
            Name *baseClassName = baseClass->name();
            const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName,
                                                                     classVisibleScopes);
            if (baseClassCandidates.isEmpty()) {
                Overview overview;
                qDebug() << "unresolved base class:" << overview.prettyName(baseClassName);
            }

            for (int j = 0; j < baseClassCandidates.size(); ++j) {
                if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass())
                    expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
            }
        }
    }
}

void LookupContext::expandBlock(Scope *scope,
                                const QList<Scope *> &visibleScopes,
                                QList<Scope *> *expandedScopes) const
{
    for (unsigned i = 0; i < scope->symbolCount(); ++i) {
        Symbol *symbol = scope->symbolAt(i);
        if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
            const QList<Symbol *> candidates = resolveNamespace(u->name(),
                                                                visibleScopes);
            for (int j = 0; j < candidates.size(); ++j) {
                expand(candidates.at(j)->asNamespace()->members(),
                       visibleScopes, expandedScopes);
            }
        }

    }
}

void LookupContext::expandFunction(Scope *scope,
                                   const QList<Scope *> &visibleScopes,
                                   QList<Scope *> *expandedScopes) const
{
    Function *function = scope->owner()->asFunction();
    if (! expandedScopes->contains(function->arguments()))
        expandedScopes->append(function->arguments());
    if (QualifiedNameId *q = function->name()->asQualifiedNameId()) {
        Name *nestedNameSpec = 0;
        if (q->nameCount() == 1 && q->isGlobal())
            nestedNameSpec = q->nameAt(0);
        else
            nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
                                                        q->isGlobal());
        const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
        for (int j = 0; j < candidates.size(); ++j) {
            expand(candidates.at(j)->asScopedSymbol()->members(),
                   visibleScopes, expandedScopes);
        }
    }
}

void LookupContext::expand(Scope *scope,
                           const QList<Scope *> &visibleScopes,
                           QList<Scope *> *expandedScopes) const
{
    if (expandedScopes->contains(scope))
        return;

    expandedScopes->append(scope);

    if (scope->isNamespaceScope()) {
        expandNamespace(scope, visibleScopes, expandedScopes);
    } else if (scope->isClassScope()) {
        expandClass(scope, visibleScopes, expandedScopes);
    } else if (scope->isBlockScope()) {
        expandBlock(scope, visibleScopes, expandedScopes);
    } else if (scope->isFunctionScope()) {
        expandFunction(scope, visibleScopes, expandedScopes);
    } else if (scope->isPrototypeScope()) {
        //qDebug() << "prototype scope" << overview.prettyName(scope->owner()->name());
    }
}
<commit_msg>Fixes: Possible crash while resolving qualified name ids.<commit_after>/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/

#include "LookupContext.h"
#include "ResolveExpression.h"
#include "Overview.h"

#include <CoreTypes.h>
#include <Symbols.h>
#include <Literals.h>
#include <Names.h>
#include <Scope.h>
#include <Control.h>

#include <QtDebug>

using namespace CPlusPlus;

bool LookupContext::isNameCompatibleWithIdentifier(Name *name, Identifier *id)
{
    if (! name) {
        return false;
    } else if (NameId *nameId = name->asNameId()) {
        Identifier *identifier = nameId->identifier();
        return identifier->isEqualTo(id);
    } else if (DestructorNameId *nameId = name->asDestructorNameId()) {
        Identifier *identifier = nameId->identifier();
        return identifier->isEqualTo(id);
    } else if (TemplateNameId *templNameId = name->asTemplateNameId()) {
        Identifier *identifier = templNameId->identifier();
        return identifier->isEqualTo(id);
    }

    return false;
}

/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext(Control *control)
    : _control(control),
      _symbol(0)
{ }

LookupContext::LookupContext(Symbol *symbol,
                             Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
                             const Snapshot &documents)
    : _symbol(symbol),
      _expressionDocument(expressionDocument),
      _thisDocument(thisDocument),
      _documents(documents)
{
    _control = _expressionDocument->control();
    _visibleScopes = buildVisibleScopes();
}

LookupContext::LookupContext(Symbol *symbol,
                             const LookupContext &context)
    : _control(context._control),
      _symbol(symbol),
      _expressionDocument(context._expressionDocument),
      _documents(context._documents)
{
    const QString fn = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
    _thisDocument = _documents.value(fn);
    _visibleScopes = buildVisibleScopes();
}

LookupContext::LookupContext(Symbol *symbol,
              Document::Ptr thisDocument,
              const LookupContext &context)
    : _control(context._control),
      _symbol(symbol),
      _expressionDocument(context._expressionDocument),
      _thisDocument(thisDocument),
      _documents(context._documents)
{
    _visibleScopes = buildVisibleScopes();
}

bool LookupContext::isValid() const
{ return _control != 0; }

LookupContext::operator bool() const
{ return _control != 0; }

Control *LookupContext::control() const
{ return _control; }

Symbol *LookupContext::symbol() const
{ return _symbol; }

Document::Ptr LookupContext::expressionDocument() const
{ return _expressionDocument; }

Document::Ptr LookupContext::thisDocument() const
{ return _thisDocument; }

Document::Ptr LookupContext::document(const QString &fileName) const
{ return _documents.value(fileName); }

Identifier *LookupContext::identifier(Name *name) const
{
    if (NameId *nameId = name->asNameId())
        return nameId->identifier();
    else if (TemplateNameId *templId = name->asTemplateNameId())
        return templId->identifier();
    else if (DestructorNameId *dtorId = name->asDestructorNameId())
        return dtorId->identifier();
    else if (QualifiedNameId *q = name->asQualifiedNameId())
        return identifier(q->unqualifiedNameId());
    return 0;
}

bool LookupContext::maybeValidSymbol(Symbol *symbol,
                                     ResolveMode mode,
                                     const QList<Symbol *> &candidates)
{
    if (((mode & ResolveNamespace) && symbol->isNamespace()) ||
        ((mode & ResolveClass)     && symbol->isClass())     ||
         (mode & ResolveSymbol)) {
        return ! candidates.contains(symbol);
    }

    return false;
}

QList<Symbol *> LookupContext::resolve(Name *name, const QList<Scope *> &visibleScopes,
                                       ResolveMode mode) const
{
    if (QualifiedNameId *q = name->asQualifiedNameId()) {
        QList<Symbol *> candidates;
        QList<Scope *> scopes = visibleScopes;
        for (unsigned i = 0; i < q->nameCount(); ++i) {
            Name *name = q->nameAt(i);

            if (i + 1 == q->nameCount())
                candidates = resolve(name, scopes, mode);
            else
                candidates = resolveClassOrNamespace(name, scopes);

            if (candidates.isEmpty() || i + 1 == q->nameCount())
                break;

            scopes.clear();
            foreach (Symbol *candidate, candidates) {
                if (ScopedSymbol *scoped = candidate->asScopedSymbol()) {
                    scopes.append(scoped->members());
                }
            }
        }

        Identifier *id = identifier(name);
        foreach (Scope *scope, visibleScopes) {
            Symbol *symbol = scope->lookat(id);
            for (; symbol; symbol = symbol->next()) {
                if (! symbol->name())
                    continue;
                else if (! maybeValidSymbol(symbol, mode, candidates))
                    continue;
                QualifiedNameId *qq = symbol->name()->asQualifiedNameId();
                if (! qq)
                    continue;
                if (q->nameCount() > qq->nameCount())
                    continue;

                for (int i = q->nameCount() - 1; i != -1; --i) {
                    Name *a = q->nameAt(i);
                    Name *b = qq->nameAt(i);

                    if (! a->isEqualTo(b))
                        break;
                    else if (i == 0)
                        candidates.append(symbol);
                }
            }
        }

        return candidates;
    }

    QList<Symbol *> candidates;
    if (Identifier *id = identifier(name)) {
        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
            Scope *scope = visibleScopes.at(scopeIndex);
            for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
                if (! symbol->name()) {
                    continue;
                } else if (! maybeValidSymbol(symbol, mode, candidates)) {
                    continue;
                } else if (QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
                    if (! q->unqualifiedNameId()->isEqualTo(name))
                        continue;

                    if (q->nameCount() > 1) {
                        Name *classOrNamespaceName =
                                control()->qualifiedNameId(q->names(),
                                                           q->nameCount() - 1);

                        const QList<Symbol *> resolvedClassOrNamespace =
                                resolveClassOrNamespace(classOrNamespaceName, visibleScopes);

                        bool good = false;
                        foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) {
                            ScopedSymbol *scoped = classOrNamespace->asScopedSymbol();
                            if (visibleScopes.contains(scoped->members())) {
                                good = true;
                                break;
                            }
                        }

                        if (! good)
                            continue;
                    }
                } else if (! isNameCompatibleWithIdentifier(symbol->name(), id)) {
                    continue;
                } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) {
                    continue;
                }

                candidates.append(symbol);
            }
        }
    } else if (OperatorNameId *opId = name->asOperatorNameId()) {
        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
            Scope *scope = visibleScopes.at(scopeIndex);
            for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
                if (! opId->isEqualTo(symbol->name()))
                    continue;
                else if (! candidates.contains(symbol))
                    candidates.append(symbol);
            }
        }
    }

    return candidates;
}

QList<Scope *> LookupContext::buildVisibleScopes()
{
    QList<Scope *> scopes;

    if (_symbol) {
        for (Scope *scope = _symbol->scope(); scope; scope = scope->enclosingScope()) {
            scopes.append(scope);
        }
    }

    QSet<QString> processed;
    processed.insert(_thisDocument->fileName());

    QList<QString> todo = _thisDocument->includedFiles();
    while (! todo.isEmpty()) {
        QString fn = todo.last();
        todo.removeLast();

        if (processed.contains(fn))
            continue;

        processed.insert(fn);
        if (Document::Ptr doc = document(fn)) {
            scopes.append(doc->globalNamespace()->members());
            todo += doc->includedFiles();
        }
    }

    while (true) {
        QList<Scope *> expandedScopes;
        expand(scopes, &expandedScopes);

        if (expandedScopes.size() == scopes.size())
            return expandedScopes;

        scopes = expandedScopes;
    }

    return scopes;
}

QList<Scope *> LookupContext::visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const
{
    Symbol *symbol = result.second;
    QList<Scope *> scopes;
    for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
        scopes.append(scope);
    scopes += visibleScopes();
    scopes = expand(scopes);
    return scopes;
}

QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
{
    QList<Scope *> expanded;
    expand(scopes, &expanded);
    return expanded;
}

void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
{
    for (int i = 0; i < scopes.size(); ++i) {
        expand(scopes.at(i), scopes, expandedScopes);
    }
}

void LookupContext::expandNamespace(Scope *scope,
                                    const QList<Scope *> &visibleScopes,
                                    QList<Scope *> *expandedScopes) const
{
    Namespace *ns = scope->owner()->asNamespace();
    if (! ns)
        return;

    if (Name *nsName = ns->name()) {
        const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
        foreach (Symbol *otherNs, namespaceList) {
            if (otherNs == ns)
                continue;
            expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
        }
    }

    for (unsigned i = 0; i < scope->symbolCount(); ++i) { // ### make me fast
        Symbol *symbol = scope->symbolAt(i);
        if (Namespace *ns = symbol->asNamespace()) {
            if (! ns->name()) {
                expand(ns->members(), visibleScopes, expandedScopes);
            }
        } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
            const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
            for (int j = 0; j < candidates.size(); ++j) {
                expand(candidates.at(j)->asNamespace()->members(),
                       visibleScopes, expandedScopes);
            }
        } else if (Enum *e = symbol->asEnum()) {
            expand(e->members(), visibleScopes, expandedScopes);
        }
    }
}

void LookupContext::expandClass(Scope *scope,
                                const QList<Scope *> &visibleScopes,
                                QList<Scope *> *expandedScopes) const
{
    Class *klass = scope->owner()->asClass();
    if (! klass)
        return;

    for (unsigned i = 0; i < scope->symbolCount(); ++i) {
        Symbol *symbol = scope->symbolAt(i);
        if (Class *nestedClass = symbol->asClass()) {
            if (! nestedClass->name()) {
                expand(nestedClass->members(), visibleScopes, expandedScopes);
            }
        } else if (Enum *e = symbol->asEnum()) {
            expand(e->members(), visibleScopes, expandedScopes);
        }
    }

    if (klass->baseClassCount()) {
        QList<Scope *> classVisibleScopes = visibleScopes;
        for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
            if (scope->isNamespaceScope()) {
                Namespace *enclosingNamespace = scope->owner()->asNamespace();
                if (enclosingNamespace->name()) {
                    const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
                                                                    visibleScopes);
                    foreach (Symbol *ns, nsList) {
                        expand(ns->asNamespace()->members(), classVisibleScopes,
                               &classVisibleScopes);
                    }
                }
            }
        }

        for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
            BaseClass *baseClass = klass->baseClassAt(i);
            Name *baseClassName = baseClass->name();
            const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName,
                                                                     classVisibleScopes);
            if (baseClassCandidates.isEmpty()) {
                Overview overview;
                qDebug() << "unresolved base class:" << overview.prettyName(baseClassName);
            }

            for (int j = 0; j < baseClassCandidates.size(); ++j) {
                if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass())
                    expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
            }
        }
    }
}

void LookupContext::expandBlock(Scope *scope,
                                const QList<Scope *> &visibleScopes,
                                QList<Scope *> *expandedScopes) const
{
    for (unsigned i = 0; i < scope->symbolCount(); ++i) {
        Symbol *symbol = scope->symbolAt(i);
        if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
            const QList<Symbol *> candidates = resolveNamespace(u->name(),
                                                                visibleScopes);
            for (int j = 0; j < candidates.size(); ++j) {
                expand(candidates.at(j)->asNamespace()->members(),
                       visibleScopes, expandedScopes);
            }
        }

    }
}

void LookupContext::expandFunction(Scope *scope,
                                   const QList<Scope *> &visibleScopes,
                                   QList<Scope *> *expandedScopes) const
{
    Function *function = scope->owner()->asFunction();
    if (! expandedScopes->contains(function->arguments()))
        expandedScopes->append(function->arguments());
    if (QualifiedNameId *q = function->name()->asQualifiedNameId()) {
        Name *nestedNameSpec = 0;
        if (q->nameCount() == 1 && q->isGlobal())
            nestedNameSpec = q->nameAt(0);
        else
            nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
                                                        q->isGlobal());
        const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
        for (int j = 0; j < candidates.size(); ++j) {
            expand(candidates.at(j)->asScopedSymbol()->members(),
                   visibleScopes, expandedScopes);
        }
    }
}

void LookupContext::expand(Scope *scope,
                           const QList<Scope *> &visibleScopes,
                           QList<Scope *> *expandedScopes) const
{
    if (expandedScopes->contains(scope))
        return;

    expandedScopes->append(scope);

    if (scope->isNamespaceScope()) {
        expandNamespace(scope, visibleScopes, expandedScopes);
    } else if (scope->isClassScope()) {
        expandClass(scope, visibleScopes, expandedScopes);
    } else if (scope->isBlockScope()) {
        expandBlock(scope, visibleScopes, expandedScopes);
    } else if (scope->isFunctionScope()) {
        expandFunction(scope, visibleScopes, expandedScopes);
    } else if (scope->isPrototypeScope()) {
        //qDebug() << "prototype scope" << overview.prettyName(scope->owner()->name());
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2011, Willow Garage, 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 Willow Garage, Inc. 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.
//
// #define ECTO_TRACE_EXCEPTIONS
#define DISABLE_SHOW
#include <ecto/util.hpp>
#include <ecto/plasm.hpp>
#include <ecto/tendril.hpp>
#include <ecto/cell.hpp>

#include <string>
#include <map>
#include <set>
#include <utility>
#include <deque>

#include <ecto/impl/graph_types.hpp>
#include <ecto/plasm.hpp>
#include <ecto/impl/invoke.hpp>
#include <ecto/impl/schedulers/access.hpp>
#include <ecto/schedulers/multithreaded.hpp>

#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/asio.hpp>

#include <ecto/plasm.hpp>
#include <ecto/scheduler.hpp>
#include <ecto/tendril.hpp>
#include <ecto/cell.hpp>

#include <string>
#include <map>
#include <set>
#include <utility>
#include <deque>

namespace ecto {

  namespace schedulers {

    struct ECTO_EXPORT multithreaded::impl : scheduler<multithreaded::impl>
    {
      explicit impl(plasm_ptr);
      ~impl();

      int execute(unsigned niter, unsigned nthread);
      void execute_async(unsigned niter, unsigned nthread);

      void stop();
      void interrupt();
      bool running() const;
      void wait();

    private:

      int run_graph();
      int execute_impl(unsigned niter, unsigned nthread);

      int invoke_process(ecto::graph::graph_t::vertex_descriptor vd);
      void compute_stack();

      boost::thread runthread;

      bool stop_running;
      std::vector<ecto::graph::graph_t::vertex_descriptor> stack;
      mutable boost::mutex iface_mtx;
      mutable boost::mutex running_mtx;

      boost::asio::io_service io;
    };
  }

  using namespace ecto::graph;
  using boost::scoped_ptr;
  using boost::thread;
  using boost::bind;

  namespace pt = boost::posix_time;

  namespace schedulers {

    //
    // forwarding interface
    //

    multithreaded::multithreaded(plasm_ptr p)
      : impl_(new impl(p))
    { }

    multithreaded::~multithreaded() { }

    int multithreaded::execute(unsigned niter, unsigned nthread)
    {
      return impl_->execute(niter, nthread);
    }

    void multithreaded::execute_async(unsigned niter, unsigned nthread)
    {
      impl_->execute_async(niter, nthread);
    }

    void multithreaded::stop() {
      impl_->stop();
    }

    bool multithreaded::running() const {
      return impl_->running();
    }

    void multithreaded::wait() {
      impl_->wait();
    }

    void multithreaded::interrupt() {
      impl_->interrupt();
    }

    std::string multithreaded::stats() {
      return impl_->stats();
    }

    //
    //  impl
    //

    multithreaded::impl::impl(plasm_ptr p)
      : scheduler<multithreaded::impl>(p), stop_running(false)
    { }

    multithreaded::impl::~impl()
    {
      interrupt();
      wait();
    }

    int
    multithreaded::impl::invoke_process(graph_t::vertex_descriptor vd)
    {
      int rv;
      try {
        rv = ecto::schedulers::invoke_process(graph, vd);
      } catch (const boost::thread_interrupted& e) {
        std::cout << "Interrupted\n";
        return ecto::QUIT;
      }
      return rv;
    }

    void multithreaded::impl::compute_stack()
    {
      if (!stack.empty()) //will be empty if this needs to be computed.
        return;
      //check this plasm for correctness.
      plasm_->check();
      plasm_->configure_all();
      boost::topological_sort(graph, std::back_inserter(stack));
      std::reverse(stack.begin(), stack.end());
    }

    namespace
    {
      boost::signals2::signal<void(void)> SINGLE_THREADED_SIGINT_SIGNAL;
      void
      sigint_static_thunk(int)
      {
        std::cerr << "*** SIGINT received, stopping graph execution.\n"
                  << "*** If you are stuck here, you may need to hit ^C again\n"
                  << "*** when back in the interpreter thread.\n" << "*** or Ctrl-\\ (backslash) for a hard stop.\n"
                  << std::endl;
        SINGLE_THREADED_SIGINT_SIGNAL();
        PyErr_SetInterrupt();
      }
    }

    void multithreaded::impl::execute_async(unsigned niter, unsigned nthread)
    {
      PyEval_InitThreads();
      assert(PyEval_ThreadsInitialized());

      boost::mutex::scoped_lock l(iface_mtx);
      // compute_stack(); //FIXME hack for python based tendrils.
      scoped_ptr<thread> tmp(new thread(bind(&multithreaded::impl::execute_impl,
                                             this, niter, nthread)));
      tmp->swap(runthread);
      while(!running())
        boost::this_thread::sleep(boost::posix_time::microseconds(5)); //TODO FIXME condition variable?
    }

    int multithreaded::impl::execute(unsigned niter, unsigned nthread)
    {
      int j;
      j = execute_impl(niter, nthread);
      return j;
    }

    int multithreaded::impl::run_graph()
    {
      for (size_t k = 0; k < stack.size() && !stop_running; ++k)
        {
          //need to check the return val of a process here, non zero means exit...
          size_t retval = invoke_process(stack[k]);
          if (retval)
            return retval;
        }
      return 0;
    }

    int multithreaded::impl::execute_impl(unsigned niter, unsigned nthread)
    {
      plasm_->reset_ticks();
      compute_stack();
      boost::mutex::scoped_lock yes_running(running_mtx);
      stop_running = false;

      boost::signals2::scoped_connection
        interupt_connection(SINGLE_THREADED_SIGINT_SIGNAL.connect(boost::bind(&multithreaded::impl::interrupt, this)));

#if !defined(_WIN32)
      signal(SIGINT, &sigint_static_thunk);
#endif

      profile::graphstats_collector gs(graphstats);

      unsigned cur_iter = 0;
      while((niter == 0 || cur_iter < niter) && !stop_running)
        {
          size_t rv = run_graph();
          if (rv)
            return rv;
          ++cur_iter;
        }
      return stop_running;
    }

    void multithreaded::impl::interrupt() {
      boost::mutex::scoped_lock l(iface_mtx);
      SHOW();
      stop_running = true;
      runthread.interrupt();
      runthread.join();
    }

    void multithreaded::impl::stop() {
      boost::mutex::scoped_lock l(iface_mtx);
      SHOW();
      stop_running = true;
      runthread.join();
    }

    bool multithreaded::impl::running() const {
      boost::mutex::scoped_lock l2(running_mtx, boost::defer_lock);
      if (l2.try_lock())
        return false;
      else
        return true;
    }

    void multithreaded::impl::wait() {
      SHOW();
      boost::mutex::scoped_lock l(iface_mtx);
      while(running())
        boost::this_thread::sleep(boost::posix_time::microseconds(10));
      runthread.join();
    }

  }
}

<commit_msg>multithreaded does some interesting stuff<commit_after>//
// Copyright (c) 2011, Willow Garage, 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 Willow Garage, Inc. 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.
//
// #define ECTO_TRACE_EXCEPTIONS
#define ECTO_LOG_ON
#define DISABLE_SHOW
#include <ecto/util.hpp>
#include <ecto/plasm.hpp>
#include <ecto/tendril.hpp>
#include <ecto/cell.hpp>

#include <string>
#include <map>
#include <set>
#include <utility>
#include <deque>

#include <ecto/impl/graph_types.hpp>
#include <ecto/plasm.hpp>
#include <ecto/impl/invoke.hpp>
#include <ecto/impl/schedulers/access.hpp>
#include <ecto/schedulers/multithreaded.hpp>

#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/asio.hpp>

#include <ecto/plasm.hpp>
#include <ecto/scheduler.hpp>
#include <ecto/tendril.hpp>
#include <ecto/cell.hpp>

#include <string>
#include <map>
#include <set>
#include <utility>
#include <deque>

namespace ecto {

  namespace schedulers {

    struct ECTO_EXPORT multithreaded::impl : scheduler<multithreaded::impl>
    {
      explicit impl(plasm_ptr);
      ~impl();

      int execute(unsigned niter, unsigned nthread);
      void execute_async(unsigned niter, unsigned nthread);

      void stop();
      void interrupt();
      bool running() const;
      void wait();

    private:

      int run_graph();
      int execute_impl(unsigned niter, unsigned nthread);

      int invoke_process(ecto::graph::graph_t::vertex_descriptor vd);
      void compute_stack();

      boost::thread runthread;

      bool stop_running;
      std::vector<ecto::graph::graph_t::vertex_descriptor> stack;
      mutable boost::mutex iface_mtx;
      mutable boost::mutex running_mtx;

      boost::asio::io_service serv;
      boost::mutex current_iter_mtx;
      unsigned current_iter;
    };
  }

  using namespace ecto::graph;
  using boost::scoped_ptr;
  using boost::thread;
  using boost::bind;

  namespace pt = boost::posix_time;

  namespace schedulers {

    //
    // forwarding interface
    //

    multithreaded::multithreaded(plasm_ptr p)
      : impl_(new impl(p))
    { }

    multithreaded::~multithreaded() { }

    int multithreaded::execute(unsigned niter, unsigned nthread)
    {
      return impl_->execute(niter, nthread);
    }

    void multithreaded::execute_async(unsigned niter, unsigned nthread)
    {
      impl_->execute_async(niter, nthread);
    }

    void multithreaded::stop() {
      impl_->stop();
    }

    bool multithreaded::running() const {
      return impl_->running();
    }

    void multithreaded::wait() {
      impl_->wait();
    }

    void multithreaded::interrupt() {
      impl_->interrupt();
    }

    std::string multithreaded::stats() {
      return impl_->stats();
    }

    //
    //  impl
    //

    multithreaded::impl::impl(plasm_ptr p)
      : scheduler<multithreaded::impl>(p), stop_running(false)
    { }

    multithreaded::impl::~impl()
    {
      interrupt();
      wait();
    }

    int
    multithreaded::impl::invoke_process(graph_t::vertex_descriptor vd)
    {
      int rv;
      try {
        rv = ecto::schedulers::invoke_process(graph, vd);
      } catch (const boost::thread_interrupted& e) {
        std::cout << "Interrupted\n";
        return ecto::QUIT;
      }
      return rv;
    }

    void multithreaded::impl::compute_stack()
    {
      if (!stack.empty()) //will be empty if this needs to be computed.
        return;
      //check this plasm for correctness.
      plasm_->check();
      plasm_->configure_all();
      boost::topological_sort(graph, std::back_inserter(stack));
      std::reverse(stack.begin(), stack.end());
    }

    namespace
    {
      boost::signals2::signal<void(void)> SINGLE_THREADED_SIGINT_SIGNAL;
      void
      sigint_static_thunk(int)
      {
        std::cerr << "*** SIGINT received, stopping graph execution.\n"
                  << "*** If you are stuck here, you may need to hit ^C again\n"
                  << "*** when back in the interpreter thread.\n" << "*** or Ctrl-\\ (backslash) for a hard stop.\n"
                  << std::endl;
        SINGLE_THREADED_SIGINT_SIGNAL();
        PyErr_SetInterrupt();
      }
    }

    void multithreaded::impl::execute_async(unsigned niter, unsigned nthread)
    {
      PyEval_InitThreads();
      assert(PyEval_ThreadsInitialized());

      boost::mutex::scoped_lock l(iface_mtx);
      // compute_stack(); //FIXME hack for python based tendrils.
      scoped_ptr<thread> tmp(new thread(bind(&multithreaded::impl::execute_impl,
                                             this, niter, nthread)));
      tmp->swap(runthread);
      while(!running())
        boost::this_thread::sleep(boost::posix_time::microseconds(5)); //TODO FIXME condition variable?
    }

    int multithreaded::impl::execute(unsigned niter, unsigned nthread)
    {
      int j;
      j = execute_impl(niter, nthread);
      return j;
    }

    struct stack_runner
    {
      graph::graph_t& graph;
      const std::vector<graph::graph_t::vertex_descriptor>& stack;
      boost::asio::io_service& serv;
      unsigned max_iter;
      unsigned& overall_current_iter;
      boost::mutex& overall_current_iter_mtx;

      stack_runner(graph::graph_t& graph_,
                   const std::vector<graph::graph_t::vertex_descriptor>& stack_,
                   boost::asio::io_service& serv_,
                   unsigned max_iter_,
                   unsigned& overall_current_iter_,
                   boost::mutex& overall_current_iter_mtx_)
        : graph(graph_),
          stack(stack_),
          serv(serv_),
          max_iter(max_iter_),
          overall_current_iter(overall_current_iter_),
          overall_current_iter_mtx(overall_current_iter_mtx_)
      {
        ECTO_LOG_DEBUG("Created stack_runner @ overall iteration %u", overall_current_iter);
      }

      typedef int result_type;

      result_type operator()(std::size_t index)
      {
        ECTO_LOG_DEBUG("Runner firing on index %u of %u", index % stack.size());
        size_t retval = invoke_process(graph, stack[index]);
        ++index;
        assert (index <= stack.size());
        if (index == stack.size()) {
          boost::mutex::scoped_lock lock(overall_current_iter_mtx);
          ECTO_LOG_DEBUG("Thread deciding whether to recycle @ index %u, overall iter=%u",
                         index % overall_current_iter);
          index = 0;
          if (overall_current_iter == max_iter)
            {
              ECTO_LOG_DEBUG("Thread exiting at %u iterations", max_iter);
              return 0;
            }
          else
            {
              ++overall_current_iter;
            }
        }
        ECTO_LOG_DEBUG("Posting next job index=%u", index);
        serv.post(boost::bind(stack_runner(graph, stack, serv,
                                           max_iter,
                                           overall_current_iter, overall_current_iter_mtx), index));
        return retval;
      }
    };

    int multithreaded::impl::run_graph()
    {
      return 0;
    }

    int multithreaded::impl::execute_impl(unsigned max_iter, unsigned nthread)
    {
      ECTO_LOG_DEBUG("execute_impl max_iter=%u nthread=%u",
                     max_iter % nthread);
      plasm_->reset_ticks();
      compute_stack();
      boost::mutex::scoped_lock yes_running(running_mtx);
      stop_running = false;

      boost::signals2::scoped_connection
        interupt_connection(SINGLE_THREADED_SIGINT_SIGNAL.connect(boost::bind(&multithreaded::impl::interrupt, this)));

#if !defined(_WIN32)
      signal(SIGINT, &sigint_static_thunk);
#endif

      profile::graphstats_collector gs(graphstats);

      if (max_iter < nthread) {
        nthread = max_iter;
        ECTO_LOG_DEBUG("Clamped threads to %u", nthread);
      }
      for (unsigned j=0; j<nthread; ++j)
        serv.post(boost::bind(stack_runner(graph, stack, serv,
                                           max_iter,
                                           current_iter,
                                           current_iter_mtx),
                              0));

      boost::thread_group threads;

      for (unsigned j=0; j<nthread; ++j)
        {
          ECTO_LOG_DEBUG("Running service in thread %u", j);
          threads.create_thread(boost::bind(&boost::asio::io_service::run, &serv));
          boost::mutex::scoped_lock lock(current_iter_mtx);
          ++current_iter;
        }
      threads.join_all();
      ECTO_LOG_DEBUG("JOINED, EXITING AFTER %u", current_iter);
      return stop_running;
    }

    void multithreaded::impl::interrupt() {
      boost::mutex::scoped_lock l(iface_mtx);
      SHOW();
      stop_running = true;
      runthread.interrupt();
      runthread.join();
    }

    void multithreaded::impl::stop() {
      boost::mutex::scoped_lock l(iface_mtx);
      SHOW();
      stop_running = true;
      runthread.join();
    }

    bool multithreaded::impl::running() const {
      boost::mutex::scoped_lock l2(running_mtx, boost::defer_lock);
      if (l2.try_lock())
        return false;
      else
        return true;
    }

    void multithreaded::impl::wait() {
      SHOW();
      boost::mutex::scoped_lock l(iface_mtx);
      while(running())
        boost::this_thread::sleep(boost::posix_time::microseconds(10));
      runthread.join();
    }

  }
}

<|endoftext|>


<commit_before>/*
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Gabriel Ebner
*/
#include "library/library_task_builder.h"
#include "library/message_builder.h"

namespace lean {

struct library_scopes_imp : public delegating_task_imp {
    io_state m_ios;
    log_tree::node m_lt;

    library_scopes_imp(std::unique_ptr<gtask_imp> && base, log_tree::node const & lt) :
        delegating_task_imp(std::forward<std::unique_ptr<gtask_imp>>(base)),
        m_ios(get_global_ios()), m_lt(lt) {}

    // TODO(gabriel): set logtree status to cancelled?

    void execute(void * result) override {
        scope_global_ios scope1(m_ios);
        scope_log_tree scope2(m_lt);
        if (m_lt) m_lt.set_state(log_tree::state::Running);
        try {
            delegating_task_imp::execute(result);
        } catch (interrupted) {
            if (m_lt) m_lt.set_state(log_tree::state::Cancelled);
        }
    }
};

std::unique_ptr<gtask_imp> library_scopes::operator()(std::unique_ptr<gtask_imp> && base) {
    return std::unique_ptr<gtask_imp>(new library_scopes_imp(
            std::forward<std::unique_ptr<gtask_imp>>(base), m_lt));
}

struct exception_reporter_imp : public delegating_task_imp {
    exception_reporter_imp(std::unique_ptr<gtask_imp> && base) :
        delegating_task_imp(std::forward<std::unique_ptr<gtask_imp>>(base)) {}

    void execute(void * result) override {
        try {
            delegating_task_imp::execute(result);
        } catch (std::exception & ex) {
            message_builder(environment(), get_global_ios(),
                            logtree().get_location().m_file_name,
                            logtree().get_location().m_range.m_begin,
                            ERROR)
                    .set_exception(ex)
                    .report();
            throw;
        }
    }
};

std::unique_ptr<gtask_imp> exception_reporter::operator()(std::unique_ptr<gtask_imp> && base) {
    return std::unique_ptr<gtask_imp>(new exception_reporter_imp(
            std::forward<std::unique_ptr<gtask_imp>>(base)));
}

}
<commit_msg>fix(library/library_task_builder): prevent uninitialized task results when cancelled<commit_after>/*
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Gabriel Ebner
*/
#include "library/library_task_builder.h"
#include "library/message_builder.h"

namespace lean {

struct library_scopes_imp : public delegating_task_imp {
    io_state m_ios;
    log_tree::node m_lt;

    library_scopes_imp(std::unique_ptr<gtask_imp> && base, log_tree::node const & lt) :
        delegating_task_imp(std::forward<std::unique_ptr<gtask_imp>>(base)),
        m_ios(get_global_ios()), m_lt(lt) {}

    // TODO(gabriel): set logtree status to cancelled?

    void execute(void * result) override {
        scope_global_ios scope1(m_ios);
        scope_log_tree scope2(m_lt);
        if (m_lt) m_lt.set_state(log_tree::state::Running);
        try {
            delegating_task_imp::execute(result);
        } catch (interrupted) {
            if (m_lt) m_lt.set_state(log_tree::state::Cancelled);
            throw;
        }
    }
};

std::unique_ptr<gtask_imp> library_scopes::operator()(std::unique_ptr<gtask_imp> && base) {
    return std::unique_ptr<gtask_imp>(new library_scopes_imp(
            std::forward<std::unique_ptr<gtask_imp>>(base), m_lt));
}

struct exception_reporter_imp : public delegating_task_imp {
    exception_reporter_imp(std::unique_ptr<gtask_imp> && base) :
        delegating_task_imp(std::forward<std::unique_ptr<gtask_imp>>(base)) {}

    void execute(void * result) override {
        try {
            delegating_task_imp::execute(result);
        } catch (std::exception & ex) {
            message_builder(environment(), get_global_ios(),
                            logtree().get_location().m_file_name,
                            logtree().get_location().m_range.m_begin,
                            ERROR)
                    .set_exception(ex)
                    .report();
            throw;
        }
    }
};

std::unique_ptr<gtask_imp> exception_reporter::operator()(std::unique_ptr<gtask_imp> && base) {
    return std::unique_ptr<gtask_imp>(new exception_reporter_imp(
            std::forward<std::unique_ptr<gtask_imp>>(base)));
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include <fs.h>
#include <test/setup_common.h>
#include <util/system.h>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
    fs::path tmpfolder = GetDataDir();
    // tmpfile1 should be the same as tmpfile2
    fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
    fs::path tmpfile2 = tmpfolder / L"fs_tests_₿_🏃";
    {
        fsbridge::ofstream file(tmpfile1);
        file << "syscoin";
    }
    {
        fsbridge::ifstream file(tmpfile2);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "syscoin");
    }
    {
        fsbridge::ifstream file(tmpfile1, std::ios_base::in | std::ios_base::ate);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "");
    }
    {
        fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::app);
        file << "tests";
    }
    {
        fsbridge::ifstream file(tmpfile1);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "syscointests");
    }
    {
        fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::trunc);
        file << "syscoin";
    }
    {
        fsbridge::ifstream file(tmpfile1);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "syscoin");
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>tests: Fix fs_tests for unknown locales<commit_after>// Copyright (c) 2011-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include <fs.h>
#include <test/setup_common.h>
#include <util/system.h>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
    fs::path tmpfolder = GetDataDir();
    // tmpfile1 should be the same as tmpfile2
    fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
    fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃";
    {
        fsbridge::ofstream file(tmpfile1);
        file << "syscoin";
    }
    {
        fsbridge::ifstream file(tmpfile2);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "syscoin");
    }
    {
        fsbridge::ifstream file(tmpfile1, std::ios_base::in | std::ios_base::ate);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "");
    }
    {
        fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::app);
        file << "tests";
    }
    {
        fsbridge::ifstream file(tmpfile1);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "syscointests");
    }
    {
        fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::trunc);
        file << "syscoin";
    }
    {
        fsbridge::ifstream file(tmpfile1);
        std::string input_buffer;
        file >> input_buffer;
        BOOST_CHECK_EQUAL(input_buffer, "syscoin");
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkfdk_ggo.h"
#include "rtkGgoFunctions.h"
#include "rtkConfiguration.h"

#include "rtkThreeDCircularProjectionGeometryXMLFile.h"
#include "rtkDisplacedDetectorForOffsetFieldOfViewImageFilter.h"
#include "rtkParkerShortScanImageFilter.h"
#include "rtkFDKConeBeamReconstructionFilter.h"
#ifdef RTK_USE_CUDA
#  include "rtkCudaDisplacedDetectorImageFilter.h"
//TODO #  include "rtkCudaDisplacedDetectorForOffsetFieldOfViewImageFilter.h"
#  include "rtkCudaParkerShortScanImageFilter.h"
#  include "rtkCudaFDKConeBeamReconstructionFilter.h"
#endif
#ifdef RTK_USE_OPENCL
#  include "rtkOpenCLFDKConeBeamReconstructionFilter.h"
#endif
#include "rtkFDKWarpBackProjectionImageFilter.h"
#include "rtkCyclicDeformationImageFilter.h"

#include <itkStreamingImageFilter.h>
#include <itkImageFileWriter.h>

int main(int argc, char * argv[])
{
  GGO(rtkfdk, args_info);

  typedef float OutputPixelType;
  const unsigned int Dimension = 3;

  typedef itk::Image< OutputPixelType, Dimension >     CPUOutputImageType;
#ifdef RTK_USE_CUDA
  typedef itk::CudaImage< OutputPixelType, Dimension > OutputImageType;
#else
  typedef CPUOutputImageType                           OutputImageType;
#endif

  // Projections reader
  typedef rtk::ProjectionsReader< OutputImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  rtk::SetProjectionsReaderFromGgo<ReaderType, args_info_rtkfdk>(reader, args_info);

  itk::TimeProbe readerProbe;
  if(!args_info.lowmem_flag)
    {
    if(args_info.verbose_flag)
      std::cout << "Reading... " << std::flush;
    readerProbe.Start();
    TRY_AND_EXIT_ON_ITK_EXCEPTION( reader->Update() )
    readerProbe.Stop();
    if(args_info.verbose_flag)
      std::cout << "It took " << readerProbe.GetMean() << ' ' << readerProbe.GetUnit() << std::endl;
    }

  // Geometry
  if(args_info.verbose_flag)
    std::cout << "Reading geometry information from "
              << args_info.geometry_arg
              << "..."
              << std::endl;
  rtk::ThreeDCircularProjectionGeometryXMLFileReader::Pointer geometryReader;
  geometryReader = rtk::ThreeDCircularProjectionGeometryXMLFileReader::New();
  geometryReader->SetFilename(args_info.geometry_arg);
  TRY_AND_EXIT_ON_ITK_EXCEPTION( geometryReader->GenerateOutputInformation() )

  // Check on hardware parameter
#ifndef RTK_USE_CUDA
  if(!strcmp(args_info.hardware_arg, "cuda") )
    {
    std::cerr << "The program has not been compiled with cuda option" << std::endl;
    return EXIT_FAILURE;
    }
#endif
#ifndef RTK_USE_OPENCL
   if(!strcmp(args_info.hardware_arg, "opencl") )
     {
     std::cerr << "The program has not been compiled with opencl option" << std::endl;
     return EXIT_FAILURE;
     }
#endif

  // Displaced detector weighting
  typedef rtk::DisplacedDetectorImageFilter< OutputImageType >                     DDFCPUType;
  typedef rtk::DisplacedDetectorForOffsetFieldOfViewImageFilter< OutputImageType > DDFOFFFOVType;
#ifdef RTK_USE_CUDA
  typedef rtk::CudaDisplacedDetectorImageFilter DDFType;
#else
  typedef rtk::DisplacedDetectorForOffsetFieldOfViewImageFilter< OutputImageType > DDFType;
#endif
  DDFCPUType::Pointer ddf;
  if(!strcmp(args_info.hardware_arg, "cuda") )
    ddf = DDFType::New();
  else
    ddf = DDFOFFFOVType::New();
  ddf->SetInput( reader->GetOutput() );
  ddf->SetGeometry( geometryReader->GetOutputObject() );

  // Short scan image filter
  typedef rtk::ParkerShortScanImageFilter< OutputImageType > PSSFCPUType;
#ifdef RTK_USE_CUDA
  typedef rtk::CudaParkerShortScanImageFilter PSSFType;
#else
  typedef rtk::ParkerShortScanImageFilter< OutputImageType > PSSFType;
#endif
  PSSFCPUType::Pointer pssf;
  if(!strcmp(args_info.hardware_arg, "cuda") )
    pssf = PSSFType::New();
  else
    pssf = PSSFCPUType::New();
  pssf->SetInput( ddf->GetOutput() );
  pssf->SetGeometry( geometryReader->GetOutputObject() );
  pssf->InPlaceOff();

  // Create reconstructed image
  typedef rtk::ConstantImageSource< OutputImageType > ConstantImageSourceType;
  ConstantImageSourceType::Pointer constantImageSource = ConstantImageSourceType::New();
  rtk::SetConstantImageSourceFromGgo<ConstantImageSourceType, args_info_rtkfdk>(constantImageSource, args_info);

  // Motion-compensated objects for the compensation of a cyclic deformation.
  // Although these will only be used if the command line options for motion
  // compensation are set, we still create the object before hand to avoid auto
  // destruction.
  typedef itk::Vector<float,3> DVFPixelType;
  typedef itk::Image< DVFPixelType, 3 > DVFImageType;
  typedef rtk::CyclicDeformationImageFilter< DVFImageType > DeformationType;
  typedef itk::ImageFileReader<DeformationType::InputImageType> DVFReaderType;
  DVFReaderType::Pointer dvfReader = DVFReaderType::New();
  DeformationType::Pointer def = DeformationType::New();
  def->SetInput(dvfReader->GetOutput());
  typedef rtk::FDKWarpBackProjectionImageFilter<OutputImageType, OutputImageType, DeformationType> WarpBPType;
  WarpBPType::Pointer bp = WarpBPType::New();
  bp->SetDeformation(def);
  bp->SetGeometry( geometryReader->GetOutputObject() );

  // This macro sets options for fdk filter which I can not see how to do better
  // because TFFTPrecision is not the same, e.g. for CPU and CUDA (SR)
#define SET_FELDKAMP_OPTIONS(f) \
    f->SetInput( 0, constantImageSource->GetOutput() ); \
    f->SetInput( 1, pssf->GetOutput() ); \
    f->SetGeometry( geometryReader->GetOutputObject() ); \
    f->GetRampFilter()->SetTruncationCorrection(args_info.pad_arg); \
    f->GetRampFilter()->SetHannCutFrequency(args_info.hann_arg); \
    f->GetRampFilter()->SetHannCutFrequencyY(args_info.hannY_arg); \
    f->SetProjectionSubsetSize(args_info.subsetsize_arg)

  // FDK reconstruction filtering
  typedef rtk::FDKConeBeamReconstructionFilter< OutputImageType > FDKCPUType;
  FDKCPUType::Pointer feldkamp;
#ifdef RTK_USE_OPENCL
  typedef rtk::OpenCLFDKConeBeamReconstructionFilter FDKOPENCLType;
  FDKOPENCLType::Pointer feldkampOCL;
#endif
#ifdef RTK_USE_CUDA
  typedef rtk::CudaFDKConeBeamReconstructionFilter FDKCUDAType;
  FDKCUDAType::Pointer feldkampCUDA;
#endif
  itk::Image< OutputPixelType, Dimension > *pfeldkamp = NULL;
  if(!strcmp(args_info.hardware_arg, "cpu") )
    {
    feldkamp = FDKCPUType::New();
    SET_FELDKAMP_OPTIONS( feldkamp );

    // Motion compensated CBCT settings
    if(args_info.signal_given && args_info.dvf_given)
      {
      dvfReader->SetFileName(args_info.dvf_arg);
      def->SetSignalFilename(args_info.signal_arg);
      feldkamp->SetBackProjectionFilter( bp.GetPointer() );
      }
    pfeldkamp = feldkamp->GetOutput();
    }
#ifdef RTK_USE_CUDA
  else if(!strcmp(args_info.hardware_arg, "cuda") )
    {
    // Motion compensation not supported in cuda
    if(args_info.signal_given && args_info.dvf_given)
      {
      std::cerr << "Motion compensation is not supported in CUDA. Aborting" << std::endl;
      return EXIT_FAILURE;
      }

    feldkampCUDA = FDKCUDAType::New();
    SET_FELDKAMP_OPTIONS( feldkampCUDA );
    pfeldkamp = feldkampCUDA->GetOutput();
    }
#endif
#ifdef RTK_USE_OPENCL
  else if(!strcmp(args_info.hardware_arg, "opencl") )
    {
    feldkampOCL = FDKOPENCLType::New();
    SET_FELDKAMP_OPTIONS( feldkampOCL );
    pfeldkamp = feldkampOCL->GetOutput();
    }
#endif

  // Streaming depending on streaming capability of writer
  typedef itk::StreamingImageFilter<CPUOutputImageType, CPUOutputImageType> StreamerType;
  StreamerType::Pointer streamerBP = StreamerType::New();
  streamerBP->SetInput( pfeldkamp );
  streamerBP->SetNumberOfStreamDivisions( args_info.divisions_arg );

  // Write
  typedef itk::ImageFileWriter<CPUOutputImageType> WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName( args_info.output_arg );
  writer->SetInput( streamerBP->GetOutput() );

  if(args_info.verbose_flag)
    std::cout << "Reconstructing and writing... " << std::flush;
  itk::TimeProbe writerProbe;

  writerProbe.Start();
  TRY_AND_EXIT_ON_ITK_EXCEPTION( writer->Update() );
  writerProbe.Stop();

  if(args_info.verbose_flag)
    {
    std::cout << "It took " << writerProbe.GetMean() << ' ' << readerProbe.GetUnit() << std::endl;
    if(!strcmp(args_info.hardware_arg, "cpu") )
      feldkamp->PrintTiming(std::cout);
#ifdef RTK_USE_CUDA
    else if(!strcmp(args_info.hardware_arg, "cuda") )
      feldkampCUDA->PrintTiming(std::cout);
#endif
#ifdef RTK_USE_OPENCL
    else if(!strcmp(args_info.hardware_arg, "opencl") )
      feldkampOCL->PrintTiming(std::cout);
#endif
    std::cout << std::endl;
    }

  return EXIT_SUCCESS;
}
<commit_msg>Motion in compensation is not supported with OpenCL<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkfdk_ggo.h"
#include "rtkGgoFunctions.h"
#include "rtkConfiguration.h"

#include "rtkThreeDCircularProjectionGeometryXMLFile.h"
#include "rtkDisplacedDetectorForOffsetFieldOfViewImageFilter.h"
#include "rtkParkerShortScanImageFilter.h"
#include "rtkFDKConeBeamReconstructionFilter.h"
#ifdef RTK_USE_CUDA
#  include "rtkCudaDisplacedDetectorImageFilter.h"
//TODO #  include "rtkCudaDisplacedDetectorForOffsetFieldOfViewImageFilter.h"
#  include "rtkCudaParkerShortScanImageFilter.h"
#  include "rtkCudaFDKConeBeamReconstructionFilter.h"
#endif
#ifdef RTK_USE_OPENCL
#  include "rtkOpenCLFDKConeBeamReconstructionFilter.h"
#endif
#include "rtkFDKWarpBackProjectionImageFilter.h"
#include "rtkCyclicDeformationImageFilter.h"

#include <itkStreamingImageFilter.h>
#include <itkImageFileWriter.h>

int main(int argc, char * argv[])
{
  GGO(rtkfdk, args_info);

  typedef float OutputPixelType;
  const unsigned int Dimension = 3;

  typedef itk::Image< OutputPixelType, Dimension >     CPUOutputImageType;
#ifdef RTK_USE_CUDA
  typedef itk::CudaImage< OutputPixelType, Dimension > OutputImageType;
#else
  typedef CPUOutputImageType                           OutputImageType;
#endif

  // Projections reader
  typedef rtk::ProjectionsReader< OutputImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  rtk::SetProjectionsReaderFromGgo<ReaderType, args_info_rtkfdk>(reader, args_info);

  itk::TimeProbe readerProbe;
  if(!args_info.lowmem_flag)
    {
    if(args_info.verbose_flag)
      std::cout << "Reading... " << std::flush;
    readerProbe.Start();
    TRY_AND_EXIT_ON_ITK_EXCEPTION( reader->Update() )
    readerProbe.Stop();
    if(args_info.verbose_flag)
      std::cout << "It took " << readerProbe.GetMean() << ' ' << readerProbe.GetUnit() << std::endl;
    }

  // Geometry
  if(args_info.verbose_flag)
    std::cout << "Reading geometry information from "
              << args_info.geometry_arg
              << "..."
              << std::endl;
  rtk::ThreeDCircularProjectionGeometryXMLFileReader::Pointer geometryReader;
  geometryReader = rtk::ThreeDCircularProjectionGeometryXMLFileReader::New();
  geometryReader->SetFilename(args_info.geometry_arg);
  TRY_AND_EXIT_ON_ITK_EXCEPTION( geometryReader->GenerateOutputInformation() )

  // Check on hardware parameter
#ifndef RTK_USE_CUDA
  if(!strcmp(args_info.hardware_arg, "cuda") )
    {
    std::cerr << "The program has not been compiled with cuda option" << std::endl;
    return EXIT_FAILURE;
    }
#endif
#ifndef RTK_USE_OPENCL
   if(!strcmp(args_info.hardware_arg, "opencl") )
     {
     std::cerr << "The program has not been compiled with opencl option" << std::endl;
     return EXIT_FAILURE;
     }
#endif

  // Displaced detector weighting
  typedef rtk::DisplacedDetectorImageFilter< OutputImageType >                     DDFCPUType;
  typedef rtk::DisplacedDetectorForOffsetFieldOfViewImageFilter< OutputImageType > DDFOFFFOVType;
#ifdef RTK_USE_CUDA
  typedef rtk::CudaDisplacedDetectorImageFilter DDFType;
#else
  typedef rtk::DisplacedDetectorForOffsetFieldOfViewImageFilter< OutputImageType > DDFType;
#endif
  DDFCPUType::Pointer ddf;
  if(!strcmp(args_info.hardware_arg, "cuda") )
    ddf = DDFType::New();
  else
    ddf = DDFOFFFOVType::New();
  ddf->SetInput( reader->GetOutput() );
  ddf->SetGeometry( geometryReader->GetOutputObject() );

  // Short scan image filter
  typedef rtk::ParkerShortScanImageFilter< OutputImageType > PSSFCPUType;
#ifdef RTK_USE_CUDA
  typedef rtk::CudaParkerShortScanImageFilter PSSFType;
#else
  typedef rtk::ParkerShortScanImageFilter< OutputImageType > PSSFType;
#endif
  PSSFCPUType::Pointer pssf;
  if(!strcmp(args_info.hardware_arg, "cuda") )
    pssf = PSSFType::New();
  else
    pssf = PSSFCPUType::New();
  pssf->SetInput( ddf->GetOutput() );
  pssf->SetGeometry( geometryReader->GetOutputObject() );
  pssf->InPlaceOff();

  // Create reconstructed image
  typedef rtk::ConstantImageSource< OutputImageType > ConstantImageSourceType;
  ConstantImageSourceType::Pointer constantImageSource = ConstantImageSourceType::New();
  rtk::SetConstantImageSourceFromGgo<ConstantImageSourceType, args_info_rtkfdk>(constantImageSource, args_info);

  // Motion-compensated objects for the compensation of a cyclic deformation.
  // Although these will only be used if the command line options for motion
  // compensation are set, we still create the object before hand to avoid auto
  // destruction.
  typedef itk::Vector<float,3> DVFPixelType;
  typedef itk::Image< DVFPixelType, 3 > DVFImageType;
  typedef rtk::CyclicDeformationImageFilter< DVFImageType > DeformationType;
  typedef itk::ImageFileReader<DeformationType::InputImageType> DVFReaderType;
  DVFReaderType::Pointer dvfReader = DVFReaderType::New();
  DeformationType::Pointer def = DeformationType::New();
  def->SetInput(dvfReader->GetOutput());
  typedef rtk::FDKWarpBackProjectionImageFilter<OutputImageType, OutputImageType, DeformationType> WarpBPType;
  WarpBPType::Pointer bp = WarpBPType::New();
  bp->SetDeformation(def);
  bp->SetGeometry( geometryReader->GetOutputObject() );

  // This macro sets options for fdk filter which I can not see how to do better
  // because TFFTPrecision is not the same, e.g. for CPU and CUDA (SR)
#define SET_FELDKAMP_OPTIONS(f) \
    f->SetInput( 0, constantImageSource->GetOutput() ); \
    f->SetInput( 1, pssf->GetOutput() ); \
    f->SetGeometry( geometryReader->GetOutputObject() ); \
    f->GetRampFilter()->SetTruncationCorrection(args_info.pad_arg); \
    f->GetRampFilter()->SetHannCutFrequency(args_info.hann_arg); \
    f->GetRampFilter()->SetHannCutFrequencyY(args_info.hannY_arg); \
    f->SetProjectionSubsetSize(args_info.subsetsize_arg)

  // FDK reconstruction filtering
  typedef rtk::FDKConeBeamReconstructionFilter< OutputImageType > FDKCPUType;
  FDKCPUType::Pointer feldkamp;
#ifdef RTK_USE_OPENCL
  typedef rtk::OpenCLFDKConeBeamReconstructionFilter FDKOPENCLType;
  FDKOPENCLType::Pointer feldkampOCL;
#endif
#ifdef RTK_USE_CUDA
  typedef rtk::CudaFDKConeBeamReconstructionFilter FDKCUDAType;
  FDKCUDAType::Pointer feldkampCUDA;
#endif
  itk::Image< OutputPixelType, Dimension > *pfeldkamp = NULL;
  if(!strcmp(args_info.hardware_arg, "cpu") )
    {
    feldkamp = FDKCPUType::New();
    SET_FELDKAMP_OPTIONS( feldkamp );

    // Motion compensated CBCT settings
    if(args_info.signal_given && args_info.dvf_given)
      {
      dvfReader->SetFileName(args_info.dvf_arg);
      def->SetSignalFilename(args_info.signal_arg);
      feldkamp->SetBackProjectionFilter( bp.GetPointer() );
      }
    pfeldkamp = feldkamp->GetOutput();
    }
#ifdef RTK_USE_CUDA
  else if(!strcmp(args_info.hardware_arg, "cuda") )
    {
    // Motion compensation not supported in cuda
    if(args_info.signal_given && args_info.dvf_given)
      {
      std::cerr << "Motion compensation is not supported in CUDA. Aborting" << std::endl;
      return EXIT_FAILURE;
      }

    feldkampCUDA = FDKCUDAType::New();
    SET_FELDKAMP_OPTIONS( feldkampCUDA );
    pfeldkamp = feldkampCUDA->GetOutput();
    }
#endif
#ifdef RTK_USE_OPENCL
  else if(!strcmp(args_info.hardware_arg, "opencl") )
    {
    if(args_info.signal_given && args_info.dvf_given)
      {
      std::cerr << "Motion compensation is not supported in OpenCL. Aborting" << std::endl;
      return EXIT_FAILURE;
      }

    feldkampOCL = FDKOPENCLType::New();
    SET_FELDKAMP_OPTIONS( feldkampOCL );
    pfeldkamp = feldkampOCL->GetOutput();
    }
#endif

  // Streaming depending on streaming capability of writer
  typedef itk::StreamingImageFilter<CPUOutputImageType, CPUOutputImageType> StreamerType;
  StreamerType::Pointer streamerBP = StreamerType::New();
  streamerBP->SetInput( pfeldkamp );
  streamerBP->SetNumberOfStreamDivisions( args_info.divisions_arg );

  // Write
  typedef itk::ImageFileWriter<CPUOutputImageType> WriterType;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName( args_info.output_arg );
  writer->SetInput( streamerBP->GetOutput() );

  if(args_info.verbose_flag)
    std::cout << "Reconstructing and writing... " << std::flush;
  itk::TimeProbe writerProbe;

  writerProbe.Start();
  TRY_AND_EXIT_ON_ITK_EXCEPTION( writer->Update() );
  writerProbe.Stop();

  if(args_info.verbose_flag)
    {
    std::cout << "It took " << writerProbe.GetMean() << ' ' << readerProbe.GetUnit() << std::endl;
    if(!strcmp(args_info.hardware_arg, "cpu") )
      feldkamp->PrintTiming(std::cout);
#ifdef RTK_USE_CUDA
    else if(!strcmp(args_info.hardware_arg, "cuda") )
      feldkampCUDA->PrintTiming(std::cout);
#endif
#ifdef RTK_USE_OPENCL
    else if(!strcmp(args_info.hardware_arg, "opencl") )
      feldkampOCL->PrintTiming(std::cout);
#endif
    std::cout << std::endl;
    }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QtGui/QApplication>

#include "sessionconfigwindow.h"

int main(int argc, char** argv)
{
    // TODO/FIXME: maybe singleapp?
    QApplication a(argc, argv);
    a.setWindowIcon(QIcon(QString(SHARE_DIR) + "/graphics/razor_logo.png"));

    SessionConfigWindow w;
    w.show();

    return a.exec();
}<commit_msg>show icons in the config tools<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

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

#include <QtGui/QApplication>

#include <qtxdg/xdgicon.h>
#include <razorqt/razorsettings.h>

#include "sessionconfigwindow.h"

int main(int argc, char** argv)
{
    // TODO/FIXME: maybe singleapp?
    QApplication a(argc, argv);
    a.setWindowIcon(QIcon(QString(SHARE_DIR) + "/graphics/razor_logo.png"));
    XdgIcon::setThemeName(RazorSettings::globalSettings()->value("icon_theme").toString());

    SessionConfigWindow w;
    w.show();

    return a.exec();
}<|endoftext|>


<commit_before>#include "frameset.h"
#include "error.h"
#include "pad.h"

#include "private/frameset_p.h"

#include <algorithm>
#include <iostream>
#include <sstream>

namespace fileseq {

FrameSet::FrameSet() : m_frameData(new internal::FrameSetData) {

}

FrameSet::FrameSet(const std::string &frange, Status* ok)
    : m_frameData(new internal::FrameSetData(frange))
{
    Status stat;
    internal::RangeMatches matches;

    // Process the frame range and get a list of matches
    if (!(stat = internal::frameRangeMatches(matches, frange))) {
        if (ok != NULL) {
            *ok = stat;
        }
        setInvalid();
        return;
    }

    // Process each list of matches and add it to the frame set
    for (size_t i=0; i < matches.size(); ++i) {

        // If handleMatch succeeds, it will populate the FrameSet
        // with more parts of the range
        if (handleMatch(&matches[i], &stat), !stat) {

            // We could not process a match for some reason
            if (ok != NULL) {
                *ok = stat;
            }
            setInvalid();
            return;
        }
    }

    // A valid frameset
    if (ok != NULL) ok->clearError();

    // Save the original frame range string
    m_frameData->frameRange = frange;
}

FrameSet::~FrameSet() {
    setInvalid();
}

FrameSet::FrameSet(const FrameSet& other)
    : m_frameData(new internal::FrameSetData) {

    if (other.m_frameData != NULL) {
        (*m_frameData) = *(other.m_frameData);
    }
}

void FrameSet::setInvalid() {
    if ( m_frameData != NULL ) {
        delete m_frameData;
        m_frameData = NULL;
    }
}

void FrameSet::handleMatch(const internal::RangePatternMatch* match, Status* ok) {
    const int num = match->matches;

    ok->clearError();

    Frame start, end;
    size_t step = 1;

    switch (num) {

    // Single frame match
    case 1:
        start = match->start;
        m_frameData->ranges.appendUnique(start, start, 1);
        return;

    // Simple frame range
    case 2:
        start = match->start;
        end = match->end;

        // Handle descending frame ranges, like 10-1
        step = (start > end) ? -1 : 1;

        m_frameData->ranges.appendUnique(start, end, step);
        return;

    // Complex frame range
    case 4:
        start = match->start;
        end = match->end;
        step = match->step;

        if (step == 0) {
            ok->setError("Got invalid step value 0");
            return;
        }

        if (!internal::isRangeModifier(match->stepMod)) {
            std::stringstream ss;
            ss << match->stepMod << " is not one of the valid modifiers 'xy:'";
            ok->setError(ss.str());
        }

        char mod = match->stepMod[0];

        switch (mod) {

        case 'x':
            m_frameData->ranges.appendUnique(start, end, step);
            break;

        case 'y': {
            // TODO: Add proper support for adding inverse of range.
            // This approach will add excessive amounts of singe
            // range elements. They could be compressed into chunks
            Frame skip = start;
            Range aRange(start, end, 1);
            RangeIterator it = aRange.iterValues();
            Frame val;
            while (it.next()) {
                val = (*it);
                if (val == skip) {
                    skip += step;
                    continue;
                }
                m_frameData->ranges.appendUnique(val, val, 1);
            }
            break;
        }

        case ':':
            while (step > 0) {
                m_frameData->ranges.appendUnique(start, end, step);
                step--;
            }
            break;

        }

        return;
    }

    // If we get here, we  have not handled the match
    std::stringstream ss;
    ss << "Unexpected match size: " << num;
    ok->setError(ss.str());
}

// FrameSet::FrameSet(const FrameSet& rhs) : m_valid(false) {

// }

// FrameSet& FrameSet::operator=(const FrameSet& rhs) {

// }

bool FrameSet::isValid() const {
    return m_frameData != NULL;
}

std::string FrameSet::string() const {
    return isValid() ? m_frameData->frameRange : "";
}

size_t FrameSet::length() const {
    return isValid() ? m_frameData->ranges.length() : 0;
};

size_t FrameSet::index(Frame frame) const {
    return isValid() ? m_frameData->ranges.index(frame) : 0;
};

Frame FrameSet::frame(size_t index, Status* ok) const {
    if (!isValid()) {
        return 0;
    }

    return m_frameData->ranges.value(index, ok);
};

void FrameSet::frames(Frames &frames) const {
    frames.clear();

    if (!isValid()) {
        return;
    }

    size_t len = length();
    if (len <= 0) {
        return;
    }

    frames.reserve(len);

    RangesIterator it = m_frameData->ranges.iterValues();
    while (it.next()) {
        frames.push_back(*it);
    }
};

RangesIterator FrameSet::iterFrames() const {
    if (!isValid()) {
        return RangesIterator();
    }

    return m_frameData->ranges.iterValues();
}

bool FrameSet::hasFrame(Frame frame) const {
    return isValid() ? m_frameData->ranges.contains(frame) : false;
};

Frame FrameSet::start() const {
    return isValid() ? m_frameData->ranges.start() : 0;
};

Frame FrameSet::end() const {
    return isValid() ? m_frameData->ranges.end() : 0;
};

std::string FrameSet::frameRange(int pad) const {
    if (!isValid()) {
        return "";
    }

    if (pad < 2) {
        return m_frameData->frameRange;
    }

    return padFrameRange(m_frameData->frameRange, pad);
};

FrameSet FrameSet::inverted() const {
    FrameSet newFrameSet;

    if (!isValid()) {
        return newFrameSet;
    }

    // get a new range that is inverted
    Ranges ranges;
    m_frameData->ranges.inverted(ranges);

    // Create a new internal data member and swap in our ranges
    newFrameSet.m_frameData = new internal::FrameSetData();
    newFrameSet.m_frameData->frameRange = ranges.string();
    std::swap(newFrameSet.m_frameData->ranges, ranges);

    return newFrameSet;
};

std::string FrameSet::invertedFrameRange(int pad) const {
    if (!isValid()) {
        return "";
    }

    Ranges ranges;
    m_frameData->ranges.inverted(ranges);

    std::string frange = ranges.string();

    if (pad > 1) {
        frange = padFrameRange(frange, pad);
    }

    return frange;
};

FrameSet FrameSet::normalized() const {
    FrameSet newFrameSet;

    if (!isValid()) {
        return newFrameSet;
    }

    // get a new range that is normalized
    Ranges ranges;
    m_frameData->ranges.normalized(ranges);

    // Create a new internal data member and swap in our ranges
    newFrameSet.m_frameData = new internal::FrameSetData();
    newFrameSet.m_frameData->frameRange = ranges.string();
    std::swap(newFrameSet.m_frameData->ranges, ranges);

    return newFrameSet;
};

} // fileseq
<commit_msg>Deleted commented out junk code<commit_after>#include "frameset.h"
#include "error.h"
#include "pad.h"

#include "private/frameset_p.h"

#include <algorithm>
#include <iostream>
#include <sstream>

namespace fileseq {

FrameSet::FrameSet() : m_frameData(new internal::FrameSetData) {

}

FrameSet::FrameSet(const std::string &frange, Status* ok)
    : m_frameData(new internal::FrameSetData(frange))
{
    Status stat;
    internal::RangeMatches matches;

    // Process the frame range and get a list of matches
    if (!(stat = internal::frameRangeMatches(matches, frange))) {
        if (ok != NULL) {
            *ok = stat;
        }
        setInvalid();
        return;
    }

    // Process each list of matches and add it to the frame set
    for (size_t i=0; i < matches.size(); ++i) {

        // If handleMatch succeeds, it will populate the FrameSet
        // with more parts of the range
        if (handleMatch(&matches[i], &stat), !stat) {

            // We could not process a match for some reason
            if (ok != NULL) {
                *ok = stat;
            }
            setInvalid();
            return;
        }
    }

    // A valid frameset
    if (ok != NULL) ok->clearError();

    // Save the original frame range string
    m_frameData->frameRange = frange;
}

FrameSet::~FrameSet() {
    setInvalid();
}

FrameSet::FrameSet(const FrameSet& other)
    : m_frameData(new internal::FrameSetData) {

    if (other.m_frameData != NULL) {
        (*m_frameData) = *(other.m_frameData);
    }
}

void FrameSet::setInvalid() {
    if ( m_frameData != NULL ) {
        delete m_frameData;
        m_frameData = NULL;
    }
}

void FrameSet::handleMatch(const internal::RangePatternMatch* match, Status* ok) {
    const int num = match->matches;

    ok->clearError();

    Frame start, end;
    size_t step = 1;

    switch (num) {

    // Single frame match
    case 1:
        start = match->start;
        m_frameData->ranges.appendUnique(start, start, 1);
        return;

    // Simple frame range
    case 2:
        start = match->start;
        end = match->end;

        // Handle descending frame ranges, like 10-1
        step = (start > end) ? -1 : 1;

        m_frameData->ranges.appendUnique(start, end, step);
        return;

    // Complex frame range
    case 4:
        start = match->start;
        end = match->end;
        step = match->step;

        if (step == 0) {
            ok->setError("Got invalid step value 0");
            return;
        }

        if (!internal::isRangeModifier(match->stepMod)) {
            std::stringstream ss;
            ss << match->stepMod << " is not one of the valid modifiers 'xy:'";
            ok->setError(ss.str());
        }

        char mod = match->stepMod[0];

        switch (mod) {

        case 'x':
            m_frameData->ranges.appendUnique(start, end, step);
            break;

        case 'y': {
            // TODO: Add proper support for adding inverse of range.
            // This approach will add excessive amounts of singe
            // range elements. They could be compressed into chunks
            Frame skip = start;
            Range aRange(start, end, 1);
            RangeIterator it = aRange.iterValues();
            Frame val;
            while (it.next()) {
                val = (*it);
                if (val == skip) {
                    skip += step;
                    continue;
                }
                m_frameData->ranges.appendUnique(val, val, 1);
            }
            break;
        }

        case ':':
            while (step > 0) {
                m_frameData->ranges.appendUnique(start, end, step);
                step--;
            }
            break;

        }

        return;
    }

    // If we get here, we  have not handled the match
    std::stringstream ss;
    ss << "Unexpected match size: " << num;
    ok->setError(ss.str());
}

bool FrameSet::isValid() const {
    return m_frameData != NULL;
}

std::string FrameSet::string() const {
    return isValid() ? m_frameData->frameRange : "";
}

size_t FrameSet::length() const {
    return isValid() ? m_frameData->ranges.length() : 0;
};

size_t FrameSet::index(Frame frame) const {
    return isValid() ? m_frameData->ranges.index(frame) : 0;
};

Frame FrameSet::frame(size_t index, Status* ok) const {
    if (!isValid()) {
        return 0;
    }

    return m_frameData->ranges.value(index, ok);
};

void FrameSet::frames(Frames &frames) const {
    frames.clear();

    if (!isValid()) {
        return;
    }

    size_t len = length();
    if (len <= 0) {
        return;
    }

    frames.reserve(len);

    RangesIterator it = m_frameData->ranges.iterValues();
    while (it.next()) {
        frames.push_back(*it);
    }
};

RangesIterator FrameSet::iterFrames() const {
    if (!isValid()) {
        return RangesIterator();
    }

    return m_frameData->ranges.iterValues();
}

bool FrameSet::hasFrame(Frame frame) const {
    return isValid() ? m_frameData->ranges.contains(frame) : false;
};

Frame FrameSet::start() const {
    return isValid() ? m_frameData->ranges.start() : 0;
};

Frame FrameSet::end() const {
    return isValid() ? m_frameData->ranges.end() : 0;
};

std::string FrameSet::frameRange(int pad) const {
    if (!isValid()) {
        return "";
    }

    if (pad < 2) {
        return m_frameData->frameRange;
    }

    return padFrameRange(m_frameData->frameRange, pad);
};

FrameSet FrameSet::inverted() const {
    FrameSet newFrameSet;

    if (!isValid()) {
        return newFrameSet;
    }

    // get a new range that is inverted
    Ranges ranges;
    m_frameData->ranges.inverted(ranges);

    // Create a new internal data member and swap in our ranges
    newFrameSet.m_frameData = new internal::FrameSetData();
    newFrameSet.m_frameData->frameRange = ranges.string();
    std::swap(newFrameSet.m_frameData->ranges, ranges);

    return newFrameSet;
};

std::string FrameSet::invertedFrameRange(int pad) const {
    if (!isValid()) {
        return "";
    }

    Ranges ranges;
    m_frameData->ranges.inverted(ranges);

    std::string frange = ranges.string();

    if (pad > 1) {
        frange = padFrameRange(frange, pad);
    }

    return frange;
};

FrameSet FrameSet::normalized() const {
    FrameSet newFrameSet;

    if (!isValid()) {
        return newFrameSet;
    }

    // get a new range that is normalized
    Ranges ranges;
    m_frameData->ranges.normalized(ranges);

    // Create a new internal data member and swap in our ranges
    newFrameSet.m_frameData = new internal::FrameSetData();
    newFrameSet.m_frameData->frameRange = ranges.string();
    std::swap(newFrameSet.m_frameData->ranges, ranges);

    return newFrameSet;
};

} // fileseq
<|endoftext|>