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

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// CellML Model Repository widget
//==============================================================================

#include "cellmlmodelrepositorywindowwidget.h"
#include "corecliutils.h"
#include "coreguiutils.h"

//==============================================================================

#include "ui_cellmlmodelrepositorywindowwidget.h"

//==============================================================================

#include <QClipboard>
#include <QDesktopServices>
#include <QIODevice>
#include <QMenu>
#include <QPaintEvent>
#include <QRegularExpression>
#include <QWebElement>
#include <QWebFrame>

//==============================================================================

namespace OpenCOR {
namespace CellMLModelRepositoryWindow {

//==============================================================================

CellmlModelRepositoryWindowWidget::CellmlModelRepositoryWindowWidget(QWidget *pParent) :
    Core::WebViewWidget(pParent),
    Core::CommonWidget(pParent),
    mGui(new Ui::CellmlModelRepositoryWindowWidget),
    mModelNames(QStringList()),
    mErrorMessage(QString()),
    mNumberOfModels(0),
    mNumberOfFilteredModels(0),
    mLink(QString())
{
    // Set up the GUI

    mGui->setupUi(this);

    // Add a small margin ourselves, so that no visual trace of the border drawn
    // by drawBorder() in paintEvent() is left when scrolling (on Windows, but
    // it doesn't harm doing it for all our supported platforms)
    // Note: not sure why, but no matter how many pixels are specified for the
    //       margin, no margin actually exists, but it addresses the issue with
    //       the border drawn by drawBorder()...

    setStyleSheet("QWebView {"
                  "    margin: 1px;"
                  "}");

    // Create and populate our context menu

    mContextMenu = new QMenu(this);

    mContextMenu->addAction(mGui->actionCopy);

    // We want out own context menu

    setContextMenuPolicy(Qt::CustomContextMenu);

    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(showCustomContextMenu(const QPoint &)));

    // Prevent objects from being dropped on us

    setAcceptDrops(false);

    // Have links opened in the user's browser rather than in our list

    page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

    // Some connections

    connect(page(), SIGNAL(linkClicked(const QUrl &)),
            this, SLOT(linkClicked(const QUrl &)));

    // Retrieve the output template

    Core::readTextFromFile(":/output.html", mOutputTemplate);

    setHtml(mOutputTemplate.arg(Core::iconDataUri(":/oxygen/places/folder-downloads.png", 16, 16),
                                Core::iconDataUri(":/oxygen/places/folder-downloads.png", 16, 16, QIcon::Disabled)));
}

//==============================================================================

CellmlModelRepositoryWindowWidget::~CellmlModelRepositoryWindowWidget()
{
    // Delete the GUI

    delete mGui;
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::retranslateUi()
{
    // Retranslate our message

    QWebElement messageElement = page()->mainFrame()->documentElement().findFirst("p[id=message]");

    if (mErrorMessage.isEmpty()) {
        if (!mNumberOfFilteredModels) {
            if (!mNumberOfModels)
                messageElement.removeAllChildren();
            else
                messageElement.setInnerXml(tr("No CellML model matches your criteria."));
        } else if (mNumberOfFilteredModels == 1) {
            messageElement.setInnerXml(tr("1 CellML model was found:"));
        } else {
            messageElement.setInnerXml(tr("%1 CellML models were found:").arg(mNumberOfFilteredModels));
        }
    } else {
        messageElement.setInnerXml(tr("Error: ")+Core::formatMessage(mErrorMessage, true, true));
    }
}

//==============================================================================

QSize CellmlModelRepositoryWindowWidget::sizeHint() const
{
    // Suggest a default size for the CellML Model Repository widget
    // Note: this is critical if we want a docked widget, with a CellML Model
    //       Repository widget on it, to have a decent size when docked to the
    //       main window...

    return defaultSize(0.15);
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::paintEvent(QPaintEvent *pEvent)
{
    // Default handling of the event

    QWebView::paintEvent(pEvent);

    // Draw a border

    drawBorder(
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
               true, true, true, true,
#elif defined(Q_OS_MAC)
               true, false, false, false,
#else
    #error Unsupported platform
#endif
               true, false, false, false
              );
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::initialize(const QStringList &pModelNames,
                                                   const QStringList &pModelUrls,
                                                   const QString &pErrorMessage)
{
    // Keep track of some properties

    mModelNames = pModelNames;
    mErrorMessage = pErrorMessage;

    // Initialise our list of models, unless an error occurred

    if (pErrorMessage.isEmpty()) {
        mNumberOfModels = pModelNames.count();

        if (mNumberOfModels) {
            QString models = QString();

            for (int i = 0; i < mNumberOfModels; ++i) {
                models =  models
                         +"
\n"
                         +"    \n"
                         +"
\n"
                         +"
\n"
                         +"                "+pModelNames[i]+"\n"
                         +"
\n"
                         +"
\n"
                         +"    	\n"
                         +"    \n"
                         +"        \n"
                         +"    	\n"
                         +"
\n";
            }

            QWebElement modelsElement = page()->mainFrame()->documentElement().findFirst("tbody");

            modelsElement.removeAllChildren();
            modelsElement.appendInside(models);
        }
    }
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::filter(const QString &pFilter)
{
    // Make sure that we have something to filter (i.e. no error message)

    if (!mErrorMessage.isEmpty())
        return;

    // Filter our list of models, remove duplicates (they will be reintroduced
    // in the next step) and update our message (by retranslate ourselves)

    QStringList filteredModelNames = mModelNames.filter(QRegularExpression(pFilter, QRegularExpression::CaseInsensitiveOption));

    mNumberOfFilteredModels = filteredModelNames.count();

    filteredModelNames.removeDuplicates();

    retranslateUi();

    // Determine which models should be shown/hidden

    QIntList modelIndexes = QIntList();
    int modelIndex;

    foreach (const QString &filteredModelName, filteredModelNames) {
        modelIndex = -1;

        forever {
            modelIndex = mModelNames.indexOf(filteredModelName, ++modelIndex);

            if (modelIndex == -1)
                break;
            else
                modelIndexes << modelIndex;
        }
    }

    // Show/hide the relevant models

    QWebElement documentElement = page()->mainFrame()->documentElement();

    for (int i = 0, iMax = mModelNames.count(); i < iMax; ++i)
        documentElement.findFirst(QString("tr[id=model_%1]").arg(i)).setStyleProperty("display", modelIndexes.contains(i)?"table-row":"none");
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::on_actionCopy_triggered()
{
    // Copy the URL of the model to the clipboard

    QApplication::clipboard()->setText(mLink);
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::linkClicked(const QUrl &pUrl)
{
    // Retrieve some information about the link

    QString textContent;

    retrieveLinkInformation(mLink, textContent);

    // Check whether we have clicked a model link or a button link, i.e. that we
    // want to clone the model

    if (textContent.isEmpty()) {
        // We have clicked on a button link, so clone the model

qDebug(">>> Cloning %s...", qPrintable(mLink));
    } else {
        // Open the model link in the user's browser

        QDesktopServices::openUrl(pUrl);
    }
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::showCustomContextMenu(const QPoint &pPosition)
{
    Q_UNUSED(pPosition);

    // Retrieve some information about the link, if any

    QString textContent;

    retrieveLinkInformation(mLink, textContent);

    // Show our context menu to allow the copying of the URL of the model, but
    // only if we are over a link, i.e. if both mLink and textContent are not
    // empty

    if (!mLink.isEmpty() && !textContent.isEmpty())
        mContextMenu->exec(QCursor::pos());
}

//==============================================================================

}   // namespace CellMLModelRepositoryWindow
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>PMR window: some work on allowing a workspace to be cloned (#593) [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// CellML Model Repository widget
//==============================================================================

#include "cellmlmodelrepositorywindowwidget.h"
#include "corecliutils.h"
#include "coreguiutils.h"

//==============================================================================

#include "ui_cellmlmodelrepositorywindowwidget.h"

//==============================================================================

#include <QClipboard>
#include <QDesktopServices>
#include <QIODevice>
#include <QMenu>
#include <QPaintEvent>
#include <QRegularExpression>
#include <QWebElement>
#include <QWebFrame>

//==============================================================================

namespace OpenCOR {
namespace CellMLModelRepositoryWindow {

//==============================================================================

CellmlModelRepositoryWindowWidget::CellmlModelRepositoryWindowWidget(QWidget *pParent) :
    Core::WebViewWidget(pParent),
    Core::CommonWidget(pParent),
    mGui(new Ui::CellmlModelRepositoryWindowWidget),
    mModelNames(QStringList()),
    mErrorMessage(QString()),
    mNumberOfModels(0),
    mNumberOfFilteredModels(0),
    mLink(QString())
{
    // Set up the GUI

    mGui->setupUi(this);

    // Add a small margin ourselves, so that no visual trace of the border drawn
    // by drawBorder() in paintEvent() is left when scrolling (on Windows and
    // Linux, but it doesn't harm doing it for all our supported platforms)
    // Note: not sure why, but no matter how many pixels are specified for the
    //       margin, no margin actually exists, but it addresses the issue with
    //       the border drawn by drawBorder()...

    setStyleSheet("QWebView {"
                  "    margin: 1px;"
                  "}");

    // Create and populate our context menu

    mContextMenu = new QMenu(this);

    mContextMenu->addAction(mGui->actionCopy);

    // We want out own context menu

    setContextMenuPolicy(Qt::CustomContextMenu);

    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(showCustomContextMenu(const QPoint &)));

    // Prevent objects from being dropped on us

    setAcceptDrops(false);

    // Have links opened in the user's browser rather than in our list

    page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

    // Some connections

    connect(page(), SIGNAL(linkClicked(const QUrl &)),
            this, SLOT(linkClicked(const QUrl &)));

    // Retrieve the output template

    Core::readTextFromFile(":/output.html", mOutputTemplate);

    setHtml(mOutputTemplate.arg(Core::iconDataUri(":/oxygen/places/folder-downloads.png", 16, 16),
                                Core::iconDataUri(":/oxygen/places/folder-downloads.png", 16, 16, QIcon::Disabled)));
}

//==============================================================================

CellmlModelRepositoryWindowWidget::~CellmlModelRepositoryWindowWidget()
{
    // Delete the GUI

    delete mGui;
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::retranslateUi()
{
    // Retranslate our message

    QWebElement messageElement = page()->mainFrame()->documentElement().findFirst("p[id=message]");

    if (mErrorMessage.isEmpty()) {
        if (!mNumberOfFilteredModels) {
            if (!mNumberOfModels)
                messageElement.removeAllChildren();
            else
                messageElement.setInnerXml(tr("No CellML model matches your criteria."));
        } else if (mNumberOfFilteredModels == 1) {
            messageElement.setInnerXml(tr("1 CellML model was found:"));
        } else {
            messageElement.setInnerXml(tr("%1 CellML models were found:").arg(mNumberOfFilteredModels));
        }
    } else {
        messageElement.setInnerXml(tr("Error: ")+Core::formatMessage(mErrorMessage, true, true));
    }
}

//==============================================================================

QSize CellmlModelRepositoryWindowWidget::sizeHint() const
{
    // Suggest a default size for the CellML Model Repository widget
    // Note: this is critical if we want a docked widget, with a CellML Model
    //       Repository widget on it, to have a decent size when docked to the
    //       main window...

    return defaultSize(0.15);
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::paintEvent(QPaintEvent *pEvent)
{
    // Default handling of the event

    QWebView::paintEvent(pEvent);

    // Draw a border

    drawBorder(
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
               true, true, true, true,
#elif defined(Q_OS_MAC)
               true, false, false, false,
#else
    #error Unsupported platform
#endif
               true, false, false, false
              );
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::initialize(const QStringList &pModelNames,
                                                   const QStringList &pModelUrls,
                                                   const QString &pErrorMessage)
{
    // Keep track of some properties

    mModelNames = pModelNames;
    mErrorMessage = pErrorMessage;

    // Initialise our list of models, unless an error occurred

    if (pErrorMessage.isEmpty()) {
        mNumberOfModels = pModelNames.count();

        if (mNumberOfModels) {
            QString models = QString();

            for (int i = 0; i < mNumberOfModels; ++i) {
                models =  models
                         +"
\n"
                         +"    \n"
                         +"
\n"
                         +"
\n"
                         +"                "+pModelNames[i]+"\n"
                         +"
\n"
                         +"
\n"
                         +"    	\n"
                         +"    \n"
                         +"        \n"
                         +"    	\n"
                         +"
\n";
            }

            QWebElement modelsElement = page()->mainFrame()->documentElement().findFirst("tbody");

            modelsElement.removeAllChildren();
            modelsElement.appendInside(models);
        }
    }
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::filter(const QString &pFilter)
{
    // Make sure that we have something to filter (i.e. no error message)

    if (!mErrorMessage.isEmpty())
        return;

    // Filter our list of models, remove duplicates (they will be reintroduced
    // in the next step) and update our message (by retranslate ourselves)

    QStringList filteredModelNames = mModelNames.filter(QRegularExpression(pFilter, QRegularExpression::CaseInsensitiveOption));

    mNumberOfFilteredModels = filteredModelNames.count();

    filteredModelNames.removeDuplicates();

    retranslateUi();

    // Determine which models should be shown/hidden

    QIntList modelIndexes = QIntList();
    int modelIndex;

    foreach (const QString &filteredModelName, filteredModelNames) {
        modelIndex = -1;

        forever {
            modelIndex = mModelNames.indexOf(filteredModelName, ++modelIndex);

            if (modelIndex == -1)
                break;
            else
                modelIndexes << modelIndex;
        }
    }

    // Show/hide the relevant models

    QWebElement documentElement = page()->mainFrame()->documentElement();

    for (int i = 0, iMax = mModelNames.count(); i < iMax; ++i)
        documentElement.findFirst(QString("tr[id=model_%1]").arg(i)).setStyleProperty("display", modelIndexes.contains(i)?"table-row":"none");
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::on_actionCopy_triggered()
{
    // Copy the URL of the model to the clipboard

    QApplication::clipboard()->setText(mLink);
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::linkClicked(const QUrl &pUrl)
{
    // Retrieve some information about the link

    QString textContent;

    retrieveLinkInformation(mLink, textContent);

    // Check whether we have clicked a model link or a button link, i.e. that we
    // want to clone the model

    if (textContent.isEmpty()) {
        // We have clicked on a button link, so clone the model

qDebug(">>> Cloning %s...", qPrintable(mLink));
    } else {
        // Open the model link in the user's browser

        QDesktopServices::openUrl(pUrl);
    }
}

//==============================================================================

void CellmlModelRepositoryWindowWidget::showCustomContextMenu(const QPoint &pPosition)
{
    Q_UNUSED(pPosition);

    // Retrieve some information about the link, if any

    QString textContent;

    retrieveLinkInformation(mLink, textContent);

    // Show our context menu to allow the copying of the URL of the model, but
    // only if we are over a link, i.e. if both mLink and textContent are not
    // empty

    if (!mLink.isEmpty() && !textContent.isEmpty())
        mContextMenu->exec(QCursor::pos());
}

//==============================================================================

}   // namespace CellMLModelRepositoryWindow
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>#pragma once

#include <string>

#include "blackhole/attribute.hpp"
#include "blackhole/expression/helper.hpp"
#include "blackhole/filter.hpp"
#include "blackhole/utils/underlying.hpp"

namespace blackhole {

namespace expression {

template<typename T, class = void>
struct get_attr_action_t {
    typedef T result_type;

    const std::string name;

    const result_type& operator ()(const log::attributes_t& attributes) const {
        return boost::get<T>(attributes.at(name).value);
    }

    filter_t operator ==(const T& other) const {
        return aux::Eq<get_attr_action_t<T>>({ *this, other });
    }

    filter_t operator <(const T& other) const {
        return aux::Less<get_attr_action_t<T>>({ *this, other });
    }
};

template<typename T>
struct get_attr_action_t<T, typename std::enable_if<std::is_enum<T>::value>::type> {
    typedef typename blackhole::aux::underlying_type<T>::type underlying_type;
    typedef T result_type;

    const std::string name;

    result_type operator ()(const log::attributes_t& attributes) const {
        return static_cast<result_type>(boost::get<underlying_type>(attributes.at(name).value));
    }

    filter_t operator ==(const T& other) const {
        return aux::Eq<get_attr_action_t<T>>({ *this, other });
    }

    filter_t operator <(const T& other) const {
        return aux::Less<get_attr_action_t<T>>({ *this, other });
    }
};

template<typename T>
get_attr_action_t<T> get_attr(const std::string& name) {
    return get_attr_action_t<T>({ name });
}

template<typename T>
get_attr_action_t<typename T::type> get_attr(const T&) {
    return get_attr<typename T::type>(std::string(T::name()));
}

} // namespace expression

} // namespace blackhole
<commit_msg>Minor refactoring.<commit_after>#pragma once

#include <string>

#include "blackhole/attribute.hpp"
#include "blackhole/expression/helper.hpp"
#include "blackhole/filter.hpp"
#include "blackhole/utils/underlying.hpp"

namespace blackhole {

namespace expression {

template<typename T, class = void>
struct get_attr_action_t {
    typedef T result_type;

    const std::string name;

    result_type operator ()(const log::attributes_t& attributes) const {
        return attribute::traits<T>::extract(attributes, name);
    }

    filter_t operator ==(const T& other) const {
        return aux::Eq<get_attr_action_t<T>>({ *this, other });
    }

    filter_t operator <(const T& other) const {
        return aux::Less<get_attr_action_t<T>>({ *this, other });
    }
};

template<typename T>
struct get_attr_action_t<T, typename std::enable_if<std::is_enum<T>::value>::type> {
    typedef T result_type;
    typedef typename blackhole::aux::underlying_type<T>::type underlying_type;

    const std::string name;

    result_type operator ()(const log::attributes_t& attributes) const {
        return attribute::traits<T>::extract(attributes, name);
    }

    filter_t operator ==(const T& other) const {
        return aux::Eq<get_attr_action_t<T>>({ *this, other });
    }

    filter_t operator <(const T& other) const {
        return aux::Less<get_attr_action_t<T>>({ *this, other });
    }
};

template<typename T>
get_attr_action_t<T> get_attr(const std::string& name) {
    return get_attr_action_t<T>({ name });
}

template<typename T>
get_attr_action_t<typename T::type> get_attr(const T&) {
    return get_attr<typename T::type>(std::string(T::name()));
}

} // namespace expression

} // namespace blackhole
<|endoftext|>


<commit_before>#include "../../lower_triangular_solve.hxx"
#include "../../SDP_Solver.hxx"
#include "../../../Timers.hxx"

// Compute the quantities needed to solve the Schur complement
// equation
//
// {{S, -B}, {B^T, 0}} . {dx, dy} = {r, s}
//
// (where S = SchurComplement, B = FreeVarMatrix), using the method
// described in the manual:
//
// - Compute S using BilinearPairingsXInv and BilinearPairingsY.
//
// - Compute the Cholesky decomposition S' = L' L'^T.
//
// - Form B' = (B U) and compute
//
//   - SchurOffDiagonal = L'^{-1} B
//   - L'^{-1} U
//   - Q = (L'^{-1} B')^T (L'^{-1} B') - {{0, 0}, {0, 1}}
//
// - Compute the LU decomposition of Q.
//
// This data is sufficient to efficiently solve the above equation for
// a given r,s.
//
// Inputs:
// - BilinearPairingsXInv, BilinearPairingsY (these are members of
//   SDPSolver, but we include them as arguments to emphasize that
//   they must be computed first)
// Workspace (members of SDPSolver which are modified by this method
// and not used later):
// - SchurComplement
// Outputs (members of SDPSolver which are modified by this method and
// used later):
// - SchurComplementCholesky
// - SchurOffDiagonal
//

void compute_schur_complement(
  const SDP &sdp, const Block_Diagonal_Matrix &bilinear_pairings_X_inv,
  const Block_Diagonal_Matrix &bilinear_pairings_Y,
  Block_Diagonal_Matrix &schur_complement);

void SDP_Solver::initialize_schur_complement_solver(
  const Block_Diagonal_Matrix &bilinear_pairings_X_inv,
  const Block_Diagonal_Matrix &bilinear_pairings_Y,
  const std::vector<size_t> &block_sizes,
  const std::vector<size_t> &block_indices, const size_t &num_schur_blocks,
  const El::Grid &block_grid, const bool &debug,
  Block_Diagonal_Matrix &schur_complement_cholesky,
  Block_Matrix &schur_off_diagonal_block, El::DistMatrix<El::BigFloat> &Q)
{
  // The Schur complement matrix S: a Block_Diagonal_Matrix with one
  // block for each 0 <= j < J.  SchurComplement.blocks[j] has dimension
  // (d_j+1)*m_j*(m_j+1)/2
  //
  Block_Diagonal_Matrix schur_complement(block_sizes, block_indices,
                                         num_schur_blocks, block_grid);

  compute_schur_complement(sdp, bilinear_pairings_X_inv, bilinear_pairings_Y,
                           schur_complement);

  // compute SchurComplementCholesky = L', where
  //
  //   L' L'^T = S'
  //
  if(debug)
    {
      El::Output(
        El::mpi::Rank(),
        " run.step.initializeSchurComplementSolver.choleskyDecomposition");
    }
  timers["run.step.initializeSchurComplementSolver.choleskyDecomposition"]
    .resume();
  cholesky_decomposition(schur_complement, schur_complement_cholesky);
  timers["run.step.initializeSchurComplementSolver.choleskyDecomposition"]
    .stop();

  // SchurOffDiagonal = L'^{-1} FreeVarMatrix
  schur_off_diagonal_block = sdp.free_var_matrix;
  if(debug)
    {
      El::Output(El::mpi::Rank(), " run.step.initializeSchurComplementSolver."
                                  "blockMatrixLowerTriangularSolve");
    }
  timers["run.step.initializeSchurComplementSolver."
         "blockMatrixLowerTriangularSolve"]
    .resume();
  lower_triangular_solve(schur_complement_cholesky, schur_off_diagonal_block);
  timers["run.step.initializeSchurComplementSolver."
         "blockMatrixLowerTriangularSolve"]
    .stop();

  // Next, we compute
  //
  //   Q = (L'^{-1} B')^T (L'^{-1} B') - {{0, 0}, {0, 1}}
  //
  // Where B' = (B U).  We think of Q as containing four blocks called
  // Upper/Lower-Left/Right.

  if(debug)
    {
      El::Output(El::mpi::Rank(),
                 " run.step.initializeSchurComplementSolver.Qcomputation");
    }
  timers["run.step.initializeSchurComplementSolver.Qcomputation"].resume();

  {
    // FIXME: This breaks if no blocks are assigned to this processor
    El::DistMatrix<El::BigFloat> Q_local(
      Q.Height(), Q.Width(), schur_off_diagonal_block.blocks.front().Grid());
    El::Zero(Q_local);
    for(auto &block : schur_off_diagonal_block.blocks)
      {
        El::DistMatrix<El::BigFloat> Q_local_view(
          El::View(Q_local, 0, 0, block.Width(), block.Width()));
        El::Syrk(El::UpperOrLowerNS::UPPER, El::OrientationNS::TRANSPOSE,
                 El::BigFloat(1), block, El::BigFloat(1), Q_local_view);
      }
    El::MakeSymmetric(El::UpperOrLower::UPPER, Q_local);
    El::AllReduce(Q_local, El::mpi::COMM_WORLD);

    for(int64_t row = 0; row < Q.LocalHeight(); ++row)
      {
        int64_t global_row(Q.GlobalRow(row));
        for(int64_t column = 0; column < Q.LocalWidth(); ++column)
          {
            int64_t global_column(Q.GlobalCol(column));
            // FIXME: This assumes that there is one process per block.
            Q.SetLocal(row, column,
                       Q_local.GetLocal(global_row, global_column));
          }
      }
  }
  timers["run.step.initializeSchurComplementSolver.Qcomputation"].stop();

  if(debug)
    {
      El::Output(El::mpi::Rank(),
                 " run.step.initializeSchurComplementSolver.LUDecomposition");
    }
  timers["run.step.initializeSchurComplementSolver.LUDecomposition"].resume();
  Cholesky(El::UpperOrLowerNS::LOWER, Q);
  timers["run.step.initializeSchurComplementSolver.LUDecomposition"].stop();
}
<commit_msg>Make a local copy of Cholesky(Q)<commit_after>#include "../../lower_triangular_solve.hxx"
#include "../../SDP_Solver.hxx"
#include "../../../Timers.hxx"

// Compute the quantities needed to solve the Schur complement
// equation
//
// {{S, -B}, {B^T, 0}} . {dx, dy} = {r, s}
//
// (where S = SchurComplement, B = FreeVarMatrix), using the method
// described in the manual:
//
// - Compute S using BilinearPairingsXInv and BilinearPairingsY.
//
// - Compute the Cholesky decomposition S' = L' L'^T.
//
// - Form B' = (B U) and compute
//
//   - SchurOffDiagonal = L'^{-1} B
//   - L'^{-1} U
//   - Q = (L'^{-1} B')^T (L'^{-1} B') - {{0, 0}, {0, 1}}
//
// - Compute the LU decomposition of Q.
//
// This data is sufficient to efficiently solve the above equation for
// a given r,s.
//
// Inputs:
// - BilinearPairingsXInv, BilinearPairingsY (these are members of
//   SDPSolver, but we include them as arguments to emphasize that
//   they must be computed first)
// Workspace (members of SDPSolver which are modified by this method
// and not used later):
// - SchurComplement
// Outputs (members of SDPSolver which are modified by this method and
// used later):
// - SchurComplementCholesky
// - SchurOffDiagonal
//

void compute_schur_complement(
  const SDP &sdp, const Block_Diagonal_Matrix &bilinear_pairings_X_inv,
  const Block_Diagonal_Matrix &bilinear_pairings_Y,
  Block_Diagonal_Matrix &schur_complement);

void SDP_Solver::initialize_schur_complement_solver(
  const Block_Diagonal_Matrix &bilinear_pairings_X_inv,
  const Block_Diagonal_Matrix &bilinear_pairings_Y,
  const std::vector<size_t> &block_sizes,
  const std::vector<size_t> &block_indices, const size_t &num_schur_blocks,
  const El::Grid &block_grid, const bool &debug,
  Block_Diagonal_Matrix &schur_complement_cholesky,
  Block_Matrix &schur_off_diagonal_block, El::DistMatrix<El::BigFloat> &Q)
{
  // The Schur complement matrix S: a Block_Diagonal_Matrix with one
  // block for each 0 <= j < J.  SchurComplement.blocks[j] has dimension
  // (d_j+1)*m_j*(m_j+1)/2
  //
  Block_Diagonal_Matrix schur_complement(block_sizes, block_indices,
                                         num_schur_blocks, block_grid);

  compute_schur_complement(sdp, bilinear_pairings_X_inv, bilinear_pairings_Y,
                           schur_complement);

  // compute SchurComplementCholesky = L', where
  //
  //   L' L'^T = S'
  //
  if(debug)
    {
      El::Output(
        El::mpi::Rank(),
        " run.step.initializeSchurComplementSolver.choleskyDecomposition");
    }
  timers["run.step.initializeSchurComplementSolver.choleskyDecomposition"]
    .resume();
  cholesky_decomposition(schur_complement, schur_complement_cholesky);
  timers["run.step.initializeSchurComplementSolver.choleskyDecomposition"]
    .stop();

  // SchurOffDiagonal = L'^{-1} FreeVarMatrix
  schur_off_diagonal_block = sdp.free_var_matrix;
  if(debug)
    {
      El::Output(El::mpi::Rank(), " run.step.initializeSchurComplementSolver."
                                  "blockMatrixLowerTriangularSolve");
    }
  timers["run.step.initializeSchurComplementSolver."
         "blockMatrixLowerTriangularSolve"]
    .resume();
  lower_triangular_solve(schur_complement_cholesky, schur_off_diagonal_block);
  timers["run.step.initializeSchurComplementSolver."
         "blockMatrixLowerTriangularSolve"]
    .stop();

  // Next, we compute
  //
  //   Q = (L'^{-1} B')^T (L'^{-1} B') - {{0, 0}, {0, 1}}
  //
  // Where B' = (B U).  We think of Q as containing four blocks called
  // Upper/Lower-Left/Right.

  if(debug)
    {
      El::Output(El::mpi::Rank(),
                 " run.step.initializeSchurComplementSolver.Q_Syrk");
    }
  timers["run.step.initializeSchurComplementSolver.Q_Syrk"].resume();

  // FIXME: This breaks if no blocks are assigned to this processor
  El::DistMatrix<El::BigFloat> Q_local(
    Q.Height(), Q.Width(), schur_off_diagonal_block.blocks.front().Grid());
  El::Zero(Q_local);
  for(auto &block : schur_off_diagonal_block.blocks)
    {
      El::DistMatrix<El::BigFloat> Q_local_view(
        El::View(Q_local, 0, 0, block.Width(), block.Width()));
      El::Syrk(El::UpperOrLowerNS::UPPER, El::OrientationNS::TRANSPOSE,
               El::BigFloat(1), block, El::BigFloat(1), Q_local_view);
    }
  El::MakeSymmetric(El::UpperOrLower::UPPER, Q_local);
  El::AllReduce(Q_local, El::mpi::COMM_WORLD);

  for(int64_t row = 0; row < Q.LocalHeight(); ++row)
    {
      int64_t global_row(Q.GlobalRow(row));
      for(int64_t column = 0; column < Q.LocalWidth(); ++column)
        {
          int64_t global_column(Q.GlobalCol(column));
          // FIXME: This assumes that there is one process per block.
          Q.SetLocal(row, column, Q_local.GetLocal(global_row, global_column));
        }
    }

  timers["run.step.initializeSchurComplementSolver.Q_Syrk"].stop();

  if(debug)
    {
      El::Output(El::mpi::Rank(),
                 " run.step.initializeSchurComplementSolver.Q_Cholesky");
    }
  timers["run.step.initializeSchurComplementSolver.Q_Cholesky"].resume();
  Cholesky(El::UpperOrLowerNS::LOWER, Q);
  timers["run.step.initializeSchurComplementSolver.Q_Cholesky"].stop();
  if(debug)
    {
      El::Output(El::mpi::Rank(),
                 " run.step.initializeSchurComplementSolver.Q_copy");
    }
  timers["run.step.initializeSchurComplementSolver.Q_copy"].resume();

  Q.ReservePulls(Q_local.LocalHeight() * Q_local.LocalWidth());
  for(int64_t row = 0; row < Q_local.LocalHeight(); ++row)
    {
      int64_t global_row(Q_local.GlobalRow(row));
      for(int64_t column = 0; column < Q_local.LocalWidth(); ++column)
        {
          int64_t global_column(Q_local.GlobalCol(column));
          Q.QueuePull(global_row, global_column);
        }
    }
  std::vector<El::BigFloat> pulls;
  Q.ProcessPullQueue(pulls);

  auto pull(pulls.begin());
  for(int64_t row = 0; row < Q_local.LocalHeight(); ++row)
    {
      for(int64_t column = 0; column < Q_local.LocalWidth(); ++column)
        {
          Q_local.SetLocal(row, column, *pull);
          ++pull;
        }
    }
  timers["run.step.initializeSchurComplementSolver.Q_copy"].stop();
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <string>

#include <boost/program_options.hpp>

#include <plasp/LanguageDetection.h>
#include <plasp/pddl/Description.h>
#include <plasp/pddl/TranslatorASP.h>
#include <plasp/sas/Description.h>
#include <plasp/sas/TranslatorASP.h>
#include <plasp/utils/LogStream.h>
#include <plasp/utils/TranslatorException.h>

int main(int argc, char **argv)
{
	namespace po = boost::program_options;

	po::options_description description("Allowed options");
	description.add_options()
		("help,h", "Display this help message.")
		("version,v", "Display version information.")
		("input,i", po::value<std::vector<std::string>>(), "Specify the PDDL or SAS input file.")
		("language,l", po::value<std::string>(), "Specify the input language (sas or pddl). Omit for automatic detection.")
		("warning-level", po::value<std::string>()->default_value("normal"), "Specify whether to output warnings normally (normal), to treat them as critical errors (error), or to ignore them (ignore).")
		("color", po::value<std::string>()->default_value("auto"), "Specify whether to colorize the output (always, never, or auto).");

	po::positional_options_description positionalOptionsDescription;
	positionalOptionsDescription.add("input", -1);

	po::variables_map variablesMap;

	const auto printHelp =
		[&]()
		{
			std::cout << "Usage: plasp [files] [options]" << std::endl;
			std::cout << "Translate PDDL instances to ASP facts." << std::endl << std::endl;

			std::cout << description;
		};

	plasp::utils::Logger logger;

	try
	{
		po::store(po::command_line_parser(argc, argv)
			.options(description)
			.positional(positionalOptionsDescription)
			.run(),
			variablesMap);
		po::notify(variablesMap);
	}
	catch (const po::error &e)
	{
		logger.logError(e.what());
		std::cout << std::endl;
		printHelp();
		return EXIT_FAILURE;
	}

	if (variablesMap.count("help"))
	{
		printHelp();
		return EXIT_SUCCESS;
	}

	if (variablesMap.count("version"))
	{
		std::cout << "plasp version 3.0.1-git" << std::endl;
		return EXIT_SUCCESS;
	}

	const auto warningLevel = variablesMap["warning-level"].as<std::string>();

	if (warningLevel == "error")
		logger.setWarningLevel(plasp::utils::Logger::WarningLevel::Error);
	else if (warningLevel == "ignore")
		logger.setWarningLevel(plasp::utils::Logger::WarningLevel::Ignore);
	else if (warningLevel == "normal")
		logger.setWarningLevel(plasp::utils::Logger::WarningLevel::Normal);
	else
	{
		logger.logError("unknown warning level “" + warningLevel + "”");
		std::cout << std::endl;
		printHelp();
		return EXIT_FAILURE;
	}

	const auto colorPolicy = variablesMap["color"].as<std::string>();

	if (colorPolicy == "auto")
		logger.setColorPolicy(plasp::utils::LogStream::ColorPolicy::Auto);
	else if (colorPolicy == "never")
		logger.setColorPolicy(plasp::utils::LogStream::ColorPolicy::Never);
	else if (colorPolicy == "always")
		logger.setColorPolicy(plasp::utils::LogStream::ColorPolicy::Always);
	else
	{
		logger.logError("unknown color policy “" + colorPolicy + "”");
		std::cout << std::endl;
		printHelp();
		return EXIT_FAILURE;
	}

	try
	{
		plasp::utils::Parser<plasp::utils::CaseInsensitiveParserPolicy> parser;

		if (variablesMap.count("input"))
		{
			const auto &inputFiles = variablesMap["input"].as<std::vector<std::string>>();

			std::for_each(inputFiles.cbegin(), inputFiles.cend(),
				[&](const auto &inputFile)
				{
					parser.read(inputFile);
				});
		}
		else
			parser.read("std::cin", std::cin);

		const auto detectLanguage =
			[&]()
			{
				if (variablesMap.count("language") == 0)
					return plasp::detectLanguage(parser);

				const auto languageName = variablesMap["language"].as<std::string>();

				return plasp::Language::fromString(languageName);
			};

		const auto language = detectLanguage();

		if (language == plasp::Language::Type::Unknown)
		{
			logger.logError("unknown input language");
			std::cout << std::endl;
			printHelp();
			return EXIT_FAILURE;
		}

		if (language == plasp::Language::Type::PDDL)
		{
			auto pddlLogger = logger;
			auto context = plasp::pddl::Context(std::move(parser), std::move(pddlLogger));
			auto description = plasp::pddl::Description::fromContext(std::move(context));
			const auto translator = plasp::pddl::TranslatorASP(description, description.context().logger.outputStream());
			translator.translate();
		}
		else if (language == plasp::Language::Type::SAS)
		{
			const auto description = plasp::sas::Description::fromParser(std::move(parser));
			const auto translator = plasp::sas::TranslatorASP(description, logger.outputStream());
			translator.translate();
		}
	}
	catch (const plasp::utils::ParserException &e)
	{
		logger.logError(e.coordinate(), e.message());
		return EXIT_FAILURE;
	}
	catch (const plasp::utils::TranslatorException &e)
	{
		logger.logError(e.what());
		return EXIT_FAILURE;
	}
	catch (const std::exception &e)
	{
		logger.logError(e.what());
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}
<commit_msg>Version bump for release 3.0.2 RC 1.<commit_after>#include <algorithm>
#include <iostream>
#include <string>

#include <boost/program_options.hpp>

#include <plasp/LanguageDetection.h>
#include <plasp/pddl/Description.h>
#include <plasp/pddl/TranslatorASP.h>
#include <plasp/sas/Description.h>
#include <plasp/sas/TranslatorASP.h>
#include <plasp/utils/LogStream.h>
#include <plasp/utils/TranslatorException.h>

int main(int argc, char **argv)
{
	namespace po = boost::program_options;

	po::options_description description("Allowed options");
	description.add_options()
		("help,h", "Display this help message.")
		("version,v", "Display version information.")
		("input,i", po::value<std::vector<std::string>>(), "Specify the PDDL or SAS input file.")
		("language,l", po::value<std::string>(), "Specify the input language (sas or pddl). Omit for automatic detection.")
		("warning-level", po::value<std::string>()->default_value("normal"), "Specify whether to output warnings normally (normal), to treat them as critical errors (error), or to ignore them (ignore).")
		("color", po::value<std::string>()->default_value("auto"), "Specify whether to colorize the output (always, never, or auto).");

	po::positional_options_description positionalOptionsDescription;
	positionalOptionsDescription.add("input", -1);

	po::variables_map variablesMap;

	const auto printHelp =
		[&]()
		{
			std::cout << "Usage: plasp [files] [options]" << std::endl;
			std::cout << "Translate PDDL instances to ASP facts." << std::endl << std::endl;

			std::cout << description;
		};

	plasp::utils::Logger logger;

	try
	{
		po::store(po::command_line_parser(argc, argv)
			.options(description)
			.positional(positionalOptionsDescription)
			.run(),
			variablesMap);
		po::notify(variablesMap);
	}
	catch (const po::error &e)
	{
		logger.logError(e.what());
		std::cout << std::endl;
		printHelp();
		return EXIT_FAILURE;
	}

	if (variablesMap.count("help"))
	{
		printHelp();
		return EXIT_SUCCESS;
	}

	if (variablesMap.count("version"))
	{
		std::cout << "plasp version 3.0.2-rc.1" << std::endl;
		return EXIT_SUCCESS;
	}

	const auto warningLevel = variablesMap["warning-level"].as<std::string>();

	if (warningLevel == "error")
		logger.setWarningLevel(plasp::utils::Logger::WarningLevel::Error);
	else if (warningLevel == "ignore")
		logger.setWarningLevel(plasp::utils::Logger::WarningLevel::Ignore);
	else if (warningLevel == "normal")
		logger.setWarningLevel(plasp::utils::Logger::WarningLevel::Normal);
	else
	{
		logger.logError("unknown warning level “" + warningLevel + "”");
		std::cout << std::endl;
		printHelp();
		return EXIT_FAILURE;
	}

	const auto colorPolicy = variablesMap["color"].as<std::string>();

	if (colorPolicy == "auto")
		logger.setColorPolicy(plasp::utils::LogStream::ColorPolicy::Auto);
	else if (colorPolicy == "never")
		logger.setColorPolicy(plasp::utils::LogStream::ColorPolicy::Never);
	else if (colorPolicy == "always")
		logger.setColorPolicy(plasp::utils::LogStream::ColorPolicy::Always);
	else
	{
		logger.logError("unknown color policy “" + colorPolicy + "”");
		std::cout << std::endl;
		printHelp();
		return EXIT_FAILURE;
	}

	try
	{
		plasp::utils::Parser<plasp::utils::CaseInsensitiveParserPolicy> parser;

		if (variablesMap.count("input"))
		{
			const auto &inputFiles = variablesMap["input"].as<std::vector<std::string>>();

			std::for_each(inputFiles.cbegin(), inputFiles.cend(),
				[&](const auto &inputFile)
				{
					parser.read(inputFile);
				});
		}
		else
			parser.read("std::cin", std::cin);

		const auto detectLanguage =
			[&]()
			{
				if (variablesMap.count("language") == 0)
					return plasp::detectLanguage(parser);

				const auto languageName = variablesMap["language"].as<std::string>();

				return plasp::Language::fromString(languageName);
			};

		const auto language = detectLanguage();

		if (language == plasp::Language::Type::Unknown)
		{
			logger.logError("unknown input language");
			std::cout << std::endl;
			printHelp();
			return EXIT_FAILURE;
		}

		if (language == plasp::Language::Type::PDDL)
		{
			auto pddlLogger = logger;
			auto context = plasp::pddl::Context(std::move(parser), std::move(pddlLogger));
			auto description = plasp::pddl::Description::fromContext(std::move(context));
			const auto translator = plasp::pddl::TranslatorASP(description, description.context().logger.outputStream());
			translator.translate();
		}
		else if (language == plasp::Language::Type::SAS)
		{
			const auto description = plasp::sas::Description::fromParser(std::move(parser));
			const auto translator = plasp::sas::TranslatorASP(description, logger.outputStream());
			translator.translate();
		}
	}
	catch (const plasp::utils::ParserException &e)
	{
		logger.logError(e.coordinate(), e.message());
		return EXIT_FAILURE;
	}
	catch (const plasp::utils::TranslatorException &e)
	{
		logger.logError(e.what());
		return EXIT_FAILURE;
	}
	catch (const std::exception &e)
	{
		logger.logError(e.what());
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: SlsGenericPageCache.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: pjunck $ $Date: 2004-10-28 13:28:20 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX
#define SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX

#include "SlsQueueProcessor.hxx"
#include "view/SlsPageObjectViewObjectContact.hxx"

namespace sd { namespace slidesorter { namespace model {
class SlideSorterModel;
} } }

namespace sd { namespace slidesorter { namespace view {
class SlideSorterView;
} } }

namespace sd { namespace slidesorter { namespace cache {

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CacheCompactionPolicy,
         class QueueProcessor>
class GenericPageCache
{
public:
    /** The page chache is created with references both to the view and the
        model so that it can fill itself with requests for all or just the
        visible pages.
    */
    GenericPageCache (
        view::SlideSorterView& rView,
        model::SlideSorterModel& rModel,
        sal_Int32 nMaximalCacheSize);

    ~GenericPageCache (void);

    /** Request a preview bitmap for the specified page object in the
        specified size.  The returned bitmap may be preview of the preview,
        i.e. either a scaled (up or down) version of a previous preview (of
        the wrong size) or an empty bitmap.  In this case a request for the
        generation of a new preview is created and inserted into the request
        queue.  When the preview is available the page shape will be told to
        paint itself again.  When it then calls this method again if
        receives the correctly sized preview bitmap.
        @param rRequestData
            This data is used to determine the preview.
        @param rSize
            The size of the requested preview bitmap.
        @return
            Returns a bitmap that is either empty, contains a scaled (up or
            down) version or is the requested bitmap.
    */
    BitmapEx GetPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize);

    /** When the requested preview bitmap does not yet exist or is not
        up-to-date then the rendering of one is scheduled.  Otherwise this
        method does nothing.
        @param rRequestData
            This data is used to determine the preview.
        @param rSize
            The size of the requested preview bitmap in pixel coordinates.
        @param bMayBeUpToDate
            This flag helps the method to determine whether an existing
            preview that matches the request is up to date.  If the caller
            know that it is not then by passing <FALSE/> he tells us that we
            do not have to check the up-to-date flag a second time.  If
            unsure pass <TRUE/>.
    */
    void RequestPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize,
        bool bMayBeUpToDate = true);

    /** Tell the cache to replace the bitmap associated with the given
        request data with a new one that reflects recent changes in the
        content of the page object.
    */
    void InvalidatePreviewBitmap (const RequestData& rRequestData);

    /** Lower the priority with which the request associated with the given
        data will be processed.  Call this method when the visibility of a
        page object changes (from visible to not visible) and the request
        becomes a ahead-of-time request. When the request is already in the
        lowest class it will be removed.
    */
    void DecreaseRequestPriority (RequestData& rRequestData);

    /** Move the request associated with the given data into a higher
        priority class and increase its priority in that class above all
        other elements in the class.
    */
    void IncreaseRequestPriority (RequestData& rRequestData);

    /** Call this method when a view-object-contact object is being deleted
        and does not need (a) its current bitmap in the cache and (b) a
        requested new bitmap.
    */
    void ReleasePreviewBitmap (RequestData& rRequestData);

    /** Call this method when all preview bitmaps have to be generated anew.
        This is the case when the size of the page objects on the screen has
        changed or when the model has changed.
    */
    void InvalidateCache (void);

    /** With the precious flag you can control whether a bitmap can be
        removed or reduced in size to make room for other bitmaps or is so
        precious that it will not be touched.  A typical use is to set the
        precious flag for exactly the visible pages.
    */
    void SetPreciousFlag (RequestData& rRequestData, bool bIsPrecious);

private:
    view::SlideSorterView& mrView;

    model::SlideSorterModel& mrModel;

    BitmapCache maBitmapCache;

    RequestQueue maRequestQueue;

    QueueProcessor* mpQueueProcessor;

    const sal_Int32 mnMaximalCacheSize;

    /** Remember whether the cache limit has been reached at least once
        after a Clear() call.  This is important because afterwards the
        cache will be constantly at its limit of capacity.  Therefore
        requests with another than the highest priority class will not be
        processed since the resulting preview bitmaps would be removed
        shortly afterwards.
    */
    bool mbLimitHasBeenReached;
};

//=====  GenericPageCache =====================================================

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
GenericPageCache<
    RequestData,
    CreationManager,
    BitmapCache,
    RequestQueue,
    CompactionPolicy, QueueProcessor
    >::GenericPageCache (
        view::SlideSorterView& rView,
        model::SlideSorterModel& rModel,
        sal_Int32 nMaximalCacheSize)
        : mrView(rView),
          mrModel(rModel),
          maBitmapCache (),
          maRequestQueue(),
          mpQueueProcessor(
              new QueueProcessor(mrView,maRequestQueue,maBitmapCache)),
          mnMaximalCacheSize(nMaximalCacheSize),
          mbLimitHasBeenReached (false)
{
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::~GenericPageCache (void)
{
    OSL_TRACE("terminating thread %p", mpQueueProcessor);
    mpQueueProcessor->Stop();
    maRequestQueue.Clear();
    mpQueueProcessor->Terminate();
    //    delete mpQueueProcessor;
    OSL_TRACE("thread %p stopped and terminated", mpQueueProcessor);
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
BitmapEx GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::GetPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize)
{
    BitmapEx aPreview;
    bool bMayBeUpToDate = true;
    if (maBitmapCache.HasBitmap (rRequestData.GetPage()))
    {
        aPreview = maBitmapCache.GetBitmap (rRequestData.GetPage());
        Size aBitmapSize (aPreview.GetSizePixel());
        if (aBitmapSize != rSize)
        {
            // The bitmap has the wrong size.
            DBG_ASSERT (rSize.Width() < 1000,
                "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width.  This may indicate an error.");

            // Scale the bitmap to the desired size when that is possible,
            // i.e. the bitmap is not empty.
            if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0)
                aPreview.Scale (rSize, BMP_SCALE_FAST);
        }
        bMayBeUpToDate = true;
    }
    else
        bMayBeUpToDate = false;

    // Request the creation of a correctly sized preview bitmap.  We do this
    // even when the size of the bitmap in the cache is correct because its
    // content may be not up-to-date anymore.
    RequestPreviewBitmap (rRequestData, rSize, bMayBeUpToDate);

    return aPreview;
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::RequestPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize,
        bool bMayBeUpToDate)
{
    const SdrPage* pPage = rRequestData.GetPage();

    // Determine if the available bitmap is up to date.
    bool bIsUpToDate = false;
    if (bMayBeUpToDate)
        bIsUpToDate = maBitmapCache.BitmapIsUpToDate (pPage);
    if (bIsUpToDate)
    {
        BitmapEx aPreview (maBitmapCache.GetBitmap (pPage));
        if (aPreview.GetSizePixel() != rSize)
            bIsUpToDate = false;
    }

    if ( ! bIsUpToDate)
    {
        // No, the bitmap is not up-to-date.  Request a new one.
        int nPriorityClass = rRequestData.GetPageDescriptor().IsVisible() ? 0 : 1;
        maRequestQueue.AddRequest (rRequestData, nPriorityClass);
        mpQueueProcessor->Start (nPriorityClass);
    }

    // Reduce the cache size if it grew too large.
    if (maBitmapCache.GetSize() > mnMaximalCacheSize)
    {
        mbLimitHasBeenReached = true;
        CompactionPolicy()(maBitmapCache, mnMaximalCacheSize);
    }
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::InvalidatePreviewBitmap (const RequestData& rRequestData)
{
    maBitmapCache.InvalidateBitmap (rRequestData.GetPage());
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::DecreaseRequestPriority (RequestData& rRequestData)
{
    if (mbLimitHasBeenReached)
        maRequestQueue.RemoveRequest (rRequestData);
    else
        maRequestQueue.ChangePriorityClass (rRequestData,+1);
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::IncreaseRequestPriority (RequestData& rRequestData)
{
    maRequestQueue.ChangePriorityClass (rRequestData,-1);
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::ReleasePreviewBitmap (RequestData& rRequestData)
{
    mpQueueProcessor->RemoveRequest (rRequestData);
    maRequestQueue.RemoveRequest (rRequestData);

    // We do not relase the preview bitmap that is associated with the page
    // of the given request data because this method is called when the
    // request data, typically a view-object-contact object, is destroyed.
    // The page object usually lives longer than that and thus the preview
    // bitmap may be used later on.
    //    maBitmapCache.ReleaseBitmap (rRequestData);
}

template<class RequestData,
         class RequestFactory,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, RequestFactory, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::InvalidateCache (void)
{
    // 1.) Stop the timer while the queues are being updated.
    mpQueueProcessor->Stop();

    // 2.) Clear the request queue of their current content.
    maRequestQueue.Clear();
    mbLimitHasBeenReached = false;

    // 3.) Create the new requests for filling the cache with at least the
    // visible previews.
    RequestFactory()(mrModel, mrView,maRequestQueue);

    // 4.) Start the timer again.
    mpQueueProcessor->Start();
}

template<class RequestData,
         class RequestFactory,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, RequestFactory, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::SetPreciousFlag (RequestData& rRequestData, bool bIsPrecious)
{
    maBitmapCache.SetPrecious (rRequestData.GetPage(), bIsPrecious);
}

} } } // end of namespace ::sd::slidesorter::cache

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.4.328); FILE MERGED 2005/09/05 13:24:15 rt 1.4.328.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsGenericPageCache.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 06:10:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX
#define SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX

#include "SlsQueueProcessor.hxx"
#include "view/SlsPageObjectViewObjectContact.hxx"

namespace sd { namespace slidesorter { namespace model {
class SlideSorterModel;
} } }

namespace sd { namespace slidesorter { namespace view {
class SlideSorterView;
} } }

namespace sd { namespace slidesorter { namespace cache {

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CacheCompactionPolicy,
         class QueueProcessor>
class GenericPageCache
{
public:
    /** The page chache is created with references both to the view and the
        model so that it can fill itself with requests for all or just the
        visible pages.
    */
    GenericPageCache (
        view::SlideSorterView& rView,
        model::SlideSorterModel& rModel,
        sal_Int32 nMaximalCacheSize);

    ~GenericPageCache (void);

    /** Request a preview bitmap for the specified page object in the
        specified size.  The returned bitmap may be preview of the preview,
        i.e. either a scaled (up or down) version of a previous preview (of
        the wrong size) or an empty bitmap.  In this case a request for the
        generation of a new preview is created and inserted into the request
        queue.  When the preview is available the page shape will be told to
        paint itself again.  When it then calls this method again if
        receives the correctly sized preview bitmap.
        @param rRequestData
            This data is used to determine the preview.
        @param rSize
            The size of the requested preview bitmap.
        @return
            Returns a bitmap that is either empty, contains a scaled (up or
            down) version or is the requested bitmap.
    */
    BitmapEx GetPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize);

    /** When the requested preview bitmap does not yet exist or is not
        up-to-date then the rendering of one is scheduled.  Otherwise this
        method does nothing.
        @param rRequestData
            This data is used to determine the preview.
        @param rSize
            The size of the requested preview bitmap in pixel coordinates.
        @param bMayBeUpToDate
            This flag helps the method to determine whether an existing
            preview that matches the request is up to date.  If the caller
            know that it is not then by passing <FALSE/> he tells us that we
            do not have to check the up-to-date flag a second time.  If
            unsure pass <TRUE/>.
    */
    void RequestPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize,
        bool bMayBeUpToDate = true);

    /** Tell the cache to replace the bitmap associated with the given
        request data with a new one that reflects recent changes in the
        content of the page object.
    */
    void InvalidatePreviewBitmap (const RequestData& rRequestData);

    /** Lower the priority with which the request associated with the given
        data will be processed.  Call this method when the visibility of a
        page object changes (from visible to not visible) and the request
        becomes a ahead-of-time request. When the request is already in the
        lowest class it will be removed.
    */
    void DecreaseRequestPriority (RequestData& rRequestData);

    /** Move the request associated with the given data into a higher
        priority class and increase its priority in that class above all
        other elements in the class.
    */
    void IncreaseRequestPriority (RequestData& rRequestData);

    /** Call this method when a view-object-contact object is being deleted
        and does not need (a) its current bitmap in the cache and (b) a
        requested new bitmap.
    */
    void ReleasePreviewBitmap (RequestData& rRequestData);

    /** Call this method when all preview bitmaps have to be generated anew.
        This is the case when the size of the page objects on the screen has
        changed or when the model has changed.
    */
    void InvalidateCache (void);

    /** With the precious flag you can control whether a bitmap can be
        removed or reduced in size to make room for other bitmaps or is so
        precious that it will not be touched.  A typical use is to set the
        precious flag for exactly the visible pages.
    */
    void SetPreciousFlag (RequestData& rRequestData, bool bIsPrecious);

private:
    view::SlideSorterView& mrView;

    model::SlideSorterModel& mrModel;

    BitmapCache maBitmapCache;

    RequestQueue maRequestQueue;

    QueueProcessor* mpQueueProcessor;

    const sal_Int32 mnMaximalCacheSize;

    /** Remember whether the cache limit has been reached at least once
        after a Clear() call.  This is important because afterwards the
        cache will be constantly at its limit of capacity.  Therefore
        requests with another than the highest priority class will not be
        processed since the resulting preview bitmaps would be removed
        shortly afterwards.
    */
    bool mbLimitHasBeenReached;
};

//=====  GenericPageCache =====================================================

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
GenericPageCache<
    RequestData,
    CreationManager,
    BitmapCache,
    RequestQueue,
    CompactionPolicy, QueueProcessor
    >::GenericPageCache (
        view::SlideSorterView& rView,
        model::SlideSorterModel& rModel,
        sal_Int32 nMaximalCacheSize)
        : mrView(rView),
          mrModel(rModel),
          maBitmapCache (),
          maRequestQueue(),
          mpQueueProcessor(
              new QueueProcessor(mrView,maRequestQueue,maBitmapCache)),
          mnMaximalCacheSize(nMaximalCacheSize),
          mbLimitHasBeenReached (false)
{
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::~GenericPageCache (void)
{
    OSL_TRACE("terminating thread %p", mpQueueProcessor);
    mpQueueProcessor->Stop();
    maRequestQueue.Clear();
    mpQueueProcessor->Terminate();
    //    delete mpQueueProcessor;
    OSL_TRACE("thread %p stopped and terminated", mpQueueProcessor);
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
BitmapEx GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::GetPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize)
{
    BitmapEx aPreview;
    bool bMayBeUpToDate = true;
    if (maBitmapCache.HasBitmap (rRequestData.GetPage()))
    {
        aPreview = maBitmapCache.GetBitmap (rRequestData.GetPage());
        Size aBitmapSize (aPreview.GetSizePixel());
        if (aBitmapSize != rSize)
        {
            // The bitmap has the wrong size.
            DBG_ASSERT (rSize.Width() < 1000,
                "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width.  This may indicate an error.");

            // Scale the bitmap to the desired size when that is possible,
            // i.e. the bitmap is not empty.
            if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0)
                aPreview.Scale (rSize, BMP_SCALE_FAST);
        }
        bMayBeUpToDate = true;
    }
    else
        bMayBeUpToDate = false;

    // Request the creation of a correctly sized preview bitmap.  We do this
    // even when the size of the bitmap in the cache is correct because its
    // content may be not up-to-date anymore.
    RequestPreviewBitmap (rRequestData, rSize, bMayBeUpToDate);

    return aPreview;
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
         class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::RequestPreviewBitmap (
        RequestData& rRequestData,
        const Size& rSize,
        bool bMayBeUpToDate)
{
    const SdrPage* pPage = rRequestData.GetPage();

    // Determine if the available bitmap is up to date.
    bool bIsUpToDate = false;
    if (bMayBeUpToDate)
        bIsUpToDate = maBitmapCache.BitmapIsUpToDate (pPage);
    if (bIsUpToDate)
    {
        BitmapEx aPreview (maBitmapCache.GetBitmap (pPage));
        if (aPreview.GetSizePixel() != rSize)
            bIsUpToDate = false;
    }

    if ( ! bIsUpToDate)
    {
        // No, the bitmap is not up-to-date.  Request a new one.
        int nPriorityClass = rRequestData.GetPageDescriptor().IsVisible() ? 0 : 1;
        maRequestQueue.AddRequest (rRequestData, nPriorityClass);
        mpQueueProcessor->Start (nPriorityClass);
    }

    // Reduce the cache size if it grew too large.
    if (maBitmapCache.GetSize() > mnMaximalCacheSize)
    {
        mbLimitHasBeenReached = true;
        CompactionPolicy()(maBitmapCache, mnMaximalCacheSize);
    }
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::InvalidatePreviewBitmap (const RequestData& rRequestData)
{
    maBitmapCache.InvalidateBitmap (rRequestData.GetPage());
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::DecreaseRequestPriority (RequestData& rRequestData)
{
    if (mbLimitHasBeenReached)
        maRequestQueue.RemoveRequest (rRequestData);
    else
        maRequestQueue.ChangePriorityClass (rRequestData,+1);
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::IncreaseRequestPriority (RequestData& rRequestData)
{
    maRequestQueue.ChangePriorityClass (rRequestData,-1);
}

template<class RequestData,
         class CreationManager,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, CreationManager, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::ReleasePreviewBitmap (RequestData& rRequestData)
{
    mpQueueProcessor->RemoveRequest (rRequestData);
    maRequestQueue.RemoveRequest (rRequestData);

    // We do not relase the preview bitmap that is associated with the page
    // of the given request data because this method is called when the
    // request data, typically a view-object-contact object, is destroyed.
    // The page object usually lives longer than that and thus the preview
    // bitmap may be used later on.
    //    maBitmapCache.ReleaseBitmap (rRequestData);
}

template<class RequestData,
         class RequestFactory,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, RequestFactory, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::InvalidateCache (void)
{
    // 1.) Stop the timer while the queues are being updated.
    mpQueueProcessor->Stop();

    // 2.) Clear the request queue of their current content.
    maRequestQueue.Clear();
    mbLimitHasBeenReached = false;

    // 3.) Create the new requests for filling the cache with at least the
    // visible previews.
    RequestFactory()(mrModel, mrView,maRequestQueue);

    // 4.) Start the timer again.
    mpQueueProcessor->Start();
}

template<class RequestData,
         class RequestFactory,
         class BitmapCache,
         class RequestQueue,
         class CompactionPolicy,
        class QueueProcessor>
void GenericPageCache<
    RequestData, RequestFactory, BitmapCache, RequestQueue,
    CompactionPolicy, QueueProcessor
    >::SetPreciousFlag (RequestData& rRequestData, bool bIsPrecious)
{
    maBitmapCache.SetPrecious (rRequestData.GetPage(), bIsPrecious);
}

} } } // end of namespace ::sd::slidesorter::cache

#endif
<|endoftext|>


<commit_before>/**
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/**
 * @file utils_internal.cc
 */
#include "utils_internal.h"
#include <cassert>
#include <ts/ts.h>
#include <pthread.h>
#include <cstdlib>
#include <cassert>
#include <cstddef>
#include "atscppapi/Plugin.h"
#include "atscppapi/GlobalPlugin.h"
#include "atscppapi/Transaction.h"
#include "atscppapi/TransactionPlugin.h"
#include "atscppapi/TransformationPlugin.h"
#include "atscppapi/utils.h"
#include "logging_internal.h"

using namespace atscppapi;

namespace {

// This is the highest txn arg that can be used, we choose this
// value to minimize the likelihood of it causing any problems.
const int MAX_TXN_ARG = 15;
const int TRANSACTION_STORAGE_INDEX = MAX_TXN_ARG;

int handleTransactionEvents(TSCont cont, TSEvent event, void *edata) {
  // This function is only here to clean up Transaction objects
  TSHttpTxn ats_txn_handle = static_cast<TSHttpTxn>(edata);
  Transaction &transaction = utils::internal::getTransaction(ats_txn_handle);
  LOG_DEBUG("Got event %d on continuation %p for transaction (ats pointer %p, object %p)", event, cont,
            ats_txn_handle, &transaction);

  switch (event) {
  case TS_EVENT_HTTP_POST_REMAP:
    transaction.getClientRequest().getUrl().reset();
    break;
  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
    utils::internal::initTransactionServerRequest(transaction);
    break;
  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    utils::internal::initTransactionServerResponse(transaction);
    break;
  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
    utils::internal::initTransactionClientResponse(transaction);
    break;
  case TS_EVENT_HTTP_TXN_CLOSE:
    { // opening scope to declare plugins variable below
      const std::list<TransactionPlugin *> &plugins = utils::internal::getTransactionPlugins(transaction);
      for (std::list<TransactionPlugin *>::const_iterator iter = plugins.begin(), end = plugins.end();
           iter != end; ++iter) {
        shared_ptr<Mutex> trans_mutex = utils::internal::getTransactionPluginMutex(**iter);
        LOG_DEBUG("Locking TransacitonPlugin mutex to delete transaction plugin at %p", *iter);
        trans_mutex->lock();
        LOG_DEBUG("Locked Mutex...Deleting transaction plugin at %p", *iter);
        delete *iter;
        trans_mutex->unlock();
      }
      delete &transaction;
    }
    break;
  default:
    assert(false); /* we should never get here */
    break;
  }
  TSHttpTxnReenable(ats_txn_handle, TS_EVENT_HTTP_CONTINUE);
  return 0;
}

void setupTransactionManagement() {
  // We must always have a cleanup handler available
  TSMutex mutex = NULL;
  TSCont cont = TSContCreate(handleTransactionEvents, mutex);
  TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_SEND_REQUEST_HDR_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, cont);
}

void inline invokePluginForEvent(Plugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
  Transaction &transaction = utils::internal::getTransaction(ats_txn_handle);
  switch (event) {
  case TS_EVENT_HTTP_PRE_REMAP:
    plugin->handleReadRequestHeadersPreRemap(transaction);
    break;
  case TS_EVENT_HTTP_POST_REMAP:
    plugin->handleReadRequestHeadersPostRemap(transaction);
    break;
  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
    plugin->handleSendRequestHeaders(transaction);
    break;
  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    plugin->handleReadResponseHeaders(transaction);
    break;
  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
    plugin->handleSendResponseHeaders(transaction);
    break;
  case TS_EVENT_HTTP_OS_DNS:
    plugin->handleOsDns(transaction);
    break;
  default:
    assert(false); /* we should never get here */
    break;
  }
}

} /* anonymous namespace */

Transaction &utils::internal::getTransaction(TSHttpTxn ats_txn_handle) {
  Transaction *transaction = static_cast<Transaction *>(TSHttpTxnArgGet(ats_txn_handle, TRANSACTION_STORAGE_INDEX));
  if (!transaction) {
    transaction = new Transaction(static_cast<void *>(ats_txn_handle));
    LOG_DEBUG("Created new transaction object at %p for ats pointer %p", transaction, ats_txn_handle);
    TSHttpTxnArgSet(ats_txn_handle, TRANSACTION_STORAGE_INDEX, transaction);
  }
  return *transaction;
}

shared_ptr<Mutex> utils::internal::getTransactionPluginMutex(TransactionPlugin &transaction_plugin) {
  return transaction_plugin.getMutex();
}

TSHttpHookID utils::internal::convertInternalHookToTsHook(Plugin::HookType hooktype) {
  switch (hooktype) {
  case Plugin::HOOK_READ_REQUEST_HEADERS_POST_REMAP:
    return TS_HTTP_POST_REMAP_HOOK;
  case Plugin::HOOK_READ_REQUEST_HEADERS_PRE_REMAP:
    return TS_HTTP_PRE_REMAP_HOOK;
  case Plugin::HOOK_READ_RESPONSE_HEADERS:
    return TS_HTTP_READ_RESPONSE_HDR_HOOK;
  case Plugin::HOOK_SEND_REQUEST_HEADERS:
    return TS_HTTP_SEND_REQUEST_HDR_HOOK;
  case Plugin::HOOK_SEND_RESPONSE_HEADERS:
    return TS_HTTP_SEND_RESPONSE_HDR_HOOK;
  case Plugin::HOOK_OS_DNS:
    return TS_HTTP_OS_DNS_HOOK;
  default:
    assert(false); // shouldn't happen, let's catch it early
    break;
  }
  return static_cast<TSHttpHookID>(-1);
}

TSHttpHookID utils::internal::convertInternalTransformationTypeToTsHook(TransformationPlugin::Type type) {
  switch (type) {
    case TransformationPlugin::RESPONSE_TRANSFORMATION:
      return TS_HTTP_RESPONSE_TRANSFORM_HOOK;
    case TransformationPlugin::REQUEST_TRANSFORMATION:
      return TS_HTTP_REQUEST_TRANSFORM_HOOK;
    default:
      assert(false); // shouldn't happen, let's catch it early
      break;
  }
  return static_cast<TSHttpHookID>(-1);
}

void utils::internal::invokePluginForEvent(TransactionPlugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
  ScopedSharedMutexLock scopedLock(plugin->getMutex());
  ::invokePluginForEvent(static_cast<Plugin *>(plugin), ats_txn_handle, event);
}

void utils::internal::invokePluginForEvent(GlobalPlugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
  ::invokePluginForEvent(static_cast<Plugin *>(plugin), ats_txn_handle, event);
}

std::string utils::internal::consumeFromTSIOBufferReader(TSIOBufferReader reader) {
  std::string str;
  int avail = TSIOBufferReaderAvail(reader);

  if (avail != TS_ERROR) {
    int consumed = 0;
    if (avail > 0) {
      str.reserve(avail + 1);

      int64_t data_len;
      const char *char_data;
      TSIOBufferBlock block = TSIOBufferReaderStart(reader);
      while (block != NULL) {
        char_data = TSIOBufferBlockReadStart(block, reader, &data_len);
        str.append(char_data, data_len);
        consumed += data_len;
        block = TSIOBufferBlockNext(block);
      }
    }
    TSIOBufferReaderConsume(reader, consumed);
  } else {
    LOG_ERROR("TSIOBufferReaderAvail returned error code %d for reader %p", avail, reader);
  }

  return str;
}

HttpVersion utils::internal::getHttpVersion(TSMBuffer hdr_buf, TSMLoc hdr_loc) {
  int version = TSHttpHdrVersionGet(hdr_buf, hdr_loc);
  if (version != TS_ERROR) {
    if ((TS_HTTP_MAJOR(version) == 0) && (TS_HTTP_MINOR(version) == 0)) {
      return HTTP_VERSION_0_9;
    }
    if ((TS_HTTP_MAJOR(version) == 1) && (TS_HTTP_MINOR(version) == 0)) {
      return HTTP_VERSION_1_0;
    }
    if ((TS_HTTP_MAJOR(version) == 1) && (TS_HTTP_MINOR(version) == 1)) {
      return HTTP_VERSION_1_1;
    } else {
      LOG_ERROR("Unrecognized version %d", version);
    }
  } else {
    LOG_ERROR("Could not get version; hdr_buf %p, hdr_loc %p", hdr_buf, hdr_loc);
  }
  return HTTP_VERSION_UNKNOWN;
}

void utils::internal::initTransactionManagement() {
  static pthread_once_t setup_pthread_once_control = PTHREAD_ONCE_INIT;
  pthread_once(&setup_pthread_once_control, setupTransactionManagement);
}
<commit_msg>Cppapi: small change to force refresh of cached url<commit_after>/**
  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/**
 * @file utils_internal.cc
 */
#include "utils_internal.h"
#include <cassert>
#include <ts/ts.h>
#include <pthread.h>
#include <cstdlib>
#include <cassert>
#include <cstddef>
#include "atscppapi/Plugin.h"
#include "atscppapi/GlobalPlugin.h"
#include "atscppapi/Transaction.h"
#include "atscppapi/TransactionPlugin.h"
#include "atscppapi/TransformationPlugin.h"
#include "atscppapi/utils.h"
#include "logging_internal.h"

using namespace atscppapi;

namespace {

// This is the highest txn arg that can be used, we choose this
// value to minimize the likelihood of it causing any problems.
const int MAX_TXN_ARG = 15;
const int TRANSACTION_STORAGE_INDEX = MAX_TXN_ARG;

int handleTransactionEvents(TSCont cont, TSEvent event, void *edata) {
  // This function is only here to clean up Transaction objects
  TSHttpTxn ats_txn_handle = static_cast<TSHttpTxn>(edata);
  Transaction &transaction = utils::internal::getTransaction(ats_txn_handle);
  LOG_DEBUG("Got event %d on continuation %p for transaction (ats pointer %p, object %p)", event, cont,
            ats_txn_handle, &transaction);

  switch (event) {
  case TS_EVENT_HTTP_POST_REMAP:
    transaction.getClientRequest().getUrl().reset();
    break;
  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
    utils::internal::initTransactionServerRequest(transaction);
    break;
  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    utils::internal::initTransactionServerResponse(transaction);
    break;
  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
    utils::internal::initTransactionClientResponse(transaction);
    break;
  case TS_EVENT_HTTP_TXN_CLOSE:
    { // opening scope to declare plugins variable below
      const std::list<TransactionPlugin *> &plugins = utils::internal::getTransactionPlugins(transaction);
      for (std::list<TransactionPlugin *>::const_iterator iter = plugins.begin(), end = plugins.end();
           iter != end; ++iter) {
        shared_ptr<Mutex> trans_mutex = utils::internal::getTransactionPluginMutex(**iter);
        LOG_DEBUG("Locking TransacitonPlugin mutex to delete transaction plugin at %p", *iter);
        trans_mutex->lock();
        LOG_DEBUG("Locked Mutex...Deleting transaction plugin at %p", *iter);
        delete *iter;
        trans_mutex->unlock();
      }
      delete &transaction;
    }
    break;
  default:
    assert(false); /* we should never get here */
    break;
  }
  TSHttpTxnReenable(ats_txn_handle, TS_EVENT_HTTP_CONTINUE);
  return 0;
}

void setupTransactionManagement() {
  // We must always have a cleanup handler available
  TSMutex mutex = NULL;
  TSCont cont = TSContCreate(handleTransactionEvents, mutex);
  TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_SEND_REQUEST_HDR_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, cont);
  TSHttpHookAdd(TS_HTTP_TXN_CLOSE_HOOK, cont);
}

void inline invokePluginForEvent(Plugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
  Transaction &transaction = utils::internal::getTransaction(ats_txn_handle);
  switch (event) {
  case TS_EVENT_HTTP_PRE_REMAP:
    plugin->handleReadRequestHeadersPreRemap(transaction);
    break;
  case TS_EVENT_HTTP_POST_REMAP:
    plugin->handleReadRequestHeadersPostRemap(transaction);

    // This is hear to force a refresh of the cached client request url
    TSMBuffer hdr_buf;
    TSMLoc hdr_loc;
    TSHttpTxnClientReqGet(static_cast<TSHttpTxn>(transaction.getAtsHandle()), &hdr_buf, &hdr_loc);
    break;
  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
    plugin->handleSendRequestHeaders(transaction);
    break;
  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    plugin->handleReadResponseHeaders(transaction);
    break;
  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
    plugin->handleSendResponseHeaders(transaction);
    break;
  case TS_EVENT_HTTP_OS_DNS:
    plugin->handleOsDns(transaction);
    break;
  default:
    assert(false); /* we should never get here */
    break;
  }
}

} /* anonymous namespace */

Transaction &utils::internal::getTransaction(TSHttpTxn ats_txn_handle) {
  Transaction *transaction = static_cast<Transaction *>(TSHttpTxnArgGet(ats_txn_handle, TRANSACTION_STORAGE_INDEX));
  if (!transaction) {
    transaction = new Transaction(static_cast<void *>(ats_txn_handle));
    LOG_DEBUG("Created new transaction object at %p for ats pointer %p", transaction, ats_txn_handle);
    TSHttpTxnArgSet(ats_txn_handle, TRANSACTION_STORAGE_INDEX, transaction);
  }
  return *transaction;
}

shared_ptr<Mutex> utils::internal::getTransactionPluginMutex(TransactionPlugin &transaction_plugin) {
  return transaction_plugin.getMutex();
}

TSHttpHookID utils::internal::convertInternalHookToTsHook(Plugin::HookType hooktype) {
  switch (hooktype) {
  case Plugin::HOOK_READ_REQUEST_HEADERS_POST_REMAP:
    return TS_HTTP_POST_REMAP_HOOK;
  case Plugin::HOOK_READ_REQUEST_HEADERS_PRE_REMAP:
    return TS_HTTP_PRE_REMAP_HOOK;
  case Plugin::HOOK_READ_RESPONSE_HEADERS:
    return TS_HTTP_READ_RESPONSE_HDR_HOOK;
  case Plugin::HOOK_SEND_REQUEST_HEADERS:
    return TS_HTTP_SEND_REQUEST_HDR_HOOK;
  case Plugin::HOOK_SEND_RESPONSE_HEADERS:
    return TS_HTTP_SEND_RESPONSE_HDR_HOOK;
  case Plugin::HOOK_OS_DNS:
    return TS_HTTP_OS_DNS_HOOK;
  default:
    assert(false); // shouldn't happen, let's catch it early
    break;
  }
  return static_cast<TSHttpHookID>(-1);
}

TSHttpHookID utils::internal::convertInternalTransformationTypeToTsHook(TransformationPlugin::Type type) {
  switch (type) {
    case TransformationPlugin::RESPONSE_TRANSFORMATION:
      return TS_HTTP_RESPONSE_TRANSFORM_HOOK;
    case TransformationPlugin::REQUEST_TRANSFORMATION:
      return TS_HTTP_REQUEST_TRANSFORM_HOOK;
    default:
      assert(false); // shouldn't happen, let's catch it early
      break;
  }
  return static_cast<TSHttpHookID>(-1);
}

void utils::internal::invokePluginForEvent(TransactionPlugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
  ScopedSharedMutexLock scopedLock(plugin->getMutex());
  ::invokePluginForEvent(static_cast<Plugin *>(plugin), ats_txn_handle, event);
}

void utils::internal::invokePluginForEvent(GlobalPlugin *plugin, TSHttpTxn ats_txn_handle, TSEvent event) {
  ::invokePluginForEvent(static_cast<Plugin *>(plugin), ats_txn_handle, event);
}

std::string utils::internal::consumeFromTSIOBufferReader(TSIOBufferReader reader) {
  std::string str;
  int avail = TSIOBufferReaderAvail(reader);

  if (avail != TS_ERROR) {
    int consumed = 0;
    if (avail > 0) {
      str.reserve(avail + 1);

      int64_t data_len;
      const char *char_data;
      TSIOBufferBlock block = TSIOBufferReaderStart(reader);
      while (block != NULL) {
        char_data = TSIOBufferBlockReadStart(block, reader, &data_len);
        str.append(char_data, data_len);
        consumed += data_len;
        block = TSIOBufferBlockNext(block);
      }
    }
    TSIOBufferReaderConsume(reader, consumed);
  } else {
    LOG_ERROR("TSIOBufferReaderAvail returned error code %d for reader %p", avail, reader);
  }

  return str;
}

HttpVersion utils::internal::getHttpVersion(TSMBuffer hdr_buf, TSMLoc hdr_loc) {
  int version = TSHttpHdrVersionGet(hdr_buf, hdr_loc);
  if (version != TS_ERROR) {
    if ((TS_HTTP_MAJOR(version) == 0) && (TS_HTTP_MINOR(version) == 0)) {
      return HTTP_VERSION_0_9;
    }
    if ((TS_HTTP_MAJOR(version) == 1) && (TS_HTTP_MINOR(version) == 0)) {
      return HTTP_VERSION_1_0;
    }
    if ((TS_HTTP_MAJOR(version) == 1) && (TS_HTTP_MINOR(version) == 1)) {
      return HTTP_VERSION_1_1;
    } else {
      LOG_ERROR("Unrecognized version %d", version);
    }
  } else {
    LOG_ERROR("Could not get version; hdr_buf %p, hdr_loc %p", hdr_buf, hdr_loc);
  }
  return HTTP_VERSION_UNKNOWN;
}

void utils::internal::initTransactionManagement() {
  static pthread_once_t setup_pthread_once_control = PTHREAD_ONCE_INIT;
  pthread_once(&setup_pthread_once_control, setupTransactionManagement);
}
<|endoftext|>