<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "webkit/glue/image_decoder.h"

#include "base/compiler_specific.h"
#include "third_party/skia/include/core/SkBitmap.h"

MSVC_PUSH_WARNING_LEVEL(0);
#if defined(OS_WIN) || defined(OS_LINUX)
#include "ImageSourceSkia.h"
#elif defined(OS_MACOSX)
#include "ImageSource.h"
#include "RetainPtr.h"
#endif
#include "IntSize.h"
#include "RefPtr.h"
#include "SharedBuffer.h"
MSVC_POP_WARNING();

namespace webkit_glue {

ImageDecoder::ImageDecoder() : desired_icon_size_(0, 0) {
}

ImageDecoder::ImageDecoder(const gfx::Size& desired_icon_size)
    : desired_icon_size_(desired_icon_size) {
}

ImageDecoder::~ImageDecoder() {
}

SkBitmap ImageDecoder::Decode(const unsigned char* data, size_t size) const {

  // What's going on here? ImageDecoder is only used by ImageResourceFetcher,
  // which is only used (but extensively) by WebViewImpl. On the Mac we're using
  // CoreGraphics, but right now WebViewImpl uses SkBitmaps everywhere. For now,
  // this is a convenient bottleneck to convert from CGImageRefs to SkBitmaps,
  // but in the future we will need to replumb to get CGImageRefs (or whatever
  // the native type is) everywhere, directly.

#if defined(OS_WIN) || defined(OS_LINUX)
  WebCore::ImageSourceSkia source;
#elif defined(OS_MACOSX)
  WebCore::ImageSource source;
#endif
  WTF::RefPtr<WebCore::SharedBuffer> buffer(WebCore::SharedBuffer::create(
      data, static_cast<int>(size)));
#if defined(OS_WIN) || defined(OS_LINUX)
  source.setData(buffer.get(), true,
                 WebCore::IntSize(desired_icon_size_.width(),
                                  desired_icon_size_.height()));
#elif defined(OS_MACOSX)
  source.setData(buffer.get(), true);
#endif

  if (!source.isSizeAvailable())
    return SkBitmap();

  WebCore::NativeImagePtr frame0 = source.createFrameAtIndex(0);
  if (!frame0)
    return SkBitmap();

#if defined(OS_WIN) || defined(OS_LINUX)
  return *reinterpret_cast<SkBitmap*>(frame0);
#elif defined(OS_MACOSX)
  // BitmapImage releases automatically, but we're bypassing it so we'll need
  // to do the releasing.
  RetainPtr<CGImageRef> image(AdoptCF, frame0);

  SkBitmap result;
  result.setConfig(SkBitmap::kARGB_8888_Config, CGImageGetWidth(image.get()),
                   CGImageGetHeight(image.get()));

  // TODO(port):
  // This line is a waste, but is needed when the renderer sends a
  // ViewHostMsg_DidDownloadImage and tries to pickle the SkBitmap.
  // Presumably this will be removed when we (ImageDecoder::Decode())
  // are changed to not return a fake SkBitmap.
  result.allocPixels();

  RetainPtr<CGColorSpace> cg_color(AdoptCF, CGColorSpaceCreateDeviceRGB());
  // The last parameter is a total guess. Feel free to adjust it if images draw
  // incorrectly. TODO(avi): Verify byte ordering; it should be possible to
  // swizzle bytes with various combinations of the byte order and alpha
  // constants.
  RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(
                                             result.getPixels(),
                                             result.width(),
                                             result.height(),
                                             result.bytesPerPixel() * 8 / 4,
                                             result.rowBytes(),
                                             cg_color.get(),
                                             kCGImageAlphaPremultipliedFirst |
                                             kCGBitmapByteOrder32Host));
  CGRect rect = CGRectMake(0, 0,
                           CGImageGetWidth(image.get()),
                           CGImageGetHeight(image.get()));
  CGContextDrawImage(context.get(), rect, image.get());

  return result;
#endif
}

}  // namespace webkit_glue
<commit_msg>Fix a leak in ImageDecoder::Decode.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "webkit/glue/image_decoder.h"

#include "base/compiler_specific.h"
#include "third_party/skia/include/core/SkBitmap.h"

MSVC_PUSH_WARNING_LEVEL(0);
#if defined(OS_WIN) || defined(OS_LINUX)
#include "ImageSourceSkia.h"
#include "NativeImageSkia.h"
#elif defined(OS_MACOSX)
#include "ImageSource.h"
#include "RetainPtr.h"
#endif
#include "IntSize.h"
#include "RefPtr.h"
#include "SharedBuffer.h"
MSVC_POP_WARNING();

namespace webkit_glue {

ImageDecoder::ImageDecoder() : desired_icon_size_(0, 0) {
}

ImageDecoder::ImageDecoder(const gfx::Size& desired_icon_size)
    : desired_icon_size_(desired_icon_size) {
}

ImageDecoder::~ImageDecoder() {
}

SkBitmap ImageDecoder::Decode(const unsigned char* data, size_t size) const {

  // What's going on here? ImageDecoder is only used by ImageResourceFetcher,
  // which is only used (but extensively) by WebViewImpl. On the Mac we're using
  // CoreGraphics, but right now WebViewImpl uses SkBitmaps everywhere. For now,
  // this is a convenient bottleneck to convert from CGImageRefs to SkBitmaps,
  // but in the future we will need to replumb to get CGImageRefs (or whatever
  // the native type is) everywhere, directly.

#if defined(OS_WIN) || defined(OS_LINUX)
  WebCore::ImageSourceSkia source;
#elif defined(OS_MACOSX)
  WebCore::ImageSource source;
#endif
  WTF::RefPtr<WebCore::SharedBuffer> buffer(WebCore::SharedBuffer::create(
      data, static_cast<int>(size)));
#if defined(OS_WIN) || defined(OS_LINUX)
  source.setData(buffer.get(), true,
                 WebCore::IntSize(desired_icon_size_.width(),
                                  desired_icon_size_.height()));
#elif defined(OS_MACOSX)
  source.setData(buffer.get(), true);
#endif

  if (!source.isSizeAvailable())
    return SkBitmap();

  WebCore::NativeImagePtr frame0 = source.createFrameAtIndex(0);
  if (!frame0)
    return SkBitmap();

#if defined(OS_WIN) || defined(OS_LINUX)
  SkBitmap retval = *reinterpret_cast<SkBitmap*>(frame0);
  delete frame0;
  return retval;
#elif defined(OS_MACOSX)
  // TODO(port): should we delete frame0 like Linux/Windows do above?
  // BitmapImage releases automatically, but we're bypassing it so we'll need
  // to do the releasing.
  RetainPtr<CGImageRef> image(AdoptCF, frame0);

  SkBitmap result;
  result.setConfig(SkBitmap::kARGB_8888_Config, CGImageGetWidth(image.get()),
                   CGImageGetHeight(image.get()));

  // TODO(port):
  // This line is a waste, but is needed when the renderer sends a
  // ViewHostMsg_DidDownloadImage and tries to pickle the SkBitmap.
  // Presumably this will be removed when we (ImageDecoder::Decode())
  // are changed to not return a fake SkBitmap.
  result.allocPixels();

  RetainPtr<CGColorSpace> cg_color(AdoptCF, CGColorSpaceCreateDeviceRGB());
  // The last parameter is a total guess. Feel free to adjust it if images draw
  // incorrectly. TODO(avi): Verify byte ordering; it should be possible to
  // swizzle bytes with various combinations of the byte order and alpha
  // constants.
  RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(
                                             result.getPixels(),
                                             result.width(),
                                             result.height(),
                                             result.bytesPerPixel() * 8 / 4,
                                             result.rowBytes(),
                                             cg_color.get(),
                                             kCGImageAlphaPremultipliedFirst |
                                             kCGBitmapByteOrder32Host));
  CGRect rect = CGRectMake(0, 0,
                           CGImageGetWidth(image.get()),
                           CGImageGetHeight(image.get()));
  CGContextDrawImage(context.get(), rect, image.get());

  return result;
#endif
}

}  // namespace webkit_glue
<|endoftext|>


<commit_before>#ifndef VIENNAFVM_QUANTITY_HPP
#define VIENNAFVM_QUANTITY_HPP

/* =======================================================================
   Copyright (c) 2011, Institute for Microelectronics, TU Wien
   http://www.iue.tuwien.ac.at
                             -----------------
           ViennaFVM - The Vienna Finite Volume Method Library
                             -----------------

   authors:    Karl Rupp                          rupp@iue.tuwien.ac.at
               (add your name here)

   license:    To be discussed, see file LICENSE in the ViennaFVM base directory
======================================================================= */

#include "viennafvm/forwards.h"

#include "viennamath/forwards.h"
#include "viennamath/manipulation/substitute.hpp"
#include "viennamath/expression.hpp"

#include "viennagrid/forwards.hpp"
#include "viennagrid/mesh/segmentation.hpp"

/** @file  quantity.hpp
    @brief Defines the basic quantity which may be entirely known or unknown (with suitable boundary conditions) over a mesh
*/

namespace viennafvm
{
  namespace traits {

  template<typename EleT>
  inline std::size_t id(EleT const& elem)
  {
    return elem.id().get();
  }

  } // traits

  template<typename AssociatedT, typename ValueT = double>
  class quantity
  {
    public:
      typedef ValueT         value_type;
      typedef AssociatedT    associated_type;

      quantity() {}  // to fulfill default constructible concept!

      quantity(std::size_t id,
               std::string const & quan_name,
               std::size_t num_values,
               value_type default_value = value_type())
        : id_(id),
          name_(quan_name),
          values_          (num_values, default_value),
          boundary_types_  (num_values, BOUNDARY_NONE),
          boundary_values_ (num_values, default_value),
          unknown_mask_    (num_values, false),
          unknowns_indices_(num_values, -1)
      {}

      std::string get_name() const { return name_; }

      ValueT get_value(associated_type const & elem) const         { return values_.at(viennafvm::traits::id(elem));         }
      void   set_value(associated_type const & elem, ValueT value) {        values_.at(viennafvm::traits::id(elem)) = value; }

      // Dirichlet and Neumann
      ValueT get_boundary_value(associated_type const & elem) const         { return boundary_values_.at(viennafvm::traits::id(elem));         }
      void   set_boundary_value(associated_type const & elem, ValueT value) {        boundary_values_.at(viennafvm::traits::id(elem)) = value; }

      boundary_type_id get_boundary_type(associated_type const & elem) const                   { return boundary_types_.at(viennafvm::traits::id(elem));         }
      void             set_boundary_type(associated_type const & elem, boundary_type_id value) {        boundary_types_.at(viennafvm::traits::id(elem)) = value; }

      bool   get_unknown_mask(associated_type const & elem) const       { return unknown_mask_.at(viennafvm::traits::id(elem));         }
      void   set_unknown_mask(associated_type const & elem, bool value) {        unknown_mask_.at(viennafvm::traits::id(elem)) = value; }

      long   get_unknown_index(associated_type const & elem) const       { return unknowns_indices_.at(viennafvm::traits::id(elem));         }
      void   set_unknown_index(associated_type const & elem, long value) {        unknowns_indices_.at(viennafvm::traits::id(elem)) = value; }

      std::size_t get_unknown_num() const
      {
        std::size_t num = 0;
        for (std::size_t i=0; i<unknowns_indices_.size(); ++i)
        {
          if (unknowns_indices_[i] >= 0)
            ++num;
        }
        return num;
      }

      // possible design flaws:
      std::vector<ValueT> const & values() const { return values_; }

      std::size_t const& id    ()              const { return id_; }
      void               set_id(std::size_t id)      { id_ = id;   }

    private:
//      std::size_t id(associated_type const elem) const { return elem.id().get(); }

      std::size_t                    id_;
      std::string                    name_;
      std::vector<ValueT>            values_;
      std::vector<boundary_type_id>  boundary_types_;
      std::vector<ValueT>            boundary_values_;
      std::vector<bool>              unknown_mask_;
      std::vector<long>              unknowns_indices_;
  };
}

#endif
<commit_msg>@Quantity class: added 'are_entries_zero()' and 'get_sum()' methods<commit_after>#ifndef VIENNAFVM_QUANTITY_HPP
#define VIENNAFVM_QUANTITY_HPP

/* =======================================================================
   Copyright (c) 2011, Institute for Microelectronics, TU Wien
   http://www.iue.tuwien.ac.at
                             -----------------
           ViennaFVM - The Vienna Finite Volume Method Library
                             -----------------

   authors:    Karl Rupp                          rupp@iue.tuwien.ac.at
               (add your name here)

   license:    To be discussed, see file LICENSE in the ViennaFVM base directory
======================================================================= */

#include <numeric>

#include "viennafvm/forwards.h"

#include "viennamath/forwards.h"
#include "viennamath/manipulation/substitute.hpp"
#include "viennamath/expression.hpp"

#include "viennagrid/forwards.hpp"
#include "viennagrid/mesh/segmentation.hpp"

/** @file  quantity.hpp
    @brief Defines the basic quantity which may be entirely known or unknown (with suitable boundary conditions) over a mesh
*/

namespace viennafvm
{
  namespace traits {

  template<typename EleT>
  inline std::size_t id(EleT const& elem)
  {
    return elem.id().get();
  }

  } // traits

  template<typename AssociatedT, typename ValueT = double>
  class quantity
  {
    public:
      typedef ValueT         value_type;
      typedef AssociatedT    associated_type;

      quantity() {}  // to fulfill default constructible concept!

      quantity(std::size_t id,
               std::string const & quan_name,
               std::size_t num_values,
               value_type default_value = value_type())
        : id_(id),
          name_(quan_name),
          values_          (num_values, default_value),
          boundary_types_  (num_values, BOUNDARY_NONE),
          boundary_values_ (num_values, default_value),
          unknown_mask_    (num_values, false),
          unknowns_indices_(num_values, -1)
      {}

      std::string get_name() const { return name_; }

      ValueT get_value(associated_type const & elem) const         { return values_.at(viennafvm::traits::id(elem));         }
      void   set_value(associated_type const & elem, ValueT value) {        values_.at(viennafvm::traits::id(elem)) = value; }

      // Dirichlet and Neumann
      ValueT get_boundary_value(associated_type const & elem) const         { return boundary_values_.at(viennafvm::traits::id(elem));         }
      void   set_boundary_value(associated_type const & elem, ValueT value) {        boundary_values_.at(viennafvm::traits::id(elem)) = value; }

      boundary_type_id get_boundary_type(associated_type const & elem) const                   { return boundary_types_.at(viennafvm::traits::id(elem));         }
      void             set_boundary_type(associated_type const & elem, boundary_type_id value) {        boundary_types_.at(viennafvm::traits::id(elem)) = value; }

      bool   get_unknown_mask(associated_type const & elem) const       { return unknown_mask_.at(viennafvm::traits::id(elem));         }
      void   set_unknown_mask(associated_type const & elem, bool value) {        unknown_mask_.at(viennafvm::traits::id(elem)) = value; }

      long   get_unknown_index(associated_type const & elem) const       { return unknowns_indices_.at(viennafvm::traits::id(elem));         }
      void   set_unknown_index(associated_type const & elem, long value) {        unknowns_indices_.at(viennafvm::traits::id(elem)) = value; }

      std::size_t get_unknown_num() const
      {
        std::size_t num = 0;
        for (std::size_t i=0; i<unknowns_indices_.size(); ++i)
        {
          if (unknowns_indices_[i] >= 0)
            ++num;
        }
        return num;
      }

      bool are_entries_zero()
      {
        if( std::fabs(this->get_sum()) < 1.0E-20 ) return true;
        else return false;
      }

      value_type get_sum()
      {
        return std::accumulate(values_.begin(), values_.end(), 0.0);
      }

      // possible design flaws:
      std::vector<ValueT> const & values() const { return values_; }

      std::size_t const& id    ()              const { return id_; }
      void               set_id(std::size_t id)      { id_ = id;   }

    private:
//      std::size_t id(associated_type const elem) const { return elem.id().get(); }

      std::size_t                    id_;
      std::string                    name_;
      std::vector<ValueT>            values_;
      std::vector<boundary_type_id>  boundary_types_;
      std::vector<ValueT>            boundary_values_;
      std::vector<bool>              unknown_mask_;
      std::vector<long>              unknowns_indices_;
  };
}

#endif
<|endoftext|>


<commit_before>#include "qmljslink.h"

#include "parser/qmljsast_p.h"
#include "qmljsdocument.h"
#include "qmljsbind.h"

#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>

using namespace QmlJS;
using namespace QmlJS::Interpreter;
using namespace QmlJS::AST;

Link::Link(Context *context, Document::Ptr currentDoc, const Snapshot &snapshot)
    : _snapshot(snapshot)
    , _context(context)
{
    _docs = reachableDocuments(currentDoc, snapshot);
    linkImports();
}

Link::~Link()
{
}

Interpreter::Engine *Link::engine()
{
    return _context->engine();
}

void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
{
    // ### TODO: This object ought to contain the global namespace additions by QML.
    _context->pushScope(engine()->globalObject());

    if (! doc)
        return;

    Bind *bind = doc->bind();
    QStringList linkedDocs; // to prevent cycles

    if (doc->qmlProgram()) {
        _context->setLookupMode(Context::QmlLookup);

        ObjectValue *scopeObject = 0;
        if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
            scopeObject = bind->findQmlObject(definition);
        else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
            scopeObject = bind->findQmlObject(binding);

        pushScopeChainForComponent(doc, &linkedDocs, scopeObject);

        if (const ObjectValue *typeEnvironment = _context->typeEnvironment(doc.data()))
            _context->pushScope(typeEnvironment);
    } else {
        // add scope chains for all components that source this document
        foreach (Document::Ptr otherDoc, _docs) {
            if (otherDoc->bind()->includedScripts().contains(doc->fileName()))
                pushScopeChainForComponent(otherDoc, &linkedDocs);
        }

        // ### TODO: Which type environment do scripts see?

        _context->pushScope(bind->rootObjectValue());
    }

    if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) {
        ObjectValue *activation = engine()->newObject(/*prototype = */ 0);
        for (FormalParameterList *it = fun->formals; it; it = it->next) {
            if (it->name)
                activation->setProperty(it->name->asString(), engine()->undefinedValue());
        }
        _context->pushScope(activation);
    }
}

void Link::pushScopeChainForComponent(Document::Ptr doc, QStringList *linkedDocs,
                                      ObjectValue *scopeObject)
{
    if (!doc->qmlProgram())
        return;

    linkedDocs->append(doc->fileName());

    Bind *bind = doc->bind();

    // add scopes for all components instantiating this one
    foreach (Document::Ptr otherDoc, _docs) {
        if (linkedDocs->contains(otherDoc->fileName()))
            continue;

        if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), _context)) {
            // ### TODO: Depth-first insertion doesn't give us correct name shadowing.
            pushScopeChainForComponent(otherDoc, linkedDocs);
        }
    }

    if (bind->rootObjectValue())
        _context->pushScope(bind->rootObjectValue());

    if (scopeObject && scopeObject != bind->rootObjectValue())
        _context->pushScope(scopeObject);

    const QStringList &includedScripts = bind->includedScripts();
    for (int index = includedScripts.size() - 1; index != -1; --index) {
        const QString &scriptFile = includedScripts.at(index);

        if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) {
            if (scriptDoc->jsProgram()) {
                _context->pushScope(scriptDoc->bind()->rootObjectValue());
            }
        }
    }

    _context->pushScope(bind->functionEnvironment());
    _context->pushScope(bind->idEnvironment());
}

void Link::linkImports()
{
    foreach (Document::Ptr doc, _docs) {
        ObjectValue *typeEnv = engine()->newObject(/*prototype =*/0); // ### FIXME

        // Populate the _typeEnvironment with imports.
        populateImportedTypes(typeEnv, doc);

        _context->setTypeEnvironment(doc.data(), typeEnv);
    }
}

static QString componentName(const QString &fileName)
{
    QString componentName = fileName;
    int dotIndex = componentName.indexOf(QLatin1Char('.'));
    if (dotIndex != -1)
        componentName.truncate(dotIndex);
    componentName[0] = componentName[0].toUpper();
    return componentName;
}

void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Ptr doc)
{
    if (! (doc->qmlProgram() && doc->qmlProgram()->imports))
        return;

    QFileInfo fileInfo(doc->fileName());
    const QString absolutePath = fileInfo.absolutePath();

    // implicit imports:
    // qml files in the same directory are available without explicit imports
    foreach (Document::Ptr otherDoc, _docs) {
        if (otherDoc == doc)
            continue;

        QFileInfo otherFileInfo(otherDoc->fileName());
        const QString otherAbsolutePath = otherFileInfo.absolutePath();

        if (otherAbsolutePath != absolutePath)
            continue;

        typeEnv->setProperty(componentName(otherFileInfo.fileName()),
                             otherDoc->bind()->rootObjectValue());
    }

    // explicit imports, whether directories or files
    for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
        if (! it->import)
            continue;

        if (it->import->fileName) {
            importFile(typeEnv, doc, it->import, absolutePath);
        } else if (it->import->importUri) {
            importNonFile(typeEnv, doc, it->import);
        }
    }
}

/*
    import "content"
    import "content" as Xxx
    import "content" 4.6
    import "content" 4.6 as Xxx

    import "http://www.ovi.com/" as Ovi
*/
void Link::importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
                      AST::UiImport *import, const QString &startPath)
{
    Q_UNUSED(doc)

    if (!import->fileName)
        return;

    QString path = startPath;
    path += QLatin1Char('/');
    path += import->fileName->asString();
    path = QDir::cleanPath(path);

    ObjectValue *importNamespace = 0;

    foreach (Document::Ptr otherDoc, _docs) {
        QFileInfo otherFileInfo(otherDoc->fileName());
        const QString otherAbsolutePath = otherFileInfo.absolutePath();

        bool directoryImport = (path == otherAbsolutePath);
        bool fileImport = (path == otherDoc->fileName());
        if (!directoryImport && !fileImport)
            continue;

        if (directoryImport && import->importId && !importNamespace) {
            importNamespace = engine()->newObject(/*prototype =*/0);
            typeEnv->setProperty(import->importId->asString(), importNamespace);
        }

        QString targetName;
        if (fileImport && import->importId) {
            targetName = import->importId->asString();
        } else {
            targetName = componentName(otherFileInfo.fileName());
        }

        ObjectValue *importInto = typeEnv;
        if (importNamespace)
            importInto = importNamespace;

        importInto->setProperty(targetName, otherDoc->bind()->rootObjectValue());
    }
}

/*
  import Qt 4.6
  import Qt 4.6 as Xxx
  (import com.nokia.qt is the same as the ones above)
*/
void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, AST::UiImport *import)
{
    ObjectValue *namespaceObject = 0;

    if (import->importId) { // with namespace we insert an object in the type env. to hold the imported types
        namespaceObject = engine()->newObject(/*prototype */ 0);
        typeEnv->setProperty(import->importId->asString(), namespaceObject);

    } else { // without namespace we insert all types directly into the type env.
        namespaceObject = typeEnv;
    }

    // try the metaobject system
    if (import->importUri) {
        const QString package = Bind::toString(import->importUri, '/');
        int majorVersion = -1; // ### TODO: Check these magic version numbers
        int minorVersion = -1; // ### TODO: Check these magic version numbers

        if (import->versionToken.isValid()) {
            const QString versionString = doc->source().mid(import->versionToken.offset, import->versionToken.length);
            const int dotIdx = versionString.indexOf(QLatin1Char('.'));
            if (dotIdx == -1) {
                // only major (which is probably invalid, but let's handle it anyway)
                majorVersion = versionString.toInt();
                minorVersion = 0; // ### TODO: Check with magic version numbers above
            } else {
                majorVersion = versionString.left(dotIdx).toInt();
                minorVersion = versionString.mid(dotIdx + 1).toInt();
            }
        }
#ifndef NO_DECLARATIVE_BACKEND
        foreach (QmlObjectValue *object, engine()->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
            namespaceObject->setProperty(object->qmlTypeName(), object);
        }
#endif // NO_DECLARATIVE_BACKEND
    }
}

UiQualifiedId *Link::qualifiedTypeNameId(Node *node)
{
    if (UiObjectBinding *binding = AST::cast<UiObjectBinding *>(node))
        return binding->qualifiedTypeNameId;
    else if (UiObjectDefinition *binding = AST::cast<UiObjectDefinition *>(node))
        return binding->qualifiedTypeNameId;
    else
        return 0;
}

static uint qHash(Document::Ptr doc) {
    return qHash(doc.data());
}

QList<Document::Ptr> Link::reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot)
{
    QSet<Document::Ptr> docs;

    if (! startDoc)
        return docs.values();

    QMultiHash<QString, Document::Ptr> documentByPath;
    foreach (Document::Ptr doc, snapshot)
        documentByPath.insert(doc->path(), doc);

    // ### TODO: This doesn't scale well. Maybe just use the whole snapshot?
    // Find all documents that (indirectly) include startDoc
    {
        QList<Document::Ptr> todo;
        todo += startDoc;

        while (! todo.isEmpty()) {
            Document::Ptr doc = todo.takeFirst();

            docs += doc;

            Snapshot::const_iterator it, end = snapshot.end();
            for (it = snapshot.begin(); it != end; ++it) {
                Document::Ptr otherDoc = *it;
                if (docs.contains(otherDoc))
                    continue;

                QStringList localImports = otherDoc->bind()->localImports();
                if (localImports.contains(doc->fileName())
                    || localImports.contains(doc->path())
                    || otherDoc->bind()->includedScripts().contains(doc->fileName())
                ) {
                    todo += otherDoc;
                }
            }
        }
    }

    // Find all documents that are included by these (even if indirectly).
    {
        QSet<QString> processed;
        QStringList todo;
        foreach (Document::Ptr doc, docs)
            todo.append(doc->fileName());

        while (! todo.isEmpty()) {
            QString path = todo.takeFirst();

            if (processed.contains(path))
                continue;
            processed.insert(path);

            if (Document::Ptr doc = snapshot.document(path)) {
                docs += doc;

                if (doc->qmlProgram())
                    path = doc->path();
                else
                    continue;
            }

            QStringList localImports;
            foreach (Document::Ptr doc, documentByPath.values(path)) {
                if (doc->qmlProgram()) {
                    docs += doc;
                    localImports += doc->bind()->localImports();
                    localImports += doc->bind()->includedScripts();
                }
            }

            localImports.removeDuplicates();
            todo += localImports;
        }
    }

    return docs.values();
}
<commit_msg>Remove the lookup into including Qml files in the root scope of a JS file.<commit_after>#include "qmljslink.h"

#include "parser/qmljsast_p.h"
#include "qmljsdocument.h"
#include "qmljsbind.h"

#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>

using namespace QmlJS;
using namespace QmlJS::Interpreter;
using namespace QmlJS::AST;

Link::Link(Context *context, Document::Ptr currentDoc, const Snapshot &snapshot)
    : _snapshot(snapshot)
    , _context(context)
{
    _docs = reachableDocuments(currentDoc, snapshot);
    linkImports();
}

Link::~Link()
{
}

Interpreter::Engine *Link::engine()
{
    return _context->engine();
}

void Link::scopeChainAt(Document::Ptr doc, Node *currentObject)
{
    // ### TODO: This object ought to contain the global namespace additions by QML.
    _context->pushScope(engine()->globalObject());

    if (! doc)
        return;

    Bind *bind = doc->bind();
    QStringList linkedDocs; // to prevent cycles

    if (doc->qmlProgram()) {
        _context->setLookupMode(Context::QmlLookup);

        ObjectValue *scopeObject = 0;
        if (UiObjectDefinition *definition = cast<UiObjectDefinition *>(currentObject))
            scopeObject = bind->findQmlObject(definition);
        else if (UiObjectBinding *binding = cast<UiObjectBinding *>(currentObject))
            scopeObject = bind->findQmlObject(binding);

        pushScopeChainForComponent(doc, &linkedDocs, scopeObject);

        if (const ObjectValue *typeEnvironment = _context->typeEnvironment(doc.data()))
            _context->pushScope(typeEnvironment);
    } else {
        // the global scope of a js file does not see the instantiating component
        if (currentObject != 0) {
            // add scope chains for all components that source this document
            foreach (Document::Ptr otherDoc, _docs) {
                if (otherDoc->bind()->includedScripts().contains(doc->fileName()))
                    pushScopeChainForComponent(otherDoc, &linkedDocs);
            }

            // ### TODO: Which type environment do scripts see?
        }

        _context->pushScope(bind->rootObjectValue());
    }

    if (FunctionDeclaration *fun = cast<FunctionDeclaration *>(currentObject)) {
        ObjectValue *activation = engine()->newObject(/*prototype = */ 0);
        for (FormalParameterList *it = fun->formals; it; it = it->next) {
            if (it->name)
                activation->setProperty(it->name->asString(), engine()->undefinedValue());
        }
        _context->pushScope(activation);
    }
}

void Link::pushScopeChainForComponent(Document::Ptr doc, QStringList *linkedDocs,
                                      ObjectValue *scopeObject)
{
    if (!doc->qmlProgram())
        return;

    linkedDocs->append(doc->fileName());

    Bind *bind = doc->bind();

    // add scopes for all components instantiating this one
    foreach (Document::Ptr otherDoc, _docs) {
        if (linkedDocs->contains(otherDoc->fileName()))
            continue;

        if (otherDoc->bind()->usesQmlPrototype(bind->rootObjectValue(), _context)) {
            // ### TODO: Depth-first insertion doesn't give us correct name shadowing.
            pushScopeChainForComponent(otherDoc, linkedDocs);
        }
    }

    if (bind->rootObjectValue())
        _context->pushScope(bind->rootObjectValue());

    if (scopeObject && scopeObject != bind->rootObjectValue())
        _context->pushScope(scopeObject);

    const QStringList &includedScripts = bind->includedScripts();
    for (int index = includedScripts.size() - 1; index != -1; --index) {
        const QString &scriptFile = includedScripts.at(index);

        if (Document::Ptr scriptDoc = _snapshot.document(scriptFile)) {
            if (scriptDoc->jsProgram()) {
                _context->pushScope(scriptDoc->bind()->rootObjectValue());
            }
        }
    }

    _context->pushScope(bind->functionEnvironment());
    _context->pushScope(bind->idEnvironment());
}

void Link::linkImports()
{
    foreach (Document::Ptr doc, _docs) {
        ObjectValue *typeEnv = engine()->newObject(/*prototype =*/0); // ### FIXME

        // Populate the _typeEnvironment with imports.
        populateImportedTypes(typeEnv, doc);

        _context->setTypeEnvironment(doc.data(), typeEnv);
    }
}

static QString componentName(const QString &fileName)
{
    QString componentName = fileName;
    int dotIndex = componentName.indexOf(QLatin1Char('.'));
    if (dotIndex != -1)
        componentName.truncate(dotIndex);
    componentName[0] = componentName[0].toUpper();
    return componentName;
}

void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Ptr doc)
{
    if (! (doc->qmlProgram() && doc->qmlProgram()->imports))
        return;

    QFileInfo fileInfo(doc->fileName());
    const QString absolutePath = fileInfo.absolutePath();

    // implicit imports:
    // qml files in the same directory are available without explicit imports
    foreach (Document::Ptr otherDoc, _docs) {
        if (otherDoc == doc)
            continue;

        QFileInfo otherFileInfo(otherDoc->fileName());
        const QString otherAbsolutePath = otherFileInfo.absolutePath();

        if (otherAbsolutePath != absolutePath)
            continue;

        typeEnv->setProperty(componentName(otherFileInfo.fileName()),
                             otherDoc->bind()->rootObjectValue());
    }

    // explicit imports, whether directories or files
    for (UiImportList *it = doc->qmlProgram()->imports; it; it = it->next) {
        if (! it->import)
            continue;

        if (it->import->fileName) {
            importFile(typeEnv, doc, it->import, absolutePath);
        } else if (it->import->importUri) {
            importNonFile(typeEnv, doc, it->import);
        }
    }
}

/*
    import "content"
    import "content" as Xxx
    import "content" 4.6
    import "content" 4.6 as Xxx

    import "http://www.ovi.com/" as Ovi
*/
void Link::importFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc,
                      AST::UiImport *import, const QString &startPath)
{
    Q_UNUSED(doc)

    if (!import->fileName)
        return;

    QString path = startPath;
    path += QLatin1Char('/');
    path += import->fileName->asString();
    path = QDir::cleanPath(path);

    ObjectValue *importNamespace = 0;

    foreach (Document::Ptr otherDoc, _docs) {
        QFileInfo otherFileInfo(otherDoc->fileName());
        const QString otherAbsolutePath = otherFileInfo.absolutePath();

        bool directoryImport = (path == otherAbsolutePath);
        bool fileImport = (path == otherDoc->fileName());
        if (!directoryImport && !fileImport)
            continue;

        if (directoryImport && import->importId && !importNamespace) {
            importNamespace = engine()->newObject(/*prototype =*/0);
            typeEnv->setProperty(import->importId->asString(), importNamespace);
        }

        QString targetName;
        if (fileImport && import->importId) {
            targetName = import->importId->asString();
        } else {
            targetName = componentName(otherFileInfo.fileName());
        }

        ObjectValue *importInto = typeEnv;
        if (importNamespace)
            importInto = importNamespace;

        importInto->setProperty(targetName, otherDoc->bind()->rootObjectValue());
    }
}

/*
  import Qt 4.6
  import Qt 4.6 as Xxx
  (import com.nokia.qt is the same as the ones above)
*/
void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, AST::UiImport *import)
{
    ObjectValue *namespaceObject = 0;

    if (import->importId) { // with namespace we insert an object in the type env. to hold the imported types
        namespaceObject = engine()->newObject(/*prototype */ 0);
        typeEnv->setProperty(import->importId->asString(), namespaceObject);

    } else { // without namespace we insert all types directly into the type env.
        namespaceObject = typeEnv;
    }

    // try the metaobject system
    if (import->importUri) {
        const QString package = Bind::toString(import->importUri, '/');
        int majorVersion = -1; // ### TODO: Check these magic version numbers
        int minorVersion = -1; // ### TODO: Check these magic version numbers

        if (import->versionToken.isValid()) {
            const QString versionString = doc->source().mid(import->versionToken.offset, import->versionToken.length);
            const int dotIdx = versionString.indexOf(QLatin1Char('.'));
            if (dotIdx == -1) {
                // only major (which is probably invalid, but let's handle it anyway)
                majorVersion = versionString.toInt();
                minorVersion = 0; // ### TODO: Check with magic version numbers above
            } else {
                majorVersion = versionString.left(dotIdx).toInt();
                minorVersion = versionString.mid(dotIdx + 1).toInt();
            }
        }
#ifndef NO_DECLARATIVE_BACKEND
        foreach (QmlObjectValue *object, engine()->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
            namespaceObject->setProperty(object->qmlTypeName(), object);
        }
#endif // NO_DECLARATIVE_BACKEND
    }
}

UiQualifiedId *Link::qualifiedTypeNameId(Node *node)
{
    if (UiObjectBinding *binding = AST::cast<UiObjectBinding *>(node))
        return binding->qualifiedTypeNameId;
    else if (UiObjectDefinition *binding = AST::cast<UiObjectDefinition *>(node))
        return binding->qualifiedTypeNameId;
    else
        return 0;
}

static uint qHash(Document::Ptr doc) {
    return qHash(doc.data());
}

QList<Document::Ptr> Link::reachableDocuments(Document::Ptr startDoc, const Snapshot &snapshot)
{
    QSet<Document::Ptr> docs;

    if (! startDoc)
        return docs.values();

    QMultiHash<QString, Document::Ptr> documentByPath;
    foreach (Document::Ptr doc, snapshot)
        documentByPath.insert(doc->path(), doc);

    // ### TODO: This doesn't scale well. Maybe just use the whole snapshot?
    // Find all documents that (indirectly) include startDoc
    {
        QList<Document::Ptr> todo;
        todo += startDoc;

        while (! todo.isEmpty()) {
            Document::Ptr doc = todo.takeFirst();

            docs += doc;

            Snapshot::const_iterator it, end = snapshot.end();
            for (it = snapshot.begin(); it != end; ++it) {
                Document::Ptr otherDoc = *it;
                if (docs.contains(otherDoc))
                    continue;

                QStringList localImports = otherDoc->bind()->localImports();
                if (localImports.contains(doc->fileName())
                    || localImports.contains(doc->path())
                    || otherDoc->bind()->includedScripts().contains(doc->fileName())
                ) {
                    todo += otherDoc;
                }
            }
        }
    }

    // Find all documents that are included by these (even if indirectly).
    {
        QSet<QString> processed;
        QStringList todo;
        foreach (Document::Ptr doc, docs)
            todo.append(doc->fileName());

        while (! todo.isEmpty()) {
            QString path = todo.takeFirst();

            if (processed.contains(path))
                continue;
            processed.insert(path);

            if (Document::Ptr doc = snapshot.document(path)) {
                docs += doc;

                if (doc->qmlProgram())
                    path = doc->path();
                else
                    continue;
            }

            QStringList localImports;
            foreach (Document::Ptr doc, documentByPath.values(path)) {
                if (doc->qmlProgram()) {
                    docs += doc;
                    localImports += doc->bind()->localImports();
                    localImports += doc->bind()->includedScripts();
                }
            }

            localImports.removeDuplicates();
            todo += localImports;
        }
    }

    return docs.values();
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software 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 <fstream>
#include "itkConnectedThresholdImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkFilterWatcher.h"

int itkConnectedThresholdImageFilterTest(int ac, char* av[] )
{
  if(ac < 7)
    {
    std::cerr << "Usage: " << av[0]
      << " InputImage OutputImage "
      << "seed_x seed_y "
      << "LowerConnectedThreshold UpperConnectedThreshold "
      << "Connectivity[1=Full,0=Face]" << std::endl;
    return -1;
    }

  typedef unsigned char            PixelType;
  typedef itk::Image<PixelType, 2> myImage;

  itk::ImageFileReader<myImage>::Pointer input
    = itk::ImageFileReader<myImage>::New();
  input->SetFileName(av[1]);

  // Create a filter
  typedef itk::ConnectedThresholdImageFilter<myImage,myImage> FilterType;

  FilterType::Pointer filter = FilterType::New();
  FilterWatcher watcher(filter);

  filter->SetInput(input->GetOutput());
  FilterType::IndexType seed; seed[0] = atoi(av[3]); seed[1] = atoi(av[4]);
  filter->AddSeed(seed);
  filter->SetLower(atoi(av[5]));
  filter->SetUpper(atoi(av[6]));
  filter->SetReplaceValue(255);

  // Test the use of full (8 connectivity in 2D) on this image.
  if (ac > 7)
    {
    filter->SetConnectivity( atoi(av[7]) ?
        FilterType::FullConnectivity : FilterType::FaceConnectivity );
    }

  try
    {
    input->Update();
    filter->Update();
    }
  catch (itk::ExceptionObject& e)
    {
    std::cerr << "Exception detected: "  << e.GetDescription();
    return -1;
    }

  // Generate test image
  itk::ImageFileWriter<myImage>::Pointer writer;
  writer = itk::ImageFileWriter<myImage>::New();
  writer->SetInput( filter->GetOutput() );
  writer->SetFileName( av[2] );
  writer->Update();

  return EXIT_SUCCESS;
}
<commit_msg>ENH: Improve itkConnectedThresholdImageFilter coverage.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software 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 <fstream>
#include "itkConnectedThresholdImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkFilterWatcher.h"
#include "itkTestingMacros.h"

int itkConnectedThresholdImageFilterTest( int argc, char* argv[] )
{
  if( argc < 7 )
    {
    std::cerr << "Usage: " << argv[0]
      << " InputImage OutputImage "
      << "seed_x seed_y "
      << "LowerConnectedThreshold UpperConnectedThreshold "
      << "Connectivity[1=Full,0=Face]" << std::endl;
    return -1;
    }

  // Define the dimension of the images
  const unsigned int Dimension = 2;

  // Define the pixel types of the images
  typedef unsigned char                       PixelType;

  // Define the types of the images
  typedef itk::Image< PixelType, Dimension >  ImageType;

  itk::ImageFileReader< ImageType >::Pointer imageReader =
    itk::ImageFileReader< ImageType >::New();

  std::string inputImageFilename = argv[1];
  imageReader->SetFileName( inputImageFilename );

  TRY_EXPECT_NO_EXCEPTION( imageReader->Update(); );

  // Create the filter
  typedef itk::ConnectedThresholdImageFilter< ImageType, ImageType >
    ConnectedThresholdImageFilterType;

  ConnectedThresholdImageFilterType::Pointer connectedThresholdFilter =
    ConnectedThresholdImageFilterType::New();

  FilterWatcher watcher( connectedThresholdFilter );

  EXERCISE_BASIC_OBJECT_METHODS( connectedThresholdFilter,
    ConnectedThresholdImageFilter, ImageToImageFilter );

  ConnectedThresholdImageFilterType::IndexType seed;
  seed[0] = atoi( argv[3] );
  seed[1] = atoi( argv[4] );

  connectedThresholdFilter->AddSeed( seed );
  ConnectedThresholdImageFilterType::SeedContainerType seedContainer =
    connectedThresholdFilter->GetSeeds();

  connectedThresholdFilter->ClearSeeds();
  seedContainer = connectedThresholdFilter->GetSeeds();
  if( seedContainer.size() != 0 )
    {
    std::cerr << "Test FAILED !" << std::endl;
    std::cerr << "Seed container not empty after clearing filter seed container !" << std::endl;
    return EXIT_FAILURE;
    }

  connectedThresholdFilter->SetSeed( seed );

  ConnectedThresholdImageFilterType::InputPixelObjectType * lowerInputPixelObject =
    connectedThresholdFilter->GetLowerInput();
  connectedThresholdFilter->SetLower( lowerInputPixelObject->Get() );
  TEST_SET_GET_VALUE( lowerInputPixelObject->Get(), connectedThresholdFilter->GetLower() );

  ConnectedThresholdImageFilterType::InputPixelObjectType * upperInputPixelObject =
    connectedThresholdFilter->GetUpperInput();
  connectedThresholdFilter->SetUpper( upperInputPixelObject->Get() );
  TEST_SET_GET_VALUE( upperInputPixelObject->Get(), connectedThresholdFilter->GetUpper() );

  ConnectedThresholdImageFilterType::InputImagePixelType lowerThreshold = atoi( argv[5] );
  connectedThresholdFilter->SetLower( lowerThreshold );
  TEST_SET_GET_VALUE( lowerThreshold, connectedThresholdFilter->GetLower() );

  ConnectedThresholdImageFilterType::InputImagePixelType upperThreshold = atoi( argv[6] );
  connectedThresholdFilter->SetUpper( upperThreshold );
  TEST_SET_GET_VALUE( upperThreshold, connectedThresholdFilter->GetUpper() );

  ConnectedThresholdImageFilterType::OutputImagePixelType replaceValue = 255;
  connectedThresholdFilter->SetReplaceValue( replaceValue );
  TEST_SET_GET_VALUE( replaceValue, connectedThresholdFilter->GetReplaceValue() );

  // Test the use of full (8 connectivity in 2D) on this image
  if( argc > 7 )
    {
    ConnectedThresholdImageFilterType::ConnectivityEnumType conenctivity = atoi( argv[7] ) ?
      ConnectedThresholdImageFilterType::FullConnectivity : ConnectedThresholdImageFilterType::FaceConnectivity;
    connectedThresholdFilter->SetConnectivity( conenctivity );
    TEST_SET_GET_VALUE( conenctivity, connectedThresholdFilter->GetConnectivity() );
    }

  connectedThresholdFilter->SetInput( imageReader->GetOutput() );

  TRY_EXPECT_NO_EXCEPTION( connectedThresholdFilter->Update(); );

  // Write the output image
  itk::ImageFileWriter< ImageType >::Pointer writer =
    itk::ImageFileWriter< ImageType >::New();

  std::string ouputImageFilename = argv[2];
  writer->SetFileName( ouputImageFilename );

  writer->SetInput( connectedThresholdFilter->GetOutput() );

  TRY_EXPECT_NO_EXCEPTION( writer->Update() );

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * File:   multi_unbounded_queue.hpp
 * Author: Barath Kannan
 * Vector of unbounded queues. Enqueue operations are assigned a subqueue,
 * which is used for all enqueue operations occuring from that thread. The dequeue
 * operation maintains a list of subqueues on which a "hit" has occured - pertaining
 * to the subqueues from which a successful dequeue operation has occured. On a
 * successful dequeue operation, the queue that is used is pushed to the front of the
 * list. The "hit lists" allow the queue to adapt fairly well to different usage contexts.
 * Created on 25 September 2016, 12:04 AM
 */

#ifndef BK_CONQ_MULTI_UNBOUNDED_QUEUE_HPP
#define BK_CONQ_MULTI_UNBOUNDED_QUEUE_HPP

#include <thread>
#include <vector>
#include <mutex>
#include <bk_conq/unbounded_queue.hpp>

namespace bk_conq {

template<typename TT>
class multi_unbounded_queue;

template <template <typename> class Q, typename T>
class multi_unbounded_queue<Q<T>> : public unbounded_queue<T, multi_unbounded_queue<Q<T>>>{
	friend unbounded_queue<T, multi_unbounded_queue<Q<T>>>;
public:
	multi_unbounded_queue(size_t subqueues) :
		_q(subqueues),
		_hitlist([&]() {return hitlist_sequence(); }),
		_enqueue_identifier([&]() { return get_enqueue_index(); }, [&](size_t indx) {return return_enqueue_index(indx); })
	{
		static_assert(std::is_base_of<bk_conq::unbounded_queue_typed_tag<T>, Q<T>>::value, "Q<T> must be an unbounded queue");
	}

	multi_unbounded_queue(const multi_unbounded_queue&) = delete;
	void operator=(const multi_unbounded_queue&) = delete;

protected:
	template <typename R>
	void sp_enqueue_impl(R&& input) {
		size_t indx = _enqueue_identifier.get_tlcl();
		_q[indx].sp_enqueue(std::forward<R>(input));
	}

	template <typename R>
	void mp_enqueue_impl(R&& input) {
		size_t indx = _enqueue_identifier.get_tlcl();
		_q[indx].mp_enqueue(std::forward<R>(input));
	}

	bool sc_dequeue_impl(T& output) {
		auto& hitlist = _hitlist.get_tlcl();
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].sc_dequeue(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		return false;
	}

	bool mc_dequeue_impl(T& output) {
		auto& hitlist = _hitlist.get_tlcl();
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].mc_dequeue_uncontended(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].mc_dequeue(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		return false;
	}

	bool mc_dequeue_uncontended_impl(T& output) {
		auto& hitlist = _hitlist.get_tlcl();
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].mc_dequeue_uncontended(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		return false;
	}

private:

	template <typename U>
	class tlcl {
	public:
		tlcl(std::function<U()> defaultvalfunc = nullptr, std::function<void(U)> defaultdeletefunc = nullptr) :
			_defaultvalfunc(defaultvalfunc),
			_defaultdeletefunc(defaultdeletefunc)
		{
			std::lock_guard<std::mutex> lock(_m);
			if (!_available.empty()) {
				_mycounter = _available.back();
				_available.pop_back();
			}
			else {
				_mycounter = _counter++;
			}
		}

		virtual ~tlcl() {
			std::lock_guard<std::mutex> lock(_m);
			_available.push_back(_mycounter);
		}

		U& get_tlcl() {
			thread_local std::vector<std::pair<tlcl<U>*, U>> vec;
			if (vec.size() <= _mycounter) vec.resize(_mycounter+1);
			auto& ret = vec[_mycounter];
			if (ret.first != this) { //reset to default
				if (_defaultdeletefunc && ret.first != nullptr) _defaultdeletefunc(ret.second);
				if (_defaultvalfunc) ret.second = _defaultvalfunc();
				ret.first = this;
			}
			return ret.second;
		}

	private:
		std::function<U()> _defaultvalfunc;
		std::function<void(U)> _defaultdeletefunc;
		size_t _mycounter;
		static size_t _counter;
		static std::vector<size_t> _available;
		static std::mutex _m;
	};

	std::vector<size_t> hitlist_sequence() {
		std::vector<size_t> hitlist(_q.size());
		std::iota(hitlist.begin(), hitlist.end(), 0);
		return hitlist;
	}

	size_t get_enqueue_index() {
		std::lock_guard<std::mutex> lock(_m);
		if (_unused_enqueue_indexes.empty()) {
			return _enqueue_index++;
		}
		size_t ret = _unused_enqueue_indexes.back();
		_unused_enqueue_indexes.pop_back();
		return ret;
	}

	void return_enqueue_index(size_t index) {
		std::lock_guard<std::mutex> lock(_m);
		_unused_enqueue_indexes.push_back(index);
	}

	class padded_unbounded_queue : public Q<T>{
		char padding[64];
	};

	std::vector<padded_unbounded_queue> _q;

	std::vector<size_t> _unused_enqueue_indexes;
	size_t				_enqueue_index{ 0 };
	std::mutex			_m;

	tlcl<std::vector<size_t>> _hitlist;
	tlcl<size_t> _enqueue_identifier;
};

template <template <typename> class Q, typename T> template <typename U>
size_t multi_unbounded_queue<Q<T>>::tlcl<U>::_counter = 0;

template <template <typename> class Q, typename T> template <typename U>
std::vector<size_t> multi_unbounded_queue<Q<T>>::tlcl<U>::_available;

template <template <typename> class Q, typename T> template <typename U>
std::mutex multi_unbounded_queue<Q<T>>::tlcl<U>::_m;

}//namespace bk_conq

#endif /* BK_CONQ_MULTI_UNBOUNDED_QUEUE_HPP */
<commit_msg>forgot to add modulo operation when acquiring an enqueue index<commit_after>/*
 * File:   multi_unbounded_queue.hpp
 * Author: Barath Kannan
 * Vector of unbounded queues. Enqueue operations are assigned a subqueue,
 * which is used for all enqueue operations occuring from that thread. The dequeue
 * operation maintains a list of subqueues on which a "hit" has occured - pertaining
 * to the subqueues from which a successful dequeue operation has occured. On a
 * successful dequeue operation, the queue that is used is pushed to the front of the
 * list. The "hit lists" allow the queue to adapt fairly well to different usage contexts.
 * Created on 25 September 2016, 12:04 AM
 */

#ifndef BK_CONQ_MULTI_UNBOUNDED_QUEUE_HPP
#define BK_CONQ_MULTI_UNBOUNDED_QUEUE_HPP

#include <thread>
#include <vector>
#include <mutex>
#include <bk_conq/unbounded_queue.hpp>

namespace bk_conq {

template<typename TT>
class multi_unbounded_queue;

template <template <typename> class Q, typename T>
class multi_unbounded_queue<Q<T>> : public unbounded_queue<T, multi_unbounded_queue<Q<T>>>{
	friend unbounded_queue<T, multi_unbounded_queue<Q<T>>>;
public:
	multi_unbounded_queue(size_t subqueues) :
		_q(subqueues),
		_hitlist([&]() {return hitlist_sequence(); }),
		_enqueue_identifier([&]() { return get_enqueue_index(); }, [&](size_t indx) {return return_enqueue_index(indx); })
	{
		static_assert(std::is_base_of<bk_conq::unbounded_queue_typed_tag<T>, Q<T>>::value, "Q<T> must be an unbounded queue");
	}

	multi_unbounded_queue(const multi_unbounded_queue&) = delete;
	void operator=(const multi_unbounded_queue&) = delete;

protected:
	template <typename R>
	void sp_enqueue_impl(R&& input) {
		size_t indx = _enqueue_identifier.get_tlcl();
		_q[indx].sp_enqueue(std::forward<R>(input));
	}

	template <typename R>
	void mp_enqueue_impl(R&& input) {
		size_t indx = _enqueue_identifier.get_tlcl();
		_q[indx].mp_enqueue(std::forward<R>(input));
	}

	bool sc_dequeue_impl(T& output) {
		auto& hitlist = _hitlist.get_tlcl();
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].sc_dequeue(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		return false;
	}

	bool mc_dequeue_impl(T& output) {
		auto& hitlist = _hitlist.get_tlcl();
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].mc_dequeue_uncontended(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].mc_dequeue(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		return false;
	}

	bool mc_dequeue_uncontended_impl(T& output) {
		auto& hitlist = _hitlist.get_tlcl();
		for (auto it = hitlist.begin(); it != hitlist.end(); ++it) {
			if (_q[*it].mc_dequeue_uncontended(output)) {
				for (auto it2 = hitlist.begin(); it2 != it; ++it2) std::iter_swap(it, it2);
				return true;
			}
		}
		return false;
	}

private:

	template <typename U>
	class tlcl {
	public:
		tlcl(std::function<U()> defaultvalfunc = nullptr, std::function<void(U)> defaultdeletefunc = nullptr) :
			_defaultvalfunc(defaultvalfunc),
			_defaultdeletefunc(defaultdeletefunc)
		{
			std::lock_guard<std::mutex> lock(_m);
			if (!_available.empty()) {
				_mycounter = _available.back();
				_available.pop_back();
			}
			else {
				_mycounter = _counter++;
			}
		}

		virtual ~tlcl() {
			std::lock_guard<std::mutex> lock(_m);
			_available.push_back(_mycounter);
		}

		U& get_tlcl() {
			thread_local std::vector<std::pair<tlcl<U>*, U>> vec;
			if (vec.size() <= _mycounter) vec.resize(_mycounter+1);
			auto& ret = vec[_mycounter];
			if (ret.first != this) { //reset to default
				if (_defaultdeletefunc && ret.first != nullptr) _defaultdeletefunc(ret.second);
				if (_defaultvalfunc) ret.second = _defaultvalfunc();
				ret.first = this;
			}
			return ret.second;
		}

	private:
		std::function<U()> _defaultvalfunc;
		std::function<void(U)> _defaultdeletefunc;
		size_t _mycounter;
		static size_t _counter;
		static std::vector<size_t> _available;
		static std::mutex _m;
	};

	std::vector<size_t> hitlist_sequence() {
		std::vector<size_t> hitlist(_q.size());
		std::iota(hitlist.begin(), hitlist.end(), 0);
		return hitlist;
	}

	size_t get_enqueue_index() {
		std::lock_guard<std::mutex> lock(_m);
		if (_unused_enqueue_indexes.empty()) {
			return (_enqueue_index++)%_q.size();
		}
		size_t ret = _unused_enqueue_indexes.back();
		_unused_enqueue_indexes.pop_back();
		return ret;
	}

	void return_enqueue_index(size_t index) {
		std::lock_guard<std::mutex> lock(_m);
		_unused_enqueue_indexes.push_back(index);
	}

	class padded_unbounded_queue : public Q<T>{
		char padding[64];
	};

	std::vector<padded_unbounded_queue> _q;

	std::vector<size_t> _unused_enqueue_indexes;
	size_t				_enqueue_index{ 0 };
	std::mutex			_m;

	tlcl<std::vector<size_t>> _hitlist;
	tlcl<size_t> _enqueue_identifier;
};

template <template <typename> class Q, typename T> template <typename U>
size_t multi_unbounded_queue<Q<T>>::tlcl<U>::_counter = 0;

template <template <typename> class Q, typename T> template <typename U>
std::vector<size_t> multi_unbounded_queue<Q<T>>::tlcl<U>::_available;

template <template <typename> class Q, typename T> template <typename U>
std::mutex multi_unbounded_queue<Q<T>>::tlcl<U>::_m;

}//namespace bk_conq

#endif /* BK_CONQ_MULTI_UNBOUNDED_QUEUE_HPP */
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkStandaloneDataStorage.h"

#include "mitkDataNode.h"
#include "mitkProperties.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkGroupTagProperty.h"
#include "itkSimpleFastMutexLock.h"
#include "itkMutexLockHolder.h"

mitk::StandaloneDataStorage::StandaloneDataStorage()
: mitk::DataStorage()
{
}

mitk::StandaloneDataStorage::~StandaloneDataStorage()
{
  for(AdjacencyList::iterator it = m_SourceNodes.begin();
    it != m_SourceNodes.end(); it++)
  {
    this->RemoveListeners(it->first);
  }
}

bool mitk::StandaloneDataStorage::IsInitialized() const
{
  return true;
}

void mitk::StandaloneDataStorage::Add(mitk::DataNode* node, const mitk::DataStorage::SetOfObjects* parents)
{
  {
    itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
    if (!IsInitialized())
      throw std::logic_error("DataStorage not initialized");
    /* check if node is in its own list of sources */
    if ((parents != NULL) && (std::find(parents->begin(), parents->end(), node) != parents->end()))
      throw std::invalid_argument("Node is it's own parent");
    /* check if node already exists in StandaloneDataStorage */
    if (m_SourceNodes.find(node) != m_SourceNodes.end())
      throw std::invalid_argument("Node is already in DataStorage");

    /* create parent list if it does not exist */
    mitk::DataStorage::SetOfObjects::ConstPointer sp;
    if (parents != NULL)
      sp = parents;
    else
      sp = mitk::DataStorage::SetOfObjects::New();
    /* Store node and parent list in sources adjacency list */
    m_SourceNodes.insert(std::make_pair(node, sp));

    /* Store node and an empty children list in derivations adjacency list */
    mitk::DataStorage::SetOfObjects::Pointer childrenPointer = mitk::DataStorage::SetOfObjects::New();
    mitk::DataStorage::SetOfObjects::ConstPointer children = children.GetPointer();
    m_DerivedNodes.insert(std::make_pair(node, children));

    /* create entry in derivations adjacency list for each parent of the new node */
    for (SetOfObjects::ConstIterator it = sp->Begin(); it != sp->End(); it++)
    {
      mitk::DataNode::ConstPointer parent = it.Value().GetPointer();
      mitk::DataStorage::SetOfObjects::ConstPointer derivedObjects = m_DerivedNodes[parent]; // get or create pointer to list of derived objects for that parent node
      if (derivedObjects.IsNull())
        m_DerivedNodes[parent] = mitk::DataStorage::SetOfObjects::New();  // Create a set of Objects, if it does not already exist
      mitk::DataStorage::SetOfObjects* deob = const_cast<mitk::DataStorage::SetOfObjects*>(m_DerivedNodes[parent].GetPointer());  // temporarily get rid of const pointer to insert new element
      deob->InsertElement(deob->Size(), node); // node is derived from parent. Insert it into the parents list of derived objects
    }

    // register for ITK changed events
    this->AddListeners(node);
  }

  /* Notify observers */
  EmitAddNodeEvent(node);

}

void mitk::StandaloneDataStorage::Remove(const mitk::DataNode* node)
{
  if (!IsInitialized())
    throw std::logic_error("DataStorage not initialized");
  if (node == NULL)
    return;

  // remove ITK modified event listener
  this->RemoveListeners(node);

  // muellerm, 22.9.10: add additional reference count to ensure
  // that the node is not deleted when removed from the relation map
  // while m_Mutex is locked. This would cause the an itk::DeleteEvent
  // is thrown and a deadlock will occur when event receivers
  // access the DataStorage again in their event processing function
  //
  mitk::DataNode::ConstPointer nodeGuard(node);

  /* Notify observers of imminent node removal */
  EmitRemoveNodeEvent(node);
  {
    itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
    /* remove node from both relation adjacency lists */
    this->RemoveFromRelation(node, m_SourceNodes);
    this->RemoveFromRelation(node, m_DerivedNodes);
  }
}

bool mitk::StandaloneDataStorage::Exists(const mitk::DataNode* node) const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
  return (m_SourceNodes.find(node) != m_SourceNodes.end());
}

void mitk::StandaloneDataStorage::RemoveFromRelation(const mitk::DataNode* node, AdjacencyList& relation)
{
  for (AdjacencyList::const_iterator mapIter = relation.begin(); mapIter != relation.end(); ++mapIter)  // for each node in the relation
    if (mapIter->second.IsNotNull())      // if node has a relation list
    {
      SetOfObjects::Pointer s = const_cast<SetOfObjects*>(mapIter->second.GetPointer());   // search for node to be deleted in the relation list
      SetOfObjects::STLContainerType::iterator relationListIter = std::find(s->begin(),  s->end(), node);   // this assumes, that the relation list does not contain duplicates (which should be safe to assume)
      if (relationListIter != s->end())     // if node to be deleted is in relation list
        s->erase(relationListIter);         // remove it from parentlist
    }
  /* now remove node from the relation */
  AdjacencyList::iterator adIt;
  adIt = relation.find(node);
  if (adIt != relation.end())
    relation.erase(adIt);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetAll() const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock > locked(m_Mutex);
  if (!IsInitialized())
    throw std::logic_error("DataStorage not initialized");

  mitk::DataStorage::SetOfObjects::Pointer resultset = mitk::DataStorage::SetOfObjects::New();
  /* Fill resultset with all objects that are managed by the StandaloneDataStorage object */
  unsigned int index = 0;
  for (AdjacencyList::const_iterator it = m_SourceNodes.begin(); it != m_SourceNodes.end(); ++it)
    if (it->first.IsNull())
      continue;
    else
      resultset->InsertElement(index++, const_cast<mitk::DataNode*>(it->first.GetPointer()));

  return SetOfObjects::ConstPointer(resultset);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetRelations(const mitk::DataNode* node, const AdjacencyList& relation, const NodePredicateBase* condition, bool onlyDirectlyRelated) const
{
  if (node == NULL)
    throw std::invalid_argument("invalid node");

  /* Either read direct relations directly from adjacency list */
  if (onlyDirectlyRelated)
  {
    AdjacencyList::const_iterator it = relation.find(node); // get parents of current node
    if ((it == relation.end()) || (it->second.IsNull())) // node not found in list or no set of parents
      return SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return an empty set
    else
      return this->FilterSetOfObjects(it->second, condition);
  }

  /* Or traverse adjacency list to collect all related nodes */
  std::vector<mitk::DataNode::ConstPointer> resultset;
  std::vector<mitk::DataNode::ConstPointer> openlist;

  /* Initialize openlist with node. this will add node to resultset,
     but that is necessary to detect circular relations that would lead to endless recursion */
  openlist.push_back(node);

  while (openlist.size() > 0)
  {
    mitk::DataNode::ConstPointer current = openlist.back();  // get element that needs to be processed
    openlist.pop_back();                      // remove last element, because it gets processed now
    resultset.push_back(current);             // add current element to resultset
    AdjacencyList::const_iterator it = relation.find(current); // get parents of current node
    if (   (it == relation.end())             // if node not found in list
        || (it->second.IsNull())              // or no set of parents available
        || (it->second->Size() == 0))         // or empty set of parents
      continue;                               // then continue with next node in open list
    else
      for (SetOfObjects::ConstIterator parentIt = it->second->Begin(); parentIt != it->second->End(); ++parentIt) // for each parent of current node
      {
        mitk::DataNode::ConstPointer p = parentIt.Value().GetPointer();
        if (   !(std::find(resultset.begin(), resultset.end(), p) != resultset.end())   // if it is not already in resultset
            && !(std::find(openlist.begin(), openlist.end(), p) != openlist.end()))     // and not already in openlist
          openlist.push_back(p);                                                        // then add it to openlist, so that it can be processed
      }
  }

  /* now finally copy the results to a proper SetOfObjects variable exluding the initial node and checking the condition if any is given */
  mitk::DataStorage::SetOfObjects::Pointer realResultset = mitk::DataStorage::SetOfObjects::New();
  if (condition != NULL)
  {
    for (std::vector<mitk::DataNode::ConstPointer>::iterator resultIt = resultset.begin(); resultIt != resultset.end(); resultIt++)
      if ((*resultIt != node) && (condition->CheckNode(*resultIt) == true))
        realResultset->InsertElement(realResultset->Size(), mitk::DataNode::Pointer(const_cast<mitk::DataNode*>((*resultIt).GetPointer())));
  }
  else
  {
    for (std::vector<mitk::DataNode::ConstPointer>::iterator resultIt = resultset.begin(); resultIt != resultset.end(); resultIt++)
      if (*resultIt != node)
        realResultset->InsertElement(realResultset->Size(), mitk::DataNode::Pointer(const_cast<mitk::DataNode*>((*resultIt).GetPointer())));
  }
  return SetOfObjects::ConstPointer(realResultset);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetSources(const mitk::DataNode* node, const NodePredicateBase* condition, bool onlyDirectSources) const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
  return this->GetRelations(node, m_SourceNodes, condition, onlyDirectSources);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetDerivations(const mitk::DataNode* node, const NodePredicateBase* condition, bool onlyDirectDerivations) const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock>locked(m_Mutex);
  return this->GetRelations(node, m_DerivedNodes, condition, onlyDirectDerivations);
}

void mitk::StandaloneDataStorage::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  os << indent << "StandaloneDataStorage:\n";
  Superclass::PrintSelf(os, indent);
}
<commit_msg>Workaround for small bug<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkStandaloneDataStorage.h"

#include "mitkDataNode.h"
#include "mitkProperties.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkGroupTagProperty.h"
#include "itkSimpleFastMutexLock.h"
#include "itkMutexLockHolder.h"

mitk::StandaloneDataStorage::StandaloneDataStorage()
: mitk::DataStorage()
{
}

mitk::StandaloneDataStorage::~StandaloneDataStorage()
{
  for(AdjacencyList::iterator it = m_SourceNodes.begin();
    it != m_SourceNodes.end(); it++)
  {
    this->RemoveListeners(it->first);
  }
}

bool mitk::StandaloneDataStorage::IsInitialized() const
{
  return true;
}

void mitk::StandaloneDataStorage::Add(mitk::DataNode* node, const mitk::DataStorage::SetOfObjects* parents)
{
  {
    itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
    if (!IsInitialized())
      throw std::logic_error("DataStorage not initialized");
    /* check if node is in its own list of sources */
    if ((parents != NULL) && (std::find(parents->begin(), parents->end(), node) != parents->end()))
      throw std::invalid_argument("Node is it's own parent");
    /* check if node already exists in StandaloneDataStorage */
    if (m_SourceNodes.find(node) != m_SourceNodes.end())
      throw std::invalid_argument("Node is already in DataStorage");

    /* create parent list if it does not exist */
    mitk::DataStorage::SetOfObjects::ConstPointer sp;
    if (parents != NULL)
      sp = parents;
    else
      sp = mitk::DataStorage::SetOfObjects::New();
    /* Store node and parent list in sources adjacency list */
    m_SourceNodes.insert(std::make_pair(node, sp));

    /* Store node and an empty children list in derivations adjacency list */
    mitk::DataStorage::SetOfObjects::Pointer childrenPointer = mitk::DataStorage::SetOfObjects::New();
    mitk::DataStorage::SetOfObjects::ConstPointer children =  childrenPointer.GetPointer();
    m_DerivedNodes.insert(std::make_pair(node, children));

    /* create entry in derivations adjacency list for each parent of the new node */
    for (SetOfObjects::ConstIterator it = sp->Begin(); it != sp->End(); it++)
    {
      mitk::DataNode::ConstPointer parent = it.Value().GetPointer();
      mitk::DataStorage::SetOfObjects::ConstPointer derivedObjects = m_DerivedNodes[parent]; // get or create pointer to list of derived objects for that parent node
      if (derivedObjects.IsNull())
        m_DerivedNodes[parent] = mitk::DataStorage::SetOfObjects::New();  // Create a set of Objects, if it does not already exist
      mitk::DataStorage::SetOfObjects* deob = const_cast<mitk::DataStorage::SetOfObjects*>(m_DerivedNodes[parent].GetPointer());  // temporarily get rid of const pointer to insert new element
      deob->InsertElement(deob->Size(), node); // node is derived from parent. Insert it into the parents list of derived objects
    }

    // register for ITK changed events
    this->AddListeners(node);
  }

  /* Notify observers */
  EmitAddNodeEvent(node);

}

void mitk::StandaloneDataStorage::Remove(const mitk::DataNode* node)
{
  if (!IsInitialized())
    throw std::logic_error("DataStorage not initialized");
  if (node == NULL)
    return;

  // remove ITK modified event listener
  this->RemoveListeners(node);

  // muellerm, 22.9.10: add additional reference count to ensure
  // that the node is not deleted when removed from the relation map
  // while m_Mutex is locked. This would cause the an itk::DeleteEvent
  // is thrown and a deadlock will occur when event receivers
  // access the DataStorage again in their event processing function
  //
  mitk::DataNode::ConstPointer nodeGuard(node);

  /* Notify observers of imminent node removal */
  EmitRemoveNodeEvent(node);
  {
    itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
    /* remove node from both relation adjacency lists */
    this->RemoveFromRelation(node, m_SourceNodes);
    this->RemoveFromRelation(node, m_DerivedNodes);
  }
}

bool mitk::StandaloneDataStorage::Exists(const mitk::DataNode* node) const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
  return (m_SourceNodes.find(node) != m_SourceNodes.end());
}

void mitk::StandaloneDataStorage::RemoveFromRelation(const mitk::DataNode* node, AdjacencyList& relation)
{
  for (AdjacencyList::const_iterator mapIter = relation.begin(); mapIter != relation.end(); ++mapIter)  // for each node in the relation
    if (mapIter->second.IsNotNull())      // if node has a relation list
    {
      SetOfObjects::Pointer s = const_cast<SetOfObjects*>(mapIter->second.GetPointer());   // search for node to be deleted in the relation list
      SetOfObjects::STLContainerType::iterator relationListIter = std::find(s->begin(),  s->end(), node);   // this assumes, that the relation list does not contain duplicates (which should be safe to assume)
      if (relationListIter != s->end())     // if node to be deleted is in relation list
        s->erase(relationListIter);         // remove it from parentlist
    }
  /* now remove node from the relation */
  AdjacencyList::iterator adIt;
  adIt = relation.find(node);
  if (adIt != relation.end())
    relation.erase(adIt);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetAll() const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock > locked(m_Mutex);
  if (!IsInitialized())
    throw std::logic_error("DataStorage not initialized");

  mitk::DataStorage::SetOfObjects::Pointer resultset = mitk::DataStorage::SetOfObjects::New();
  /* Fill resultset with all objects that are managed by the StandaloneDataStorage object */
  unsigned int index = 0;
  for (AdjacencyList::const_iterator it = m_SourceNodes.begin(); it != m_SourceNodes.end(); ++it)
    if (it->first.IsNull())
      continue;
    else
      resultset->InsertElement(index++, const_cast<mitk::DataNode*>(it->first.GetPointer()));

  return SetOfObjects::ConstPointer(resultset);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetRelations(const mitk::DataNode* node, const AdjacencyList& relation, const NodePredicateBase* condition, bool onlyDirectlyRelated) const
{
  if (node == NULL)
    throw std::invalid_argument("invalid node");

  /* Either read direct relations directly from adjacency list */
  if (onlyDirectlyRelated)
  {
    AdjacencyList::const_iterator it = relation.find(node); // get parents of current node
    if ((it == relation.end()) || (it->second.IsNull())) // node not found in list or no set of parents
      return SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return an empty set
    else
      return this->FilterSetOfObjects(it->second, condition);
  }

  /* Or traverse adjacency list to collect all related nodes */
  std::vector<mitk::DataNode::ConstPointer> resultset;
  std::vector<mitk::DataNode::ConstPointer> openlist;

  /* Initialize openlist with node. this will add node to resultset,
     but that is necessary to detect circular relations that would lead to endless recursion */
  openlist.push_back(node);

  while (openlist.size() > 0)
  {
    mitk::DataNode::ConstPointer current = openlist.back();  // get element that needs to be processed
    openlist.pop_back();                      // remove last element, because it gets processed now
    resultset.push_back(current);             // add current element to resultset
    AdjacencyList::const_iterator it = relation.find(current); // get parents of current node
    if (   (it == relation.end())             // if node not found in list
        || (it->second.IsNull())              // or no set of parents available
        || (it->second->Size() == 0))         // or empty set of parents
      continue;                               // then continue with next node in open list
    else
      for (SetOfObjects::ConstIterator parentIt = it->second->Begin(); parentIt != it->second->End(); ++parentIt) // for each parent of current node
      {
        mitk::DataNode::ConstPointer p = parentIt.Value().GetPointer();
        if (   !(std::find(resultset.begin(), resultset.end(), p) != resultset.end())   // if it is not already in resultset
            && !(std::find(openlist.begin(), openlist.end(), p) != openlist.end()))     // and not already in openlist
          openlist.push_back(p);                                                        // then add it to openlist, so that it can be processed
      }
  }

  /* now finally copy the results to a proper SetOfObjects variable exluding the initial node and checking the condition if any is given */
  mitk::DataStorage::SetOfObjects::Pointer realResultset = mitk::DataStorage::SetOfObjects::New();
  if (condition != NULL)
  {
    for (std::vector<mitk::DataNode::ConstPointer>::iterator resultIt = resultset.begin(); resultIt != resultset.end(); resultIt++)
      if ((*resultIt != node) && (condition->CheckNode(*resultIt) == true))
        realResultset->InsertElement(realResultset->Size(), mitk::DataNode::Pointer(const_cast<mitk::DataNode*>((*resultIt).GetPointer())));
  }
  else
  {
    for (std::vector<mitk::DataNode::ConstPointer>::iterator resultIt = resultset.begin(); resultIt != resultset.end(); resultIt++)
      if (*resultIt != node)
        realResultset->InsertElement(realResultset->Size(), mitk::DataNode::Pointer(const_cast<mitk::DataNode*>((*resultIt).GetPointer())));
  }
  return SetOfObjects::ConstPointer(realResultset);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetSources(const mitk::DataNode* node, const NodePredicateBase* condition, bool onlyDirectSources) const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock> locked(m_Mutex);
  return this->GetRelations(node, m_SourceNodes, condition, onlyDirectSources);
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::StandaloneDataStorage::GetDerivations(const mitk::DataNode* node, const NodePredicateBase* condition, bool onlyDirectDerivations) const
{
  itk::MutexLockHolder<itk::SimpleFastMutexLock>locked(m_Mutex);
  return this->GetRelations(node, m_DerivedNodes, condition, onlyDirectDerivations);
}

void mitk::StandaloneDataStorage::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  os << indent << "StandaloneDataStorage:\n";
  Superclass::PrintSelf(os, indent);
}
<|endoftext|>