<commit_before>/** \file    SslConnection.h
 *  \brief   Implementation class SslConnection.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  \copyright 2006-2008 Project iVia.
 *  \copyright 2006-2008 The Regents of The University of California.
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  libiViaCore 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 libiViaCore; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "SslConnection.h"
#include <algorithm>
#include <memory>
#include <stdexcept>
#include "Compiler.h"
#include "DynamicLoader.h"
#include "TimeUtil.h"

std::mutex SslConnection::mutex_;
bool SslConnection::ssl_libraries_have_been_initialised_;
std::list<SslConnection::ContextInfo> SslConnection::context_infos_;

SslConnection::SslConnection(const int fd, const Method method, const ClientServerMode client_server_mode,
                             const ThreadingSupportMode threading_support_mode)
        : threading_support_mode_(threading_support_mode), ssl_connection_(nullptr), last_ret_val_(0)
{
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

    ssl_context_ = SslConnection::InitContext(method, client_server_mode);

    ssl_connection_ = ::SSL_new(ssl_context_);
    if (unlikely(ssl_connection_ == nullptr))
        throw std::runtime_error("in SslConnection::SslConnection: ::SSL_new() failed!");

    if (unlikely(not ::SSL_set_fd(ssl_connection_, fd)))
        throw std::runtime_error("in SslConnection::SslConnection: ::SSL_set_fd() failed!");

    const unsigned NO_OF_TRIES(10);
    for (unsigned try_no(0); try_no < NO_OF_TRIES; ++try_no) {
        const int ret_val(::SSL_connect(ssl_connection_));
        if (unlikely(ret_val == 0))
            throw std::runtime_error("in SslConnection::SslConnection: ::SSL_connect() failed with return "
                                     "value (0)!");
        if (ret_val == 1) // We succeeded.
            return;

        TimeUtil::Millisleep(300);
    }

    throw std::runtime_error("in SslConnection::SslConnection: ::SSL_connect() failed after "
                             + std::to_string(NO_OF_TRIES) + " tries!");
}

SslConnection::~SslConnection() {
    // Several of the functions called here throw exceptions which could cause an unexpected exception if called while
    // an exception is already in progress, destroying this object. So, don't clean up if this is the case.
    if (not std::uncaught_exception()) {
        std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
        if (threading_support_mode_ == SUPPORT_MULTITHREADING)
            mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

        if (ssl_connection_ != nullptr)
            ::SSL_free(ssl_connection_);
        SslConnection::ReleaseContext(ssl_context_);
    }
}

ssize_t SslConnection::read(void * const data, size_t data_size) {
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode_ == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

        return last_ret_val_ = ::SSL_read(ssl_connection_, data, data_size);
}

ssize_t SslConnection::write(const void * const data, size_t data_size) {
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode_ == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

    return last_ret_val_ = ::SSL_write(ssl_connection_, data, data_size);
}

int SslConnection::getLastErrorCode() const {
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode_ == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

    return ::SSL_get_error(ssl_connection_, last_ret_val_);
}

namespace {

class ContextInfoMatch {
    const SslConnection::Method method_;
    const SslConnection::ClientServerMode client_server_mode_;
public:
    explicit ContextInfoMatch(const SslConnection::Method method,
                              const SslConnection::ClientServerMode client_server_mode)
        : method_(method), client_server_mode_(client_server_mode) { }
    bool operator()(const SslConnection::ContextInfo &rhs) const;
};

bool ContextInfoMatch::operator()(const SslConnection::ContextInfo &rhs) const {
    if (rhs.method_ != method_)
        return false;
    if (rhs.client_server_mode_ != client_server_mode_)
        return false;
    return true;
}

} // unnamed namespace

SSL_CTX *SslConnection::InitContext(const Method method, const ClientServerMode client_server_mode) {
    if (not ssl_libraries_have_been_initialised_) {
        ::SSL_load_error_strings();
        ::SSL_library_init();
        // We don't call ::RAND_add() because we assume the existence of /dev/urandom!

        ssl_libraries_have_been_initialised_ = true;
    }

    // First check to see if we already have a context with the correct options:
    std::list<ContextInfo>::iterator matching_context_info(std::find_if(context_infos_.begin(), context_infos_.end(),
                                                                        ContextInfoMatch(method,
                                                                                client_server_mode)));
    if (matching_context_info != context_infos_.end()) {
        ++matching_context_info->usage_count_;
        return matching_context_info->ssl_context_;
    }

    // If we make it here we need to create a new ContextInfo:
    ContextInfo new_context_info(method, client_server_mode);
    switch (client_server_mode) {
    case CLIENT:
        new_context_info.ssl_context_ = SslConnection::InitClient(method);
        break;
    case SERVER:
        new_context_info.ssl_context_ = SslConnection::InitServer(method);
        break;
    case CLIENT_AND_SERVER:
        new_context_info.ssl_context_ = SslConnection::InitClientAndServer(method);
        break;
    default:
        throw std::runtime_error("in SslConnection::InitContext: unknown client/server mode!");
    }
    context_infos_.push_back(new_context_info);
    return new_context_info.ssl_context_;
}

namespace {

class ContextMatch {
    const SSL_CTX * const ssl_context_to_match_;
public:
    explicit ContextMatch(const SSL_CTX * const ssl_context_to_match): ssl_context_to_match_(ssl_context_to_match) { }
    bool operator()(const SslConnection::ContextInfo &rhs) const { return rhs.ssl_context_ == ssl_context_to_match_; }
};

} // unnamed namespace

void SslConnection::ReleaseContext(const SSL_CTX * const ssl_context) {
    std::list<ContextInfo>::iterator matching_context_info(
        std::find_if(context_infos_.begin(), context_infos_.end(), ContextMatch(ssl_context)));
    if (unlikely(matching_context_info == context_infos_.end()))
        throw std::runtime_error("in SslConnection::ReleaseContext: can't find context to release!");

    --matching_context_info->usage_count_;
    if (matching_context_info->usage_count_ == 0) {
        ::SSL_CTX_free(matching_context_info->ssl_context_);
        context_infos_.erase(matching_context_info);
    }
}

typedef SSL_METHOD *(*SslMethod)(void);

SSL_CTX *SslConnection::InitClient(const Method method) {
    static bool initialised(false);
    static SslMethod stream_client_method(nullptr);
    static SslMethod datagram_client_method(nullptr);
    if (not initialised) {
        initialised = true;
        DynamicLoader dynamic_loader("libssl.so");

        stream_client_method = (SslMethod)(dynamic_loader.loadSymbol("TLS_client_method"));
        if (stream_client_method == nullptr)
            stream_client_method = (SslMethod)dynamic_loader.loadSymbol("SSLv23_client_method");
        if (stream_client_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load TLS_client_method nor "
                                     "SSLv23_client_method from libssl.so!");

        datagram_client_method = (SslMethod)(dynamic_loader.loadSymbol("DTLS_client_method"));
        if (datagram_client_method == nullptr)
            datagram_client_method = (SslMethod)dynamic_loader.loadSymbol("DTLSv1_client_method");
        if (datagram_client_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load DTLS_client_method nor "
                                     "DTLSv1_client_method from libssl.so!");
    }

    return ::SSL_CTX_new(method == ALL_STREAM_METHODS ? stream_client_method() : DTLS_client_method());
}

SSL_CTX *SslConnection::InitServer(const Method method) {
    static bool initialised(false);
    static SslMethod stream_server_method(nullptr);
    static SslMethod datagram_server_method(nullptr);
    if (not initialised) {
        initialised = true;
        DynamicLoader dynamic_loader("libssl.so");

        stream_server_method = (SslMethod)(dynamic_loader.loadSymbol("TLS_server_method"));
        if (stream_server_method == nullptr)
            stream_server_method = (SslMethod)dynamic_loader.loadSymbol("SSLv23_server_method");
        if (stream_server_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load TLS_server_method nor "
                                     "SSLv23_server_method from libssl.so!");

        datagram_server_method = (SslMethod)(dynamic_loader.loadSymbol("DTLS_server_method"));
        if (datagram_server_method == nullptr)
            datagram_server_method = (SslMethod)dynamic_loader.loadSymbol("DTLSv1_server_method");
        if (datagram_server_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load DTLS_server_method nor "
                                     "DTLSv1_server_method from libssl.so!");
    }

    return ::SSL_CTX_new(method == ALL_STREAM_METHODS ? SSLv23_server_method() : DTLS_server_method());
}

SSL_CTX *SslConnection::InitClientAndServer(const Method method) {
    static bool initialised(false);
    static SslMethod stream_method(nullptr);
    static SslMethod datagram_method(nullptr);
    if (not initialised) {
        initialised = true;
        DynamicLoader dynamic_loader("libssl.so");

        stream_method = (SslMethod)(dynamic_loader.loadSymbol("TLS_method"));
        if (stream_method == nullptr)
            stream_method = (SslMethod)dynamic_loader.loadSymbol("SSLv23_method");
        if (stream_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load TLS_method nor "
                                     "SSLv23_method from libssl.so!");

        datagram_method = (SslMethod)(dynamic_loader.loadSymbol("DTLS_method"));
        if (datagram_method == nullptr)
            datagram_method = (SslMethod)dynamic_loader.loadSymbol("DTLSv1_method");
        if (datagram_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load DTLS_method nor "
                                     "DTLSv1_method from libssl.so!");
    }

    return ::SSL_CTX_new(method == ALL_STREAM_METHODS ? SSLv23_method() : DTLS_method());
}
<commit_msg>Fixed several bugs.<commit_after>/** \file    SslConnection.h
 *  \brief   Implementation class SslConnection.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  \copyright 2006-2008 Project iVia.
 *  \copyright 2006-2008 The Regents of The University of California.
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This file is part of the libiViaCore package.
 *
 *  The libiViaCore package 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  libiViaCore 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 libiViaCore; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "SslConnection.h"
#include <algorithm>
#include <memory>
#include <stdexcept>
#include "Compiler.h"
#include "DynamicLoader.h"
#include "TimeUtil.h"

std::mutex SslConnection::mutex_;
bool SslConnection::ssl_libraries_have_been_initialised_;
std::list<SslConnection::ContextInfo> SslConnection::context_infos_;

SslConnection::SslConnection(const int fd, const Method method, const ClientServerMode client_server_mode,
                             const ThreadingSupportMode threading_support_mode)
        : threading_support_mode_(threading_support_mode), ssl_connection_(nullptr), last_ret_val_(0)
{
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

    ssl_context_ = SslConnection::InitContext(method, client_server_mode);

    ssl_connection_ = ::SSL_new(ssl_context_);
    if (unlikely(ssl_connection_ == nullptr))
        throw std::runtime_error("in SslConnection::SslConnection: ::SSL_new() failed!");

    if (unlikely(not ::SSL_set_fd(ssl_connection_, fd)))
        throw std::runtime_error("in SslConnection::SslConnection: ::SSL_set_fd() failed!");

    const unsigned NO_OF_TRIES(10);
    for (unsigned try_no(0); try_no < NO_OF_TRIES; ++try_no) {
        const int ret_val(::SSL_connect(ssl_connection_));
        if (unlikely(ret_val == 0))
            throw std::runtime_error("in SslConnection::SslConnection: ::SSL_connect() failed with return "
                                     "value (0)!");
        if (ret_val == 1) // We succeeded.
            return;

        TimeUtil::Millisleep(300);
    }

    throw std::runtime_error("in SslConnection::SslConnection: ::SSL_connect() failed after "
                             + std::to_string(NO_OF_TRIES) + " tries!");
}

SslConnection::~SslConnection() {
    // Several of the functions called here throw exceptions which could cause an unexpected exception if called while
    // an exception is already in progress, destroying this object. So, don't clean up if this is the case.
    if (not std::uncaught_exception()) {
        std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
        if (threading_support_mode_ == SUPPORT_MULTITHREADING)
            mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

        if (ssl_connection_ != nullptr)
            ::SSL_free(ssl_connection_);
        SslConnection::ReleaseContext(ssl_context_);
    }
}

ssize_t SslConnection::read(void * const data, size_t data_size) {
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode_ == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

        return last_ret_val_ = ::SSL_read(ssl_connection_, data, data_size);
}

ssize_t SslConnection::write(const void * const data, size_t data_size) {
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode_ == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

    return last_ret_val_ = ::SSL_write(ssl_connection_, data, data_size);
}

int SslConnection::getLastErrorCode() const {
    std::unique_ptr<std::lock_guard<std::mutex>> mutex_locker;
    if (threading_support_mode_ == SUPPORT_MULTITHREADING)
        mutex_locker.reset(new std::lock_guard<std::mutex>(SslConnection::mutex_));

    return ::SSL_get_error(ssl_connection_, last_ret_val_);
}

namespace {

class ContextInfoMatch {
    const SslConnection::Method method_;
    const SslConnection::ClientServerMode client_server_mode_;
public:
    explicit ContextInfoMatch(const SslConnection::Method method,
                              const SslConnection::ClientServerMode client_server_mode)
        : method_(method), client_server_mode_(client_server_mode) { }
    bool operator()(const SslConnection::ContextInfo &rhs) const;
};

bool ContextInfoMatch::operator()(const SslConnection::ContextInfo &rhs) const {
    if (rhs.method_ != method_)
        return false;
    if (rhs.client_server_mode_ != client_server_mode_)
        return false;
    return true;
}

} // unnamed namespace

SSL_CTX *SslConnection::InitContext(const Method method, const ClientServerMode client_server_mode) {
    if (not ssl_libraries_have_been_initialised_) {
        ::SSL_load_error_strings();
        ::SSL_library_init();
        // We don't call ::RAND_add() because we assume the existence of /dev/urandom!

        ssl_libraries_have_been_initialised_ = true;
    }

    // First check to see if we already have a context with the correct options:
    std::list<ContextInfo>::iterator matching_context_info(std::find_if(context_infos_.begin(), context_infos_.end(),
                                                                        ContextInfoMatch(method,
                                                                                client_server_mode)));
    if (matching_context_info != context_infos_.end()) {
        ++matching_context_info->usage_count_;
        return matching_context_info->ssl_context_;
    }

    // If we make it here we need to create a new ContextInfo:
    ContextInfo new_context_info(method, client_server_mode);
    switch (client_server_mode) {
    case CLIENT:
        new_context_info.ssl_context_ = SslConnection::InitClient(method);
        break;
    case SERVER:
        new_context_info.ssl_context_ = SslConnection::InitServer(method);
        break;
    case CLIENT_AND_SERVER:
        new_context_info.ssl_context_ = SslConnection::InitClientAndServer(method);
        break;
    default:
        throw std::runtime_error("in SslConnection::InitContext: unknown client/server mode!");
    }
    context_infos_.push_back(new_context_info);
    return new_context_info.ssl_context_;
}

namespace {

class ContextMatch {
    const SSL_CTX * const ssl_context_to_match_;
public:
    explicit ContextMatch(const SSL_CTX * const ssl_context_to_match): ssl_context_to_match_(ssl_context_to_match) { }
    bool operator()(const SslConnection::ContextInfo &rhs) const { return rhs.ssl_context_ == ssl_context_to_match_; }
};

} // unnamed namespace

void SslConnection::ReleaseContext(const SSL_CTX * const ssl_context) {
    std::list<ContextInfo>::iterator matching_context_info(
        std::find_if(context_infos_.begin(), context_infos_.end(), ContextMatch(ssl_context)));
    if (unlikely(matching_context_info == context_infos_.end()))
        throw std::runtime_error("in SslConnection::ReleaseContext: can't find context to release!");

    --matching_context_info->usage_count_;
    if (matching_context_info->usage_count_ == 0) {
        ::SSL_CTX_free(matching_context_info->ssl_context_);
        context_infos_.erase(matching_context_info);
    }
}

typedef SSL_METHOD *(*SslMethod)(void);

SSL_CTX *SslConnection::InitClient(const Method method) {
    static bool initialised(false);
    static SslMethod stream_client_method(nullptr);
    static SslMethod datagram_client_method(nullptr);
    if (not initialised) {
        initialised = true;
        DynamicLoader dynamic_loader("libssl.so");

        stream_client_method = (SslMethod)(dynamic_loader.loadSymbol("TLS_client_method"));
        if (stream_client_method == nullptr)
            stream_client_method = (SslMethod)dynamic_loader.loadSymbol("SSLv23_client_method");
        if (stream_client_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load TLS_client_method nor "
                                     "SSLv23_client_method from libssl.so!");

        datagram_client_method = (SslMethod)(dynamic_loader.loadSymbol("DTLS_client_method"));
        if (datagram_client_method == nullptr)
            datagram_client_method = (SslMethod)dynamic_loader.loadSymbol("DTLSv1_client_method");
        if (datagram_client_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load DTLS_client_method nor "
                                     "DTLSv1_client_method from libssl.so!");
    }

    return ::SSL_CTX_new(method == ALL_STREAM_METHODS ? stream_client_method() : datagram_client_method());
}

SSL_CTX *SslConnection::InitServer(const Method method) {
    static bool initialised(false);
    static SslMethod stream_server_method(nullptr);
    static SslMethod datagram_server_method(nullptr);
    if (not initialised) {
        initialised = true;
        DynamicLoader dynamic_loader("libssl.so");

        stream_server_method = (SslMethod)(dynamic_loader.loadSymbol("TLS_server_method"));
        if (stream_server_method == nullptr)
            stream_server_method = (SslMethod)dynamic_loader.loadSymbol("SSLv23_server_method");
        if (stream_server_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load TLS_server_method nor "
                                     "SSLv23_server_method from libssl.so!");

        datagram_server_method = (SslMethod)(dynamic_loader.loadSymbol("DTLS_server_method"));
        if (datagram_server_method == nullptr)
            datagram_server_method = (SslMethod)dynamic_loader.loadSymbol("DTLSv1_server_method");
        if (datagram_server_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load DTLS_server_method nor "
                                     "DTLSv1_server_method from libssl.so!");
    }

    return ::SSL_CTX_new(method == ALL_STREAM_METHODS ? stream_server_method() : datagram_server_method());
}

SSL_CTX *SslConnection::InitClientAndServer(const Method method) {
    static bool initialised(false);
    static SslMethod stream_method(nullptr);
    static SslMethod datagram_method(nullptr);
    if (not initialised) {
        initialised = true;
        DynamicLoader dynamic_loader("libssl.so");

        stream_method = (SslMethod)(dynamic_loader.loadSymbol("TLS_method"));
        if (stream_method == nullptr)
            stream_method = (SslMethod)dynamic_loader.loadSymbol("SSLv23_method");
        if (stream_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load TLS_method nor "
                                     "SSLv23_method from libssl.so!");

        datagram_method = (SslMethod)(dynamic_loader.loadSymbol("DTLS_method"));
        if (datagram_method == nullptr)
            datagram_method = (SslMethod)dynamic_loader.loadSymbol("DTLSv1_method");
        if (datagram_method == nullptr)
            throw std::runtime_error("in SslConnection::InitClient: can't load DTLS_method nor "
                                     "DTLSv1_method from libssl.so!");
    }

    return ::SSL_CTX_new(method == ALL_STREAM_METHODS ? stream_method() : datagram_method());
}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "@FUNCTIONALITY_NAME@.h"
#include "@FUNCTIONALITY_NAME@Controls.h"
#include <qaction.h>
#include "icon.xpm"
#include "QmitkTreeNodeSelector.h"
#include "QmitkStdMultiWidget.h"

@FUNCTIONALITY_NAME@::@FUNCTIONALITY_NAME@(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it)
    : QmitkFunctionality(parent, name, it), m_MultiWidget(mitkStdMultiWidget), m_Controls(NULL)
{
  SetAvailability(true);
}

@FUNCTIONALITY_NAME@::~@FUNCTIONALITY_NAME@()
{}

QWidget * @FUNCTIONALITY_NAME@::CreateMainWidget(QWidget *parent)
{
  if ( m_MultiWidget == NULL )
  {
    m_MultiWidget = new QmitkStdMultiWidget( parent );
  }
  return m_MultiWidget;
}

QWidget * @FUNCTIONALITY_NAME@::CreateControlWidget(QWidget *parent)
{
  if (m_Controls == NULL)
  {
    m_Controls = new @FUNCTIONALITY_NAME@Controls(parent);
  }
  return m_Controls;
}

void @FUNCTIONALITY_NAME@::CreateConnections()
{
  if ( m_Controls )
  {
    connect( (QObject*)(m_Controls->m_TreeNodeSelector), SIGNAL(Activated(mitk::DataTreeIteratorClone)),(QObject*) this, SLOT(ImageSelected(mitk::DataTreeIteratorClone)) );
    connect( (QObject*)(m_Controls->m_StartButton), SIGNAL(clicked()),(QObject*) this, SLOT(StartButtonClicked()));
  }
}

QAction * @FUNCTIONALITY_NAME@::CreateAction(QActionGroup *parent)
{
  QAction* action;
  action = new QAction( tr( "@FUNCTIONALITY_NAME@ description" ), QPixmap((const char**)icon_xpm), tr( "@FUNCTIONALITY_NAME@ menu" ), 0, parent, "@FUNCTIONALITY_NAME@" );
  return action;
}

void @FUNCTIONALITY_NAME@::TreeChanged()
{
  m_Controls->m_TreeNodeSelector->SetDataTreeNodeIterator(this->GetDataTreeIterator());
}

void @FUNCTIONALITY_NAME@::Activated()
{
  QmitkFunctionality::Activated();
}

void @FUNCTIONALITY_NAME@::ImageSelected(mitk::DataTreeIteratorClone imageIt)
{
  assert( imageIt.IsNotNull() ); // should never fail, the selection widget cares for that

  mitk::DataTreeNode* node = imageIt->Get();
  if ( node )
  {
    // here we have a valid mitk::DataTreeNode
    std::string name;
    if (node->GetName(name))
    {
      // a property called "name" was found for this DataTreeNode
      std::cout << "Tree node selected with name '" << name << "'" << std::endl;
    }

    // a node itself is not very useful, we need its data item
    mitk::BaseData* data = node->GetData();
    if (data)
    {
      // test if this data item is an image or not (could also be a surface or something totally different)
      mitk::Image* image = dynamic_cast<mitk::Image*>( data );
      if (image)
      {
        std::cout << "Surprise: this node contains a real image dataset." << std::endl;
      }
    }
  }
}
void @FUNCTIONALITY_NAME@::StartButtonClicked()
{
  std::cout << "Start Button clicked!" << std::endl;
}

<commit_msg>ENH (#1578): add hints about the usage of StatusBar, ProgressBar and WaitCursor to functionality template<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "@FUNCTIONALITY_NAME@.h"
#include "@FUNCTIONALITY_NAME@Controls.h"
#include <qaction.h>
#include "icon.xpm"
#include "QmitkTreeNodeSelector.h"
#include "QmitkStdMultiWidget.h"
#include "mitkStatusBar.h"
#include "mitkProgressBar.h"

@FUNCTIONALITY_NAME@::@FUNCTIONALITY_NAME@(QObject *parent, const char *name, QmitkStdMultiWidget *mitkStdMultiWidget, mitk::DataTreeIteratorBase* it)
    : QmitkFunctionality(parent, name, it), m_MultiWidget(mitkStdMultiWidget), m_Controls(NULL)
{
  SetAvailability(true);
}

@FUNCTIONALITY_NAME@::~@FUNCTIONALITY_NAME@()
{}

QWidget * @FUNCTIONALITY_NAME@::CreateMainWidget(QWidget *parent)
{
  if ( m_MultiWidget == NULL )
  {
    m_MultiWidget = new QmitkStdMultiWidget( parent );
  }
  return m_MultiWidget;
}

QWidget * @FUNCTIONALITY_NAME@::CreateControlWidget(QWidget *parent)
{
  if (m_Controls == NULL)
  {
    m_Controls = new @FUNCTIONALITY_NAME@Controls(parent);
  }
  return m_Controls;
}

void @FUNCTIONALITY_NAME@::CreateConnections()
{
  if ( m_Controls )
  {
    connect( (QObject*)(m_Controls->m_TreeNodeSelector), SIGNAL(Activated(mitk::DataTreeIteratorClone)),(QObject*) this, SLOT(ImageSelected(mitk::DataTreeIteratorClone)) );
    connect( (QObject*)(m_Controls->m_StartButton), SIGNAL(clicked()),(QObject*) this, SLOT(StartButtonClicked()));
  }
}

QAction * @FUNCTIONALITY_NAME@::CreateAction(QActionGroup *parent)
{
  QAction* action;
  action = new QAction( tr( "@FUNCTIONALITY_NAME@ description" ), QPixmap((const char**)icon_xpm), tr( "@FUNCTIONALITY_NAME@ menu" ), 0, parent, "@FUNCTIONALITY_NAME@" );
  return action;
}

void @FUNCTIONALITY_NAME@::TreeChanged()
{
  m_Controls->m_TreeNodeSelector->SetDataTreeNodeIterator(this->GetDataTreeIterator());
}

void @FUNCTIONALITY_NAME@::Activated()
{
  QmitkFunctionality::Activated();
}

void @FUNCTIONALITY_NAME@::ImageSelected(mitk::DataTreeIteratorClone imageIt)
{
  assert( imageIt.IsNotNull() ); // should never fail, the selection widget cares for that

  mitk::DataTreeNode* node = imageIt->Get();
  if ( node )
  {
    // here we have a valid mitk::DataTreeNode
    std::string name;
    if (node->GetName(name))
    {
      // a property called "name" was found for this DataTreeNode
      std::cout << "Tree node selected with name '" << name << "'" << std::endl;
    }

    // a node itself is not very useful, we need its data item
    mitk::BaseData* data = node->GetData();
    if (data)
    {
      // test if this data item is an image or not (could also be a surface or something totally different)
      mitk::Image* image = dynamic_cast<mitk::Image*>( data );
      if (image)
      {
        std::cout << "Surprise: this node contains a real image dataset." << std::endl;
      }
    }
  }
}

void @FUNCTIONALITY_NAME@::StartButtonClicked()
{
  std::cout << "Start Button clicked!" << std::endl;
  WaitCursorOn(); // always good to show the user that the application is processing and will not react to user input for a while
  mitk::StatusBar::GetInstance()->DisplayText("@FUNCTIONALITY_NAME@ is doing something...", 4000);  // tell the user what you are doing
  mitk::ProgressBar::GetInstance()->AddStepsToDo(2);  // use progress bar to show that the application is doing something

  // Do something here, add progress while you do it:

  mitk::ProgressBar::GetInstance()->Progress();
  mitk::ProgressBar::GetInstance()->Progress(); // last step, we're finished!
  mitk::StatusBar::GetInstance()->DisplayText("@FUNCTIONALITY_NAME@ has finished...", 2000);
  WaitCursorOff();  // restore normal mouse cursor after you finished
}
<|endoftext|>


<commit_before>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2018 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/sfm/pipelines/relative_pose_engine.hpp"

#include "openMVG/multiview/essential.hpp"
#include "openMVG/multiview/triangulation.hpp"
#include "openMVG/sfm/pipelines/sfm_robust_model_estimation.hpp"
#include "openMVG/sfm/pipelines/sfm_features_provider.hpp"
#include "openMVG/sfm/pipelines/sfm_matches_provider.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/sfm/sfm_data_BA_ceres.hpp"
#include "openMVG/sfm/sfm_data_io.hpp"
#include "openMVG/sfm/sfm_data_triangulation.hpp"
#include "openMVG/system/timer.hpp"

#include "ceres/ceres.h"

namespace openMVG {
namespace sfm {

using namespace cameras;
using namespace geometry;
using namespace matching;

// Try to compute all the possible relative pose.
bool Relative_Pose_Engine::Process(
  const SfM_Data & sfm_data_,
  const Matches_Provider * matches_provider_,
  const Features_Provider * features_provider_
)
{
  Pair_Set relative_pose_pairs;
  for (const auto & iterMatches : matches_provider_->pairWise_matches_)
  {
    const Pair pair = iterMatches.first;
    const View * v1 = sfm_data_.GetViews().at(pair.first).get();
    const View * v2 = sfm_data_.GetViews().at(pair.second).get();
    if (v1->id_pose != v2->id_pose)
      relative_pose_pairs.insert({v1->id_pose, v2->id_pose});
  }
  return
    Process(
      relative_pose_pairs,
      sfm_data_,
      matches_provider_,
      features_provider_);
}

// Try to compute the relative pose for the provided pose pairs
bool Relative_Pose_Engine::Relative_Pose_Engine::Process(
  const Pair_Set & relative_pose_pairs,
  const SfM_Data & sfm_data_,
  const Matches_Provider * matches_provider_,
  const Features_Provider * features_provider_
)
{
  //
  // List the pairwise matches related to each pose edge ids.
  //
  using PoseWiseMatches = Hash_Map<Pair, Pair_Set>;
  PoseWiseMatches posewise_matches;
  for (const auto & iterMatches : matches_provider_->pairWise_matches_)
  {
    const Pair pair = iterMatches.first;
    const View * v1 = sfm_data_.GetViews().at(pair.first).get();
    const View * v2 = sfm_data_.GetViews().at(pair.second).get();
    if (v1->id_pose != v2->id_pose
        && relative_pose_pairs.count({v1->id_pose, v2->id_pose}) == 1)
      posewise_matches[{v1->id_pose, v2->id_pose}].insert(pair);
  }

  system::Timer t;

  std::unique_ptr<C_Progress> progress_status
    (new C_Progress_display(posewise_matches.size(),
      std::cout, "\n- Relative pose computation -\n" ));

  #ifdef OPENMVG_USE_OPENMP
    #pragma omp parallel for schedule(dynamic)
  #endif
  // Compute the relative pose from pairwise point matches:
  for (int i = 0; i < static_cast<int>(posewise_matches.size()); ++i)
  {
    ++(*progress_status);
    {
      PoseWiseMatches::const_iterator iter (posewise_matches.begin());
      std::advance(iter, i);
      const auto & relative_pose_iterator(*iter);
      const Pair relative_pose_pair = relative_pose_iterator.first;
      const Pair_Set & match_pairs = relative_pose_iterator.second;

      // If a pair has the same ID, discard it
      if (relative_pose_pair.first == relative_pose_pair.second)
      {
        continue;
      }

      // Select common bearing vectors
      if (match_pairs.size() > 1)
      {
        std::cerr << "Compute relative pose between more than two view is not supported" << std::endl;
        continue;
      }

      const Pair current_pair(*std::begin(match_pairs));

      const IndexT
        I = current_pair.first,
        J = current_pair.second;

      const View
        * view_I = sfm_data_.views.at(I).get(),
        * view_J = sfm_data_.views.at(J).get();

      // Check that valid cameras exist for the view pair
      if (sfm_data_.GetIntrinsics().count(view_I->id_intrinsic) == 0 ||
          sfm_data_.GetIntrinsics().count(view_J->id_intrinsic) == 0)
        continue;

      const IntrinsicBase
        * cam_I = sfm_data_.GetIntrinsics().at(view_I->id_intrinsic).get(),
        * cam_J = sfm_data_.GetIntrinsics().at(view_J->id_intrinsic).get();

      // Compute for each feature the un-distorted camera coordinates
      const matching::IndMatches & matches = matches_provider_->pairWise_matches_.at(current_pair);
      size_t number_matches = matches.size();
      Mat2X x1(2, number_matches), x2(2, number_matches);
      number_matches = 0;
      for (const auto & match : matches)
      {
        x1.col(number_matches) = cam_I->get_ud_pixel(
          features_provider_->feats_per_view.at(I)[match.i_].coords().cast<double>());
        x2.col(number_matches++) = cam_J->get_ud_pixel(
          features_provider_->feats_per_view.at(J)[match.j_].coords().cast<double>());
      }

      RelativePose_Info relativePose_info;
      relativePose_info.initial_residual_tolerance = Square(2.5);
      if (!robustRelativePose(cam_I, cam_J,
                              x1, x2, relativePose_info,
                              {cam_I->w(), cam_I->h()},
                              {cam_J->w(), cam_J->h()},
                              256))
      {
        continue;
      }
      const bool bRefine_using_BA = true;
      if (bRefine_using_BA)
      {
        // Refine the defined scene
        SfM_Data tiny_scene;
        tiny_scene.views.insert(*sfm_data_.GetViews().find(view_I->id_view));
        tiny_scene.views.insert(*sfm_data_.GetViews().find(view_J->id_view));
        tiny_scene.intrinsics.insert(*sfm_data_.GetIntrinsics().find(view_I->id_intrinsic));
        tiny_scene.intrinsics.insert(*sfm_data_.GetIntrinsics().find(view_J->id_intrinsic));

        // Init poses
        const Pose3 & Pose_I = tiny_scene.poses[view_I->id_pose] = {Mat3::Identity(), Vec3::Zero()};
        const Pose3 & Pose_J = tiny_scene.poses[view_J->id_pose] = relativePose_info.relativePose;

        // Init structure
        const Mat34
          P1 = cam_I->get_projective_equivalent(Pose_I),
          P2 = cam_J->get_projective_equivalent(Pose_J);
        Landmarks & landmarks = tiny_scene.structure;
        for (Mat::Index k = 0; k < x1.cols(); ++k)
        {
          const Vec2
            x1_ = features_provider_->feats_per_view.at(I)[matches[k].i_].coords().cast<double>(),
            x2_ = features_provider_->feats_per_view.at(J)[matches[k].j_].coords().cast<double>();
          Vec3 X;
          TriangulateDLT(P1, x1_.homogeneous(), P2, x2_.homogeneous(), &X);
          Observations obs;
          obs[view_I->id_view] = Observation(x1_, matches[k].i_);
          obs[view_J->id_view] = Observation(x2_, matches[k].j_);
          landmarks[k].obs = obs;
          landmarks[k].X = X;
        }
        // - refine only Structure and Rotations & translations (keep intrinsic constant)
        Bundle_Adjustment_Ceres::BA_Ceres_options options(false, false);
        options.linear_solver_type_ = ceres::DENSE_SCHUR;
        Bundle_Adjustment_Ceres bundle_adjustment_obj(options);
        const Optimize_Options ba_refine_options
          (Intrinsic_Parameter_Type::NONE, // -> Keep intrinsic constant
          Extrinsic_Parameter_Type::ADJUST_ALL, // adjust camera motion
          Structure_Parameter_Type::ADJUST_ALL);// adjust scene structure
        if (bundle_adjustment_obj.Adjust(tiny_scene, ba_refine_options))
        {
          // --> to debug: save relative pair geometry on disk
          // std::ostringstream os;
          // os << relative_pose_pair.first << "_" << relative_pose_pair.second << ".ply";
          // Save(tiny_scene, os.str(), ESfM_Data(STRUCTURE | EXTRINSICS));
          //
          const Mat3 R1 = tiny_scene.poses[view_I->id_pose].rotation(),
                     R2 = tiny_scene.poses[view_J->id_pose].rotation();
          const Vec3 t1 = tiny_scene.poses[view_I->id_pose].translation(),
                     t2 = tiny_scene.poses[view_J->id_pose].translation();
          // Compute relative motion and save it
          Mat3 Rrel;
          Vec3 trel;
          RelativeCameraMotion(R1, t1, R2, t2, &Rrel, &trel);
          // Update found relative pose
          relativePose_info.relativePose = Pose3(Rrel, -Rrel.transpose() * trel);
        }
      }
#ifdef OPENMVG_USE_OPENMP
      #pragma omp critical
#endif
      {
        // Add the relative pose to the relative 'rotation' pose graph
        relative_poses_[relative_pose_pair] = relativePose_info.relativePose;
      }
    }
  }
  std::cout << "Relative motion computation took: " << t.elapsedMs() << "(ms)" << std::endl;
  return !relative_poses_.empty();
}

// Relative poses accessor
Relative_Pose_Engine::Relative_Pair_Poses
Relative_Pose_Engine::Get_Relative_Poses() const
{
  return relative_poses_;
}

} // namespace sfm
} // namespace openMVG
<commit_msg>[sfm] Fix the initial triangulation for the relative pose engine #1241<commit_after>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2018 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "openMVG/sfm/pipelines/relative_pose_engine.hpp"

#include "openMVG/multiview/essential.hpp"
#include "openMVG/multiview/triangulation.hpp"
#include "openMVG/sfm/pipelines/sfm_robust_model_estimation.hpp"
#include "openMVG/sfm/pipelines/sfm_features_provider.hpp"
#include "openMVG/sfm/pipelines/sfm_matches_provider.hpp"
#include "openMVG/sfm/sfm_data.hpp"
#include "openMVG/sfm/sfm_data_BA_ceres.hpp"
#include "openMVG/sfm/sfm_data_io.hpp"
#include "openMVG/sfm/sfm_data_triangulation.hpp"
#include "openMVG/system/timer.hpp"

#include "ceres/ceres.h"

namespace openMVG {
namespace sfm {

using namespace cameras;
using namespace geometry;
using namespace matching;

// Try to compute all the possible relative pose.
bool Relative_Pose_Engine::Process(
  const SfM_Data & sfm_data_,
  const Matches_Provider * matches_provider_,
  const Features_Provider * features_provider_
)
{
  Pair_Set relative_pose_pairs;
  for (const auto & iterMatches : matches_provider_->pairWise_matches_)
  {
    const Pair pair = iterMatches.first;
    const View * v1 = sfm_data_.GetViews().at(pair.first).get();
    const View * v2 = sfm_data_.GetViews().at(pair.second).get();
    if (v1->id_pose != v2->id_pose)
      relative_pose_pairs.insert({v1->id_pose, v2->id_pose});
  }
  return
    Process(
      relative_pose_pairs,
      sfm_data_,
      matches_provider_,
      features_provider_);
}

// Try to compute the relative pose for the provided pose pairs
bool Relative_Pose_Engine::Relative_Pose_Engine::Process(
  const Pair_Set & relative_pose_pairs,
  const SfM_Data & sfm_data_,
  const Matches_Provider * matches_provider_,
  const Features_Provider * features_provider_
)
{
  //
  // List the pairwise matches related to each pose edge ids.
  //
  using PoseWiseMatches = Hash_Map<Pair, Pair_Set>;
  PoseWiseMatches posewise_matches;
  for (const auto & iterMatches : matches_provider_->pairWise_matches_)
  {
    const Pair pair = iterMatches.first;
    const View * v1 = sfm_data_.GetViews().at(pair.first).get();
    const View * v2 = sfm_data_.GetViews().at(pair.second).get();
    if (v1->id_pose != v2->id_pose
        && relative_pose_pairs.count({v1->id_pose, v2->id_pose}) == 1)
      posewise_matches[{v1->id_pose, v2->id_pose}].insert(pair);
  }

  system::Timer t;

  std::unique_ptr<C_Progress> progress_status
    (new C_Progress_display(posewise_matches.size(),
      std::cout, "\n- Relative pose computation -\n" ));

  #ifdef OPENMVG_USE_OPENMP
    #pragma omp parallel for schedule(dynamic)
  #endif
  // Compute the relative pose from pairwise point matches:
  for (int i = 0; i < static_cast<int>(posewise_matches.size()); ++i)
  {
    ++(*progress_status);
    {
      PoseWiseMatches::const_iterator iter (posewise_matches.begin());
      std::advance(iter, i);
      const auto & relative_pose_iterator(*iter);
      const Pair relative_pose_pair = relative_pose_iterator.first;
      const Pair_Set & match_pairs = relative_pose_iterator.second;

      // If a pair has the same ID, discard it
      if (relative_pose_pair.first == relative_pose_pair.second)
      {
        continue;
      }

      // Select common bearing vectors
      if (match_pairs.size() > 1)
      {
        std::cerr << "Compute relative pose between more than two view is not supported" << std::endl;
        continue;
      }

      const Pair current_pair(*std::begin(match_pairs));

      const IndexT
        I = current_pair.first,
        J = current_pair.second;

      const View
        * view_I = sfm_data_.views.at(I).get(),
        * view_J = sfm_data_.views.at(J).get();

      // Check that valid cameras exist for the view pair
      if (sfm_data_.GetIntrinsics().count(view_I->id_intrinsic) == 0 ||
          sfm_data_.GetIntrinsics().count(view_J->id_intrinsic) == 0)
        continue;

      const IntrinsicBase
        * cam_I = sfm_data_.GetIntrinsics().at(view_I->id_intrinsic).get(),
        * cam_J = sfm_data_.GetIntrinsics().at(view_J->id_intrinsic).get();

      // Compute for each feature the un-distorted camera coordinates
      const matching::IndMatches & matches = matches_provider_->pairWise_matches_.at(current_pair);
      size_t number_matches = matches.size();
      Mat2X x1(2, number_matches), x2(2, number_matches);
      number_matches = 0;
      for (const auto & match : matches)
      {
        x1.col(number_matches) = cam_I->get_ud_pixel(
          features_provider_->feats_per_view.at(I)[match.i_].coords().cast<double>());
        x2.col(number_matches++) = cam_J->get_ud_pixel(
          features_provider_->feats_per_view.at(J)[match.j_].coords().cast<double>());
      }

      RelativePose_Info relativePose_info;
      relativePose_info.initial_residual_tolerance = Square(2.5);
      if (!robustRelativePose(cam_I, cam_J,
                              x1, x2, relativePose_info,
                              {cam_I->w(), cam_I->h()},
                              {cam_J->w(), cam_J->h()},
                              256))
      {
        continue;
      }
      const bool bRefine_using_BA = true;
      if (bRefine_using_BA)
      {
        // Refine the defined scene
        SfM_Data tiny_scene;
        tiny_scene.views.insert(*sfm_data_.GetViews().find(view_I->id_view));
        tiny_scene.views.insert(*sfm_data_.GetViews().find(view_J->id_view));
        tiny_scene.intrinsics.insert(*sfm_data_.GetIntrinsics().find(view_I->id_intrinsic));
        tiny_scene.intrinsics.insert(*sfm_data_.GetIntrinsics().find(view_J->id_intrinsic));

        // Init poses
        const Pose3 & pose_I = tiny_scene.poses[view_I->id_pose] = {Mat3::Identity(), Vec3::Zero()};
        const Pose3 & pose_J = tiny_scene.poses[view_J->id_pose] = relativePose_info.relativePose;

        // Init structure
        Landmarks & landmarks = tiny_scene.structure;
        for (Mat::Index k = 0; k < x1.cols(); ++k)
        {
          Vec3 X;
          TriangulateDLT(pose_I.asMatrix(), (*cam_I)(x1.col(k)),
                         pose_J.asMatrix(), (*cam_J)(x2.col(k)), &X);
          Observations obs;
          const Vec2 obs_I = features_provider_->feats_per_view.at(I)[matches[k].i_].coords().cast<double>();
          const Vec2 obs_J = features_provider_->feats_per_view.at(J)[matches[k].j_].coords().cast<double>();
          obs[view_I->id_view] = {obs_I, matches[k].i_};
          obs[view_J->id_view] = {obs_J, matches[k].j_};
          landmarks[k].obs = obs;
          landmarks[k].X = X;
        }
        // - refine only Structure and Rotations & translations (keep intrinsic constant)
        Bundle_Adjustment_Ceres::BA_Ceres_options options(false, false);
        options.linear_solver_type_ = ceres::DENSE_SCHUR;
        Bundle_Adjustment_Ceres bundle_adjustment_obj(options);
        const Optimize_Options ba_refine_options
          (Intrinsic_Parameter_Type::NONE, // -> Keep intrinsic constant
          Extrinsic_Parameter_Type::ADJUST_ALL, // adjust camera motion
          Structure_Parameter_Type::ADJUST_ALL);// adjust scene structure
        if (bundle_adjustment_obj.Adjust(tiny_scene, ba_refine_options))
        {
          // --> to debug: save relative pair geometry on disk
          // std::ostringstream os;
          // os << relative_pose_pair.first << "_" << relative_pose_pair.second << ".ply";
          // Save(tiny_scene, os.str(), ESfM_Data(STRUCTURE | EXTRINSICS));
          //
          const Mat3 R1 = tiny_scene.poses[view_I->id_pose].rotation(),
                     R2 = tiny_scene.poses[view_J->id_pose].rotation();
          const Vec3 t1 = tiny_scene.poses[view_I->id_pose].translation(),
                     t2 = tiny_scene.poses[view_J->id_pose].translation();
          // Compute relative motion and save it
          Mat3 Rrel;
          Vec3 trel;
          RelativeCameraMotion(R1, t1, R2, t2, &Rrel, &trel);
          // Update found relative pose
          relativePose_info.relativePose = Pose3(Rrel, -Rrel.transpose() * trel);
        }
      }
#ifdef OPENMVG_USE_OPENMP
      #pragma omp critical
#endif
      {
        // Add the relative pose to the relative 'rotation' pose graph
        relative_poses_[relative_pose_pair] = relativePose_info.relativePose;
      }
    }
  }
  std::cout << "Relative motion computation took: " << t.elapsedMs() << "(ms)" << std::endl;
  return !relative_poses_.empty();
}

// Relative poses accessor
Relative_Pose_Engine::Relative_Pair_Poses
Relative_Pose_Engine::Get_Relative_Poses() const
{
  return relative_poses_;
}

} // namespace sfm
} // namespace openMVG
<|endoftext|>


<commit_before>// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "HaxeRuntime.h"

#if PLATFORM_WINDOWS || PLATFORM_WINRT || PLATFORM_XBOXONE
	#include <windows.h>
#elif PLATFORM_MAC || PLATFORM_IOS || PLATFORM_LINUX || PLATFORM_ANDROID
	#include <pthread.h>
#else
#endif

IMPLEMENT_GAME_MODULE( FHaxeRuntime, HaxeSources );

extern "C" void  gc_set_top_of_stack(int *inTopOfStack,bool inForce);
extern "C" const char *hxRunLibrary();
// void __scriptable_load_cppia(String inCode);

static void *get_top_of_stack(void)
{
#if PLATFORM_WINDOWS || PLATFORM_WINRT || PLATFORM_XBOXONE //TODO: see if XBOXONE really behaves like Windows
  MEMORY_BASIC_INFORMATION info;
  VirtualQuery(&info, &info, sizeof(MEMORY_BASIC_INFORMATION));
  return (void *)info.BaseAddress + info.RegionSize;
#elif PLATFORM_MAC || PLATFORM_IOS
  return pthread_get_stackaddr_np(pthread_self());
#elif PLATFORM_LINUX || PLATFORM_ANDROID
  pthread_t self = pthread_self();
  pthread_attr_t attr;
  void* addr;
  size_t size;

  pthread_getattr_np(self, &attr);
  pthread_attr_getstack(&attr, &addr, &size);
  pthread_attr_destroy(&attr);

  return (void *) (((intptr_t)addr) + size);
#else //PLATFORM_PS4, PLATFORM_HTML5
  return NULL;
#endif
}

static bool did_init = false;

extern "C" void check_hx_init()
{
  if (did_init) return;
  did_init = true;

  // This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
  int x;
  void *top_of_stack = get_top_of_stack();
  if (NULL == top_of_stack)
  {
    // UE_LOG(HXR, Error, TEXT("Currently unsupported Haxe runtime platform. Trying to get approximate stack size"));
    top_of_stack = &x;
  }

#ifdef WITH_HAXE
  gc_set_top_of_stack((int *)top_of_stack, false);
  const char *error = hxRunLibrary();
  // if (error) { UE_LOG(HXR, Error, TEXT("Error on Haxe main function: %s"), UTF8_TO_TCHAR(error)); }
  if (error) { fprintf(stderr, "Error on Haxe main function: %s", error); }
#endif
}

void FHaxeRuntime::StartupModule()
{
  check_hx_init();
}

void FHaxeRuntime::ShutdownModule()
{
}
<commit_msg>Fix setting region address<commit_after>// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "HaxeRuntime.h"

#if PLATFORM_WINDOWS || PLATFORM_WINRT || PLATFORM_XBOXONE
	#include <windows.h>
#elif PLATFORM_MAC || PLATFORM_IOS || PLATFORM_LINUX || PLATFORM_ANDROID
	#include <pthread.h>
#else
#endif

IMPLEMENT_GAME_MODULE( FHaxeRuntime, HaxeSources );

extern "C" void  gc_set_top_of_stack(int *inTopOfStack,bool inForce);
extern "C" const char *hxRunLibrary();
// void __scriptable_load_cppia(String inCode);

static void *get_top_of_stack(void)
{
#if PLATFORM_WINDOWS || PLATFORM_WINRT || PLATFORM_XBOXONE //TODO: see if XBOXONE really behaves like Windows
  MEMORY_BASIC_INFORMATION info;
  VirtualQuery(&info, &info, sizeof(MEMORY_BASIC_INFORMATION));
  return (void *) (( (char *) info.BaseAddress) + info.RegionSize);
#elif PLATFORM_MAC || PLATFORM_IOS
  return pthread_get_stackaddr_np(pthread_self());
#elif PLATFORM_LINUX || PLATFORM_ANDROID
  pthread_t self = pthread_self();
  pthread_attr_t attr;
  void* addr;
  size_t size;

  pthread_getattr_np(self, &attr);
  pthread_attr_getstack(&attr, &addr, &size);
  pthread_attr_destroy(&attr);

  return (void *) (((intptr_t)addr) + size);
#else //PLATFORM_PS4, PLATFORM_HTML5
  return NULL;
#endif
}

static bool did_init = false;

extern "C" void check_hx_init()
{
  if (did_init) return;
  did_init = true;

  // This code will execute after your module is loaded into memory (but after global variables are initialized, of course.)
  int x;
  void *top_of_stack = get_top_of_stack();
  if (NULL == top_of_stack)
  {
    // UE_LOG(HXR, Error, TEXT("Currently unsupported Haxe runtime platform. Trying to get approximate stack size"));
    top_of_stack = &x;
  }

#ifdef WITH_HAXE
  gc_set_top_of_stack((int *)top_of_stack, false);
  const char *error = hxRunLibrary();
  // if (error) { UE_LOG(HXR, Error, TEXT("Error on Haxe main function: %s"), UTF8_TO_TCHAR(error)); }
  if (error) { fprintf(stderr, "Error on Haxe main function: %s", error); }
#endif
}

void FHaxeRuntime::StartupModule()
{
  check_hx_init();
}

void FHaxeRuntime::ShutdownModule()
{
}
<|endoftext|>


<commit_before>/*
 * -----------------------------------------------------------------------------
 * This source file is part of OGRE
 * (Object-oriented Graphics Rendering Engine)
 * For the latest info, see http://www.ogre3d.org/
 *
 * Copyright (c) 2000-2013 Torus Knot Software Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * -----------------------------------------------------------------------------
 */

#include "OgreLodCollapseCostProfiler.h"

namespace Ogre
{

	Real LodCollapseCostProfiler::computeEdgeCollapseCost( LodData* data, LodData::Vertex* src, LodData::Edge* dstEdge )
	{
		OgreAssert(0, "Only computeVertexCollapseCost should call this function.");
		return 0;
	}

	void LodCollapseCostProfiler::computeVertexCollapseCost( LodData* data, LodData::Vertex* vertex, Real& collapseCost, LodData::Vertex*& collapseTo )
	{
		LodData::VEdges::iterator it = vertex->edges.begin();
		if(!mHasProfile[LodData::getVectorIDFromPointer(data->mVertexList, vertex)]){
			for (; it != vertex->edges.end(); it++) {
				it->collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &*it);
				if (collapseCost > it->collapseCost) {
					collapseCost = it->collapseCost;
					collapseTo = it->dst;
				}
			}
		} else {
			std::pair<ProfileLookup::iterator, ProfileLookup::iterator> ret = mProfileLookup.equal_range(vertex);
			for (; it != vertex->edges.end(); it++) {
				it->collapseCost = LodData::UNINITIALIZED_COLLAPSE_COST;
				for(ProfileLookup::iterator it2 = ret.first; it2 != ret.second; it2++){
					if(it2->second.dst == it->dst ){
						it->collapseCost = it2->second.cost;
						break;
					}
				}
				if(it->collapseCost == LodData::UNINITIALIZED_COLLAPSE_COST){
					it->collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &*it);
				}
				if (collapseCost > it->collapseCost) {
					collapseCost = it->collapseCost;
					collapseTo = it->dst;
				}
			}
		}
	}

	void LodCollapseCostProfiler::injectProfile( LodData* data)
	{
		mHasProfile.clear();
		mHasProfile.resize(data->mVertexList.size(), false);
		LodProfile::iterator it = mProfile.begin();
		LodProfile::iterator itEnd = mProfile.end();
		for(;it != itEnd;it++){
			LodData::Vertex v;
			v.position = it->src;
			LodData::UniqueVertexSet::iterator src = data->mUniqueVertexSet.find(&v);
			assert(src != data->mUniqueVertexSet.end());
			mHasProfile[LodData::getVectorIDFromPointer(data->mVertexList, *src)] = true;
			v.position = it->dst;
			LodData::UniqueVertexSet::iterator dst = data->mUniqueVertexSet.find(&v);
			ProfiledEdge e;
			e.dst = *dst;
			e.cost = it->cost;
			OgreAssert(e.cost >= 0 && e.cost != LodData::UNINITIALIZED_COLLAPSE_COST, "Invalid collapse cost");
			mProfileLookup.insert(ProfileLookup::value_type(*src, e));
		}
	}

	void LodCollapseCostProfiler::initCollapseCosts( LodData* data )
	{
		injectProfile(data);
		mProfile.clear();
		mCostCalculator->initCollapseCosts(data);
	}

}

<commit_msg>Add assert if profiled destination point is invalid.<commit_after>/*
 * -----------------------------------------------------------------------------
 * This source file is part of OGRE
 * (Object-oriented Graphics Rendering Engine)
 * For the latest info, see http://www.ogre3d.org/
 *
 * Copyright (c) 2000-2013 Torus Knot Software Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * -----------------------------------------------------------------------------
 */

#include "OgreLodCollapseCostProfiler.h"

namespace Ogre
{

	Real LodCollapseCostProfiler::computeEdgeCollapseCost( LodData* data, LodData::Vertex* src, LodData::Edge* dstEdge )
	{
		OgreAssert(0, "Only computeVertexCollapseCost should call this function.");
		return 0;
	}

	void LodCollapseCostProfiler::computeVertexCollapseCost( LodData* data, LodData::Vertex* vertex, Real& collapseCost, LodData::Vertex*& collapseTo )
	{
		LodData::VEdges::iterator it = vertex->edges.begin();
		if(!mHasProfile[LodData::getVectorIDFromPointer(data->mVertexList, vertex)]){
			for (; it != vertex->edges.end(); it++) {
				it->collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &*it);
				if (collapseCost > it->collapseCost) {
					collapseCost = it->collapseCost;
					collapseTo = it->dst;
				}
			}
		} else {
			std::pair<ProfileLookup::iterator, ProfileLookup::iterator> ret = mProfileLookup.equal_range(vertex);
			for (; it != vertex->edges.end(); it++) {
				it->collapseCost = LodData::UNINITIALIZED_COLLAPSE_COST;
				for(ProfileLookup::iterator it2 = ret.first; it2 != ret.second; it2++){
					if(it2->second.dst == it->dst ){
						it->collapseCost = it2->second.cost;
						break;
					}
				}
				if(it->collapseCost == LodData::UNINITIALIZED_COLLAPSE_COST){
					it->collapseCost = mCostCalculator->computeEdgeCollapseCost(data, vertex, &*it);
				}
				if (collapseCost > it->collapseCost) {
					collapseCost = it->collapseCost;
					collapseTo = it->dst;
				}
			}
		}
	}

	void LodCollapseCostProfiler::injectProfile( LodData* data)
	{
		mHasProfile.clear();
		mHasProfile.resize(data->mVertexList.size(), false);
		LodProfile::iterator it = mProfile.begin();
		LodProfile::iterator itEnd = mProfile.end();
		for(;it != itEnd;it++){
			LodData::Vertex v;
			v.position = it->src;
			LodData::UniqueVertexSet::iterator src = data->mUniqueVertexSet.find(&v);
			OgreAssert(src != data->mUniqueVertexSet.end(), "Invalid vertex position in Lod profile");
			mHasProfile[LodData::getVectorIDFromPointer(data->mVertexList, *src)] = true;
			v.position = it->dst;
			LodData::UniqueVertexSet::iterator dst = data->mUniqueVertexSet.find(&v);
			OgreAssert(dst != data->mUniqueVertexSet.end(), "Invalid vertex position in Lod profile");
			ProfiledEdge e;
			e.dst = *dst;
			e.cost = it->cost;
			OgreAssert(e.cost >= 0 && e.cost != LodData::UNINITIALIZED_COLLAPSE_COST, "Invalid collapse cost");
			mProfileLookup.insert(ProfileLookup::value_type(*src, e));
		}
	}

	void LodCollapseCostProfiler::initCollapseCosts( LodData* data )
	{
		injectProfile(data);
		mProfile.clear();
		mCostCalculator->initCollapseCosts(data);
	}

}

<|endoftext|>


<commit_before>/* httprequest.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of tntnet.

Tntnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

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

You should have received a copy of the GNU General Public License
along with tntnet; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include <tnt/httprequest.h>
#include <tnt/httpparser.h>
#include <sstream>
#include <cxxtools/log.h>
#include <cxxtools/thread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <tnt/sessionscope.h>
#include <errno.h>
#include "config.h"

namespace tnt
{
  log_define("tntnet.httprequest")

  ////////////////////////////////////////////////////////////////////////
  // HttpRequest
  //
  unsigned HttpRequest::serial_ = 0;

  HttpRequest::HttpRequest(const std::string& url)
    : ssl(false),
      locale_init(false),
      requestScope(0),
      applicationScope(0),
      sessionScope(0),
      applicationScopeLocked(false),
      sessionScopeLocked(false)
  {
    std::istringstream s("GET " + url + " HTTP/1.1\r\n\r\n");
    parse(s);
  }

  HttpRequest::HttpRequest(const HttpRequest& r)
    : pathinfo(r.pathinfo),
      args(r.args),
      qparam(r.qparam),
      peerAddr(r.peerAddr),
      serverAddr(r.serverAddr),
      ct(r.ct),
      mp(r.mp),
      ssl(r.ssl),
      serial(r.serial),
      locale_init(r.locale_init),
      locale(r.locale),
      requestScope(r.requestScope),
      applicationScope(r.applicationScope),
      sessionScope(r.sessionScope),
      applicationScopeLocked(false),
      sessionScopeLocked(false)
  {
    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();
  }

  HttpRequest::~HttpRequest()
  {
    releaseLocks();

    if (requestScope)
      requestScope->release();
    if (applicationScope)
      applicationScope->release();
    if (sessionScope)
      sessionScope->release();
  }

  HttpRequest& HttpRequest::operator= (const HttpRequest& r)
  {
    pathinfo = r.pathinfo;
    args = r.args;
    qparam = r.qparam;
    peerAddr = r.peerAddr;
    serverAddr = r.serverAddr;
    ct = r.ct;
    mp = r.mp;
    ssl = r.ssl;
    serial = r.serial;
    locale_init = r.locale_init;
    locale = r.locale;
    requestScope = r.requestScope;
    applicationScope = r.applicationScope;
    sessionScope = r.sessionScope;
    applicationScopeLocked = false;
    sessionScopeLocked = false;

    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();

    return *this;
  }

  void HttpRequest::clear()
  {
    HttpMessage::clear();
    pathinfo.clear();
    args.clear();
    qparam.clear();
    ct = Contenttype();
    mp = Multipart();
    locale_init = false;
    if (requestScope)
    {
      requestScope->release();
      requestScope = 0;
    }
    httpcookies.clear();
    encodingRead = false;

    releaseLocks();

    if (applicationScope)
    {
      applicationScope->release();
      applicationScope = 0;
    }

    if (sessionScope)
    {
      sessionScope->release();
      sessionScope = 0;
    }
  }

  void HttpRequest::parse(std::istream& in)
  {
    Parser p(*this);
    p.parse(in);
    if (!p.failed())
      doPostParse();
  }

  void HttpRequest::doPostParse()
  {
    qparam.parse_url(getQueryString());
    if (getMethod() == "POST")
    {
      std::istringstream in(getHeader(httpheader::contentType));
      in >> ct;

      if (in)
      {
        log_debug(httpheader::contentType << ' ' << in.str());
        log_debug("type=" << ct.getType() << " subtype=" << ct.getSubtype());
        if (ct.isMultipart())
        {
          log_debug("multipart-boundary=" << ct.getBoundary());
          mp.set(ct.getBoundary(), getBody());
          for (Multipart::const_iterator it = mp.begin();
               it != mp.end(); ++it)
          {
            // hochgeladene Dateien nicht in qparam übernehmen
            if (it->getFilename().empty())
            {
              std::string multipartBody(it->getBodyBegin(), it->getBodyEnd());
              log_debug("multipart-item name=" << it->getName()
                     << " body=" << multipartBody);
              qparam.add(it->getName(), multipartBody);
            }
          }
        }
        else
        {
          qparam.parse_url(getBody());
        }
      }
      else if (ct.getType() == "application"
            && ct.getSubtype() == "x-www-form-urlencoded")
        qparam.parse_url(getBody());
    }

    {
      static cxxtools::Mutex monitor;
      cxxtools::MutexLock lock(monitor);
      serial = ++serial_;
    }
  }

  std::string HttpRequest::getPeerIp() const
  {
#ifdef HAVE_INET_NTOP
    char buffer[32];
    const char* r = inet_ntop(AF_INET,
                              &(peerAddr.sin_addr),
                              buffer,
                              sizeof(buffer));
    if (r == 0)
    {
      std::ostringstream msg;
      msg << "error " << errno << " in inet_ntop: " << strerror(errno);
      throw std::runtime_error(msg.str());
    }
    return std::string(buffer);
#else
    static cxxtools::Mutex monitor;
    cxxtools::MutexLock lock(monitor);

    char* p = inet_ntoa(peerAddr.sin_addr);
    return std::string(p);
#endif
  }

  std::string HttpRequest::getServerIp() const
  {
    static cxxtools::Mutex monitor;
    cxxtools::MutexLock lock(monitor);

    char* p = inet_ntoa(serverAddr.sin_addr);
    return std::string(p);
  }

  const std::locale& HttpRequest::getLocale() const
  {
    if (!locale_init)
    {
      static const std::string LANG = "LANG";
      static const std::locale stdlocale("");

      locale_init = true;

      log_debug("HttpRequest::getLocale() " << qparam.dump());

      std::string lang = qparam[LANG];

      if (lang.empty() || lang == stdlocale.name())
        return stdlocale;
      else
      {
        log_debug("LANG from query-parameter");
        try
        {
          locale = std::locale(lang.c_str());
        }
        catch (const std::exception& e)
        {
          log_warn("unknown locale " << LANG);
          return stdlocale;
        }
      }

      log_debug("LANG=" << locale.name());
    }

    return locale;
  }

  const Cookies& HttpRequest::getCookies() const
  {
    log_debug("HttpRequest::getCookies()");

    if (!httpcookies.hasCookies())
    {
      log_debug("cookies found");

      header_type::const_iterator it = header.find(httpheader::cookie);
      if (it != header.end())
      {
        log_debug("parse cookie-header " << it->second);
        const_cast<HttpRequest*>(this)->httpcookies.set(it->second);
      }
    }

    return httpcookies;
  }

  const Encoding& HttpRequest::getEncoding() const
  {
    if (!encodingRead)
    {
      encoding.parse(getHeader(httpheader::acceptEncoding));
      encodingRead = true;
    }
    return encoding;
  }

  namespace
  {
    class CompareNoCase
    {
      public:
        bool operator() (char c1, char c2) const
          { return tolower(c1) == tolower(c2); }
    };
  }

  bool HttpRequest::keepAlive() const
  {
    header_type::const_iterator it = header.find(httpheader::connection);
    return it == header.end() ? getMajorVersion() == 1 && getMinorVersion() == 1
                              : it->second.size() >= httpheader::connectionKeepAlive.size()
                                && std::equal(it->second.begin(),
                                              it->second.end(),
                                              httpheader::connectionKeepAlive.begin(),
                                              CompareNoCase());
  }

  void HttpRequest::setApplicationScope(Scope* s)
  {
    if (applicationScope)
    {
      releaseApplicationScopeLock();
      applicationScope->release();
    }

    if (s)
      s->addRef();
    applicationScope = s;
  }

  void HttpRequest::setSessionScope(Sessionscope* s)
  {
    if (sessionScope)
    {
      releaseSessionScopeLock();
      sessionScope->release();
    }

    if (s)
      s->addRef();
    sessionScope = s;
  }

  void HttpRequest::clearSession()
  {
    if (sessionScope)
    {
      releaseSessionScopeLock();
      sessionScope->release();
      sessionScope = 0;
    }
  }

  void HttpRequest::ensureApplicationScopeLock()
  {
    log_trace("ensureApplicationScopeLock; thread " << pthread_self());

    ensureSessionScopeLock();
    if (applicationScope && !applicationScopeLocked)
    {
      log_debug("lock application scope; thread" << pthread_self());
      applicationScope->lock();
      applicationScopeLocked = true;
    }
    else
      log_debug("applicationscope locked already");
  }

  void HttpRequest::ensureSessionScopeLock()
  {
    log_trace("ensureSessionScopeLock; thread " << pthread_self());

    if (sessionScope && !sessionScopeLocked)
    {
      log_debug("lock sessionscope; thread " << pthread_self());
      sessionScope->lock();
      sessionScopeLocked = true;
    }
    else
      log_debug("sessionscope locked already");
  }

  void HttpRequest::releaseApplicationScopeLock()
  {
    log_trace("releaseApplicationScopeLock; thread " << pthread_self());

    if (applicationScope && applicationScopeLocked)
    {
      log_debug("unlock applicationscope");
      applicationScopeLocked = false;
      applicationScope->unlock();
    }
    else
      log_debug("applicationscope not locked");
  }

  void HttpRequest::releaseSessionScopeLock()
  {
    log_trace("releaseSessionScopeLock; thread " << pthread_self());

    releaseApplicationScopeLock();

    if (sessionScope && sessionScopeLocked)
    {
      log_debug("unlock sessionscope");
      sessionScopeLocked = false;
      sessionScope->unlock();
    }
    else
      log_debug("sessionscope not locked");
  }

  Scope& HttpRequest::getRequestScope()
  {
    if (requestScope == 0)
      requestScope = new Scope();
    return *requestScope;
  }

  Scope& HttpRequest::getApplicationScope()
  {
    ensureApplicationScopeLock();
    return *applicationScope;
  }

  Sessionscope& HttpRequest::getSessionScope()
  {
    if (!sessionScope)
      sessionScope = new Sessionscope();
    ensureSessionScopeLock();
    return *sessionScope;
  }

  bool HttpRequest::hasSessionScope() const
  {
    return sessionScope != 0 && !sessionScope->empty();
  }
}

<commit_msg>locale-cache<commit_after>/* httprequest.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of tntnet.

Tntnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

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

You should have received a copy of the GNU General Public License
along with tntnet; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include <tnt/httprequest.h>
#include <tnt/httpparser.h>
#include <sstream>
#include <cxxtools/log.h>
#include <cxxtools/thread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <tnt/sessionscope.h>
#include <errno.h>
#include "config.h"

namespace tnt
{
  log_define("tntnet.httprequest")

  ////////////////////////////////////////////////////////////////////////
  // HttpRequest
  //
  unsigned HttpRequest::serial_ = 0;

  HttpRequest::HttpRequest(const std::string& url)
    : ssl(false),
      locale_init(false),
      requestScope(0),
      applicationScope(0),
      sessionScope(0),
      applicationScopeLocked(false),
      sessionScopeLocked(false)
  {
    std::istringstream s("GET " + url + " HTTP/1.1\r\n\r\n");
    parse(s);
  }

  HttpRequest::HttpRequest(const HttpRequest& r)
    : pathinfo(r.pathinfo),
      args(r.args),
      qparam(r.qparam),
      peerAddr(r.peerAddr),
      serverAddr(r.serverAddr),
      ct(r.ct),
      mp(r.mp),
      ssl(r.ssl),
      serial(r.serial),
      locale_init(r.locale_init),
      locale(r.locale),
      requestScope(r.requestScope),
      applicationScope(r.applicationScope),
      sessionScope(r.sessionScope),
      applicationScopeLocked(false),
      sessionScopeLocked(false)
  {
    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();
  }

  HttpRequest::~HttpRequest()
  {
    releaseLocks();

    if (requestScope)
      requestScope->release();
    if (applicationScope)
      applicationScope->release();
    if (sessionScope)
      sessionScope->release();
  }

  HttpRequest& HttpRequest::operator= (const HttpRequest& r)
  {
    pathinfo = r.pathinfo;
    args = r.args;
    qparam = r.qparam;
    peerAddr = r.peerAddr;
    serverAddr = r.serverAddr;
    ct = r.ct;
    mp = r.mp;
    ssl = r.ssl;
    serial = r.serial;
    locale_init = r.locale_init;
    locale = r.locale;
    requestScope = r.requestScope;
    applicationScope = r.applicationScope;
    sessionScope = r.sessionScope;
    applicationScopeLocked = false;
    sessionScopeLocked = false;

    if (requestScope)
      requestScope->addRef();
    if (applicationScope)
      applicationScope->addRef();
    if (sessionScope)
      sessionScope->addRef();

    return *this;
  }

  void HttpRequest::clear()
  {
    HttpMessage::clear();
    pathinfo.clear();
    args.clear();
    qparam.clear();
    ct = Contenttype();
    mp = Multipart();
    locale_init = false;
    if (requestScope)
    {
      requestScope->release();
      requestScope = 0;
    }
    httpcookies.clear();
    encodingRead = false;

    releaseLocks();

    if (applicationScope)
    {
      applicationScope->release();
      applicationScope = 0;
    }

    if (sessionScope)
    {
      sessionScope->release();
      sessionScope = 0;
    }
  }

  void HttpRequest::parse(std::istream& in)
  {
    Parser p(*this);
    p.parse(in);
    if (!p.failed())
      doPostParse();
  }

  void HttpRequest::doPostParse()
  {
    qparam.parse_url(getQueryString());
    if (getMethod() == "POST")
    {
      std::istringstream in(getHeader(httpheader::contentType));
      in >> ct;

      if (in)
      {
        log_debug(httpheader::contentType << ' ' << in.str());
        log_debug("type=" << ct.getType() << " subtype=" << ct.getSubtype());
        if (ct.isMultipart())
        {
          log_debug("multipart-boundary=" << ct.getBoundary());
          mp.set(ct.getBoundary(), getBody());
          for (Multipart::const_iterator it = mp.begin();
               it != mp.end(); ++it)
          {
            // hochgeladene Dateien nicht in qparam übernehmen
            if (it->getFilename().empty())
            {
              std::string multipartBody(it->getBodyBegin(), it->getBodyEnd());
              log_debug("multipart-item name=" << it->getName()
                     << " body=" << multipartBody);
              qparam.add(it->getName(), multipartBody);
            }
          }
        }
        else
        {
          qparam.parse_url(getBody());
        }
      }
      else if (ct.getType() == "application"
            && ct.getSubtype() == "x-www-form-urlencoded")
        qparam.parse_url(getBody());
    }

    {
      static cxxtools::Mutex monitor;
      cxxtools::MutexLock lock(monitor);
      serial = ++serial_;
    }
  }

  std::string HttpRequest::getPeerIp() const
  {
#ifdef HAVE_INET_NTOP
    char buffer[32];
    const char* r = inet_ntop(AF_INET,
                              &(peerAddr.sin_addr),
                              buffer,
                              sizeof(buffer));
    if (r == 0)
    {
      std::ostringstream msg;
      msg << "error " << errno << " in inet_ntop: " << strerror(errno);
      throw std::runtime_error(msg.str());
    }
    return std::string(buffer);
#else
    static cxxtools::Mutex monitor;
    cxxtools::MutexLock lock(monitor);

    char* p = inet_ntoa(peerAddr.sin_addr);
    return std::string(p);
#endif
  }

  std::string HttpRequest::getServerIp() const
  {
    static cxxtools::Mutex monitor;
    cxxtools::MutexLock lock(monitor);

    char* p = inet_ntoa(serverAddr.sin_addr);
    return std::string(p);
  }

  const std::locale& HttpRequest::getLocale() const
  {
    if (!locale_init)
    {
      static const std::string LANG = "LANG";
      static const std::locale stdlocale("");
      typedef std::map<std::string, std::locale> locale_map_type;
      static locale_map_type locale_map;
      static cxxtools::Mutex locale_monitor;

      locale_init = true;

      log_debug("HttpRequest::getLocale() " << qparam.dump());

      std::string lang = qparam[LANG];

      if (lang.empty() || lang == stdlocale.name())
        return stdlocale;
      else
      {
        log_debug("LANG from query-parameter");
        try
        {
          cxxtools::MutexLock lock(locale_monitor);
          locale_map_type::const_iterator it = locale_map.find(lang);
          if (it == locale_map.end())
          {
            locale = std::locale(lang.c_str());
            locale_map.insert(locale_map_type::value_type(lang, locale));
          }
          else
            locale = it->second;
        }
        catch (const std::exception& e)
        {
          log_warn("unknown locale " << LANG);
          return stdlocale;
        }
      }

      log_debug("LANG=" << locale.name());
    }

    return locale;
  }

  const Cookies& HttpRequest::getCookies() const
  {
    log_debug("HttpRequest::getCookies()");

    if (!httpcookies.hasCookies())
    {
      log_debug("cookies found");

      header_type::const_iterator it = header.find(httpheader::cookie);
      if (it != header.end())
      {
        log_debug("parse cookie-header " << it->second);
        const_cast<HttpRequest*>(this)->httpcookies.set(it->second);
      }
    }

    return httpcookies;
  }

  const Encoding& HttpRequest::getEncoding() const
  {
    if (!encodingRead)
    {
      encoding.parse(getHeader(httpheader::acceptEncoding));
      encodingRead = true;
    }
    return encoding;
  }

  namespace
  {
    class CompareNoCase
    {
      public:
        bool operator() (char c1, char c2) const
          { return tolower(c1) == tolower(c2); }
    };
  }

  bool HttpRequest::keepAlive() const
  {
    header_type::const_iterator it = header.find(httpheader::connection);
    return it == header.end() ? getMajorVersion() == 1 && getMinorVersion() == 1
                              : it->second.size() >= httpheader::connectionKeepAlive.size()
                                && std::equal(it->second.begin(),
                                              it->second.end(),
                                              httpheader::connectionKeepAlive.begin(),
                                              CompareNoCase());
  }

  void HttpRequest::setApplicationScope(Scope* s)
  {
    if (applicationScope)
    {
      releaseApplicationScopeLock();
      applicationScope->release();
    }

    if (s)
      s->addRef();
    applicationScope = s;
  }

  void HttpRequest::setSessionScope(Sessionscope* s)
  {
    if (sessionScope)
    {
      releaseSessionScopeLock();
      sessionScope->release();
    }

    if (s)
      s->addRef();
    sessionScope = s;
  }

  void HttpRequest::clearSession()
  {
    if (sessionScope)
    {
      releaseSessionScopeLock();
      sessionScope->release();
      sessionScope = 0;
    }
  }

  void HttpRequest::ensureApplicationScopeLock()
  {
    log_trace("ensureApplicationScopeLock; thread " << pthread_self());

    ensureSessionScopeLock();
    if (applicationScope && !applicationScopeLocked)
    {
      log_debug("lock application scope; thread" << pthread_self());
      applicationScope->lock();
      applicationScopeLocked = true;
    }
    else
      log_debug("applicationscope locked already");
  }

  void HttpRequest::ensureSessionScopeLock()
  {
    log_trace("ensureSessionScopeLock; thread " << pthread_self());

    if (sessionScope && !sessionScopeLocked)
    {
      log_debug("lock sessionscope; thread " << pthread_self());
      sessionScope->lock();
      sessionScopeLocked = true;
    }
    else
      log_debug("sessionscope locked already");
  }

  void HttpRequest::releaseApplicationScopeLock()
  {
    log_trace("releaseApplicationScopeLock; thread " << pthread_self());

    if (applicationScope && applicationScopeLocked)
    {
      log_debug("unlock applicationscope");
      applicationScopeLocked = false;
      applicationScope->unlock();
    }
    else
      log_debug("applicationscope not locked");
  }

  void HttpRequest::releaseSessionScopeLock()
  {
    log_trace("releaseSessionScopeLock; thread " << pthread_self());

    releaseApplicationScopeLock();

    if (sessionScope && sessionScopeLocked)
    {
      log_debug("unlock sessionscope");
      sessionScopeLocked = false;
      sessionScope->unlock();
    }
    else
      log_debug("sessionscope not locked");
  }

  Scope& HttpRequest::getRequestScope()
  {
    if (requestScope == 0)
      requestScope = new Scope();
    return *requestScope;
  }

  Scope& HttpRequest::getApplicationScope()
  {
    ensureApplicationScopeLock();
    return *applicationScope;
  }

  Sessionscope& HttpRequest::getSessionScope()
  {
    if (!sessionScope)
      sessionScope = new Sessionscope();
    ensureSessionScopeLock();
    return *sessionScope;
  }

  bool HttpRequest::hasSessionScope() const
  {
    return sessionScope != 0 && !sessionScope->empty();
  }
}

<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
// Author:		Martin Klemsa
//----------------------------------------------------------------------------
#ifndef _ctoolhu_random_generator_included_
#define _ctoolhu_random_generator_included_

#include "engine.hpp"
#include <boost/random/variate_generator.hpp>
#include <boost/random/uniform_smallint.hpp>

#ifdef _DEBUG_RAND
#include <ctoolhu/event/events.h>
#include <ctoolhu/event/firer.hpp>
#endif

namespace Ctoolhu {

	namespace Random {

		//shortcut for the generator template we'll be using
		template <class Distribution>
		using RandomGenerator = boost::variate_generator<Private::RandomEngine &, Distribution>;

		//generator with run-time bounds
		template <
			class Distribution,
			typename Boundary = int
		>
		class Generator : public RandomGenerator<Distribution> {

			typedef RandomGenerator<Distribution> base_type;

		  public:

			//for number generators
			Generator(Boundary lower, Boundary upper)
				: base_type(Private::SingleRandomEngine::Instance(), Distribution(lower, upper)) {}

			//for bool generator
			Generator()
				: base_type(Private::SingleRandomEngine::Instance(), Distribution()) {}

#ifdef _DEBUG_RAND
			result_type operator()()
			{
				auto res = this->base_type::operator()();
				Event::Fire(Event::Message{"random: " + to_string(res)});
				return res;
			}
#endif
		};

		//generator with compile-time bounds
		template <
			int LowerBound,
			int UpperBound,
			class Distribution = std::uniform_int_distribution<>
		>
		class StaticGenerator : public RandomGenerator<Distribution> {

		  public:

			StaticGenerator()
				: RandomGenerator<Distribution>(Private::SingleRandomEngine::Instance(), Distribution(LowerBound, UpperBound)) {}
		};

		//expose typical usages of the dynamic generator
		typedef Generator<std::uniform_int_distribution<>>	IntGenerator;
		typedef Generator<boost::uniform_smallint<>>		SmallIntGenerator;
		typedef Generator<std::uniform_real_distribution<float>, float>	FloatGenerator;
		typedef Generator<std::bernoulli_distribution>		BoolGenerator;

	} //ns Random

} //ns Ctoolhu

#endif
<commit_msg>corrected std usage and headers in random generator<commit_after>//----------------------------------------------------------------------------
// Author:		Martin Klemsa
//----------------------------------------------------------------------------
#ifndef _ctoolhu_random_generator_included_
#define _ctoolhu_random_generator_included_

#include "engine.hpp"
#include <boost/random/variate_generator.hpp>
#include <boost/random/uniform_smallint.hpp>

#ifdef _DEBUG_RAND
#include <ctoolhu/event/events.h>
#include <ctoolhu/event/firer.hpp>
#include <string>
#endif

namespace Ctoolhu {

	namespace Random {

		//shortcut for the generator template we'll be using
		template <class Distribution>
		using RandomGenerator = boost::variate_generator<Private::RandomEngine &, Distribution>;

		//generator with run-time bounds
		template <
			class Distribution,
			typename Boundary = int
		>
		class Generator : public RandomGenerator<Distribution> {

			typedef RandomGenerator<Distribution> base_type;

		  public:

			//for number generators
			Generator(Boundary lower, Boundary upper)
				: base_type(Private::SingleRandomEngine::Instance(), Distribution(lower, upper)) {}

			//for bool generator
			Generator()
				: base_type(Private::SingleRandomEngine::Instance(), Distribution()) {}

#ifdef _DEBUG_RAND
			result_type operator()()
			{
				auto res = this->base_type::operator()();
				Event::Fire(Event::Message{"random: " + std::to_string(res)});
				return res;
			}
#endif
		};

		//generator with compile-time bounds
		template <
			int LowerBound,
			int UpperBound,
			class Distribution = std::uniform_int_distribution<>
		>
		class StaticGenerator : public RandomGenerator<Distribution> {

		  public:

			StaticGenerator()
				: RandomGenerator<Distribution>(Private::SingleRandomEngine::Instance(), Distribution(LowerBound, UpperBound)) {}
		};

		//expose typical usages of the dynamic generator
		typedef Generator<std::uniform_int_distribution<>>	IntGenerator;
		typedef Generator<boost::uniform_smallint<>>		SmallIntGenerator;
		typedef Generator<std::uniform_real_distribution<float>, float>	FloatGenerator;
		typedef Generator<std::bernoulli_distribution>		BoolGenerator;

	} //ns Random

} //ns Ctoolhu

#endif
<|endoftext|>


<commit_before>#include "common.h"
#include "metrix.h"

template <
    int grid_size

  , int baselines
  , int timesteps
  , int channels
  , bool is_half_gcf
  >
// grid must be initialized to 0s.
void gridKernel_scatter(
    // We have a [w_planes][over][over]-shaped array of pointers to
    // variable-sized gcf layers, but we precompute (in pregrid)
    // exact index into this array, thus we use plain pointer here
    const complexd * gcf
  , Double4c grid[grid_size][grid_size]
  // , const Pregridded uvw[baselines][timesteps][channels]
  // , const Double4c vis[baselines][timesteps][channels]
  , const Pregridded uvw[baselines * timesteps * channels]
  , const Double4c vis[baselines * timesteps * channels]
  ) {
  for (int sv = 0; /* see CHECK_SUPP comment */ ; sv++) { // Moved from 2-levels below according to Romein
    for (int i = 0; i < baselines * timesteps * channels; i++) {
      const int
        max_supp_here = uvw[i].gcf_layer_supp;

      if (sv > max_supp_here)
        return; // CHECK_SUPP

#ifdef __AVX__
      // We port Romein CPU code to doubles here (for MS2 we didn't)
      // vis0 covers XX and XY, vis1 -- YX and YY
      __m256d vis0 = _mm256_load_pd((const double *) &vis[i].XX);
      __m256d vis1 = _mm256_load_pd((const double *) &vis[i].YX);
#endif

      for (int su = 0; su <= max_supp_here; su++) {
      // NOTE: Romein writes about moving this to the very outer scope
      // (2 levels up) to make things more cache-friendly.
      // I don't know whether it is cache frendly
      // but what I definitely see gcc generates 4-times shorter code for it!
      // We need to investigate this!
      // for (int sv = 0; sv < max_supp_here; sv++) {
        // Don't forget our u v are already translated by -max_supp_here/2
        int gsu, gsv;
        gsu = uvw[i].u + su;
        gsv = uvw[i].v + sv;

        complexd supportPixel;
        #define __layeroff su * max_supp_here + sv
        if (is_half_gcf) {
          int index = uvw[i].gcf_layer_index;
          // Negative index indicates that original w was mirrored
          // and we shall negate the index to obtain correct
          // offset *and* conjugate the result.
          if (index < 0) {
            supportPixel = conj((gcf - index)[__layeroff]);
          } else {
            supportPixel = (gcf + index)[__layeroff];
          }
        } else {
            supportPixel = (gcf + uvw[i].gcf_layer_index)[__layeroff];
        }

#ifdef __AVX__
        __m256d weight_r = _mm256_set1_pd(supportPixel.real());
        __m256d weight_i = _mm256_set1_pd(supportPixel.imag());

        /* _mm256_permute_pd(x, 5) swaps adjacent doubles pairs of x:
           d0, d1, d2, d3 goes to d1, d0, d3, d2
         */
        #define __DO(p,f)                                     \
        __m256d * gridptr##p = (__m256d *) &grid[gsu][gsv].f; \
        __m256d tr##p = _mm256_mul_pd(weight_r, vis##p);      \
        __m256d ti##p = _mm256_mul_pd(weight_i, vis##p);      \
        __m256d tp##p = _mm256_permute_pd(ti##p, 5);          \
        __m256d t##p = _mm256_addsub_pd(tr##p, tp##p);        \
        gridptr##p[p] = _mm256_add_pd(gridptr##p[p], t##p)

        __DO(0, XX);
        __DO(1, YX);
#else
        #define __GRID_POL(pol) grid[gsu][gsv].pol += vis[i].pol * supportPixel
        __GRID_POL(XX);
        __GRID_POL(XY);
        __GRID_POL(YX);
        __GRID_POL(YY);
#endif
      }
    }
  }
}

// Test instantiation
void gridKernel_scatter1(
    const complexd * gcf
  , Double4c grid[GRID_SIZE][GRID_SIZE]
  , const Pregridded uvw[BASELINES * TIMESTEPS * CHANNELS]
  , const Double4c vis[BASELINES * TIMESTEPS * CHANNELS]
  ){
  gridKernel_scatter<GRID_SIZE, BASELINES, TIMESTEPS, CHANNELS, false>(gcf, grid, uvw, vis);
  }
<commit_msg>Assignment instead of initialization for CPU.<commit_after>#include "common.h"
#include "metrix.h"

template <
    int grid_size

  , int baselines
  , int timesteps
  , int channels
  , bool is_half_gcf
  >
// grid must be initialized to 0s.
void gridKernel_scatter(
    // We have a [w_planes][over][over]-shaped array of pointers to
    // variable-sized gcf layers, but we precompute (in pregrid)
    // exact index into this array, thus we use plain pointer here
    const complexd * gcf
  , Double4c grid[grid_size][grid_size]
  // , const Pregridded uvw[baselines][timesteps][channels]
  // , const Double4c vis[baselines][timesteps][channels]
  , const Pregridded uvw[baselines * timesteps * channels]
  , const Double4c vis[baselines * timesteps * channels]
  ) {
  for (int sv = 0; /* see CHECK_SUPP comment */ ; sv++) { // Moved from 2-levels below according to Romein
    for (int i = 0; i < baselines * timesteps * channels; i++) {
      const int
        max_supp_here = uvw[i].gcf_layer_supp;

      if (sv > max_supp_here)
        return; // CHECK_SUPP

#ifdef __AVX__
      // We port Romein CPU code to doubles here (for MS2 we didn't)
      // vis0 covers XX and XY, vis1 -- YX and YY
      __m256d vis0, vis1;
      vis0 = _mm256_load_pd((const double *) &vis[i].XX);
      vis1 = _mm256_load_pd((const double *) &vis[i].YX);
#endif

      for (int su = 0; su <= max_supp_here; su++) {
      // NOTE: Romein writes about moving this to the very outer scope
      // (2 levels up) to make things more cache-friendly.
      // I don't know whether it is cache frendly
      // but what I definitely see gcc generates 4-times shorter code for it!
      // We need to investigate this!
      // for (int sv = 0; sv < max_supp_here; sv++) {
        // Don't forget our u v are already translated by -max_supp_here/2
        int gsu, gsv;
        gsu = uvw[i].u + su;
        gsv = uvw[i].v + sv;

        complexd supportPixel;
        #define __layeroff su * max_supp_here + sv
        if (is_half_gcf) {
          int index;
          index = uvw[i].gcf_layer_index;
          // Negative index indicates that original w was mirrored
          // and we shall negate the index to obtain correct
          // offset *and* conjugate the result.
          if (index < 0) {
            supportPixel = conj((gcf - index)[__layeroff]);
          } else {
            supportPixel = (gcf + index)[__layeroff];
          }
        } else {
            supportPixel = (gcf + uvw[i].gcf_layer_index)[__layeroff];
        }

#ifdef __AVX__
        __m256d weight_r, weight_i;
        weight_r = _mm256_set1_pd(supportPixel.real());
        weight_i = _mm256_set1_pd(supportPixel.imag());

        /* _mm256_permute_pd(x, 5) swaps adjacent doubles pairs of x:
           d0, d1, d2, d3 goes to d1, d0, d3, d2
         */
        #define __DO(p,f)                                     \
        __m256d * gridptr##p = (__m256d *) &grid[gsu][gsv].f; \
        __m256d tr##p = _mm256_mul_pd(weight_r, vis##p);      \
        __m256d ti##p = _mm256_mul_pd(weight_i, vis##p);      \
        __m256d tp##p = _mm256_permute_pd(ti##p, 5);          \
        __m256d t##p = _mm256_addsub_pd(tr##p, tp##p);        \
        gridptr##p[p] = _mm256_add_pd(gridptr##p[p], t##p)

        __DO(0, XX);
        __DO(1, YX);
#else
        #define __GRID_POL(pol) grid[gsu][gsv].pol += vis[i].pol * supportPixel
        __GRID_POL(XX);
        __GRID_POL(XY);
        __GRID_POL(YX);
        __GRID_POL(YY);
#endif
      }
    }
  }
}

// Test instantiation
void gridKernel_scatter1(
    const complexd * gcf
  , Double4c grid[GRID_SIZE][GRID_SIZE]
  , const Pregridded uvw[BASELINES * TIMESTEPS * CHANNELS]
  , const Double4c vis[BASELINES * TIMESTEPS * CHANNELS]
  ){
  gridKernel_scatter<GRID_SIZE, BASELINES, TIMESTEPS, CHANNELS, false>(gcf, grid, uvw, vis);
  }
<|endoftext|>