<commit_before>#include "elxProgressCommand.h"
#include "xoutmain.h"
#include "vnl/vnl_math.h"

namespace elastix
{
  using namespace itk;

  /**
	 * ******************* Constructor ***********************
	 */

  ProgressCommand::ProgressCommand()
  {
    this->m_StartString = "Progress: ";
    this->m_EndString = "%";
    this->m_Tag = 0;
    this->m_TagIsSet = false;
    this->m_ObservedProcessObject = 0;
    this->m_NumberOfVoxels = 0;
    this->m_NumberOfUpdates = 0;

    /** Check if the output of the stream is a console. */
    this->m_StreamOutputIsConsole = false;
    std::string streamOutput = "cout";
    int currentPos = xl::xout["coutonly"].GetCOutputs().find( streamOutput )->second->tellp();
    if ( currentPos == -1 )
    {
      this->m_StreamOutputIsConsole = true;
    }

  } // end Constructor()

  /**
	 * ******************* Destructor ***********************
	 */

  ProgressCommand::~ProgressCommand()
  {
    this->DisconnectObserver( this->m_ObservedProcessObject );

  } // end Destructor()

  /**
	 * ******************* SetUpdateFrequency ***********************
	 */

  void ProgressCommand
    ::SetUpdateFrequency(
    const unsigned long numberOfVoxels,
    const unsigned long numberOfUpdates )
  {
    /** Set the member variables. */
    this->m_NumberOfVoxels  = numberOfVoxels;
    this->m_NumberOfUpdates = numberOfUpdates;

    /** Make sure we have at least one pixel. */
    if ( this->m_NumberOfVoxels < 1 )
    {
      this->m_NumberOfVoxels = 1;
    }

    /** We cannot update more times than there are pixels. */
    if ( this->m_NumberOfUpdates > this->m_NumberOfVoxels )
    {
      this->m_NumberOfUpdates = this->m_NumberOfVoxels;
    }

    /** Make sure we update at least once. */
    if ( this->m_NumberOfUpdates < 1 )
    {
      this->m_NumberOfUpdates = 1;
    }

  } // end SetUpdateFrequency()

  /**
	 * ******************* ConnectObserver ***********************
	 */

  void ProgressCommand
    ::ConnectObserver( ProcessObject * filter )
  {
    /** Disconnect from old observed filters. */
    this->DisconnectObserver( this->m_ObservedProcessObject );

    /** Connect to the new filter. */
    if ( this->m_StreamOutputIsConsole )
    {
      this->m_Tag = filter->AddObserver( itk::ProgressEvent(), this );
      this->m_TagIsSet = true;
      this->m_ObservedProcessObject = filter;
    }

  } // end ConnectObserver()

  /**
	 * ******************* DisconnectObserver ***********************
	 */

  void ProgressCommand
    ::DisconnectObserver( ProcessObject * filter )
  {
    if ( this->m_StreamOutputIsConsole )
    {
      if ( this->m_TagIsSet )
      {
        filter->RemoveObserver( this->m_Tag );
        this->m_TagIsSet = false;
        this->m_ObservedProcessObject = 0;
      }
    }

  } // end DisconnectObserver()

  /**
	 * ******************* Execute ***********************
	 */

  void ProgressCommand
    ::Execute( Object *caller, const EventObject &event )
  {
    ProcessObject *po = dynamic_cast<ProcessObject *>( caller );
    if ( !po ) return;

    if ( typeid( event ) == typeid( ProgressEvent ) )
    {
      this->PrintProgress( po->GetProgress() );
    }

  } // end Execute()

  /**
	 * ******************* Execute ***********************
	 */

  void ProgressCommand
    ::Execute( const Object *caller, const EventObject &event )
  {
    const ProcessObject *po = dynamic_cast<const ProcessObject *>( caller );
    if ( !po ) return;

    if ( typeid( event ) == typeid( ProgressEvent ) )
    {
      this->PrintProgress( po->GetProgress() );
    }

  } // end Execute()

  /**
	 * ******************* PrintProgress ***********************
	 */

  void ProgressCommand
    ::PrintProgress( const float & progress ) const
  {
    /** Print the progress to the screen. */
    int progressInt = vnl_math_rnd( 100 * progress );
    xl::xout["coutonly"]
      << "\r"
      << this->m_StartString
      << progressInt
      << this->m_EndString;

    /** If the process is completed, print an end-of-line. */
    if ( progress > 0.99999 )
    {
      xl::xout["coutonly"] << std::endl;
    }

  } // end PrintProgress()

  /**
	 * ******************* PrintProgress ***********************
	 */

  void ProgressCommand
    ::UpdateAndPrintProgress( const unsigned long & currentVoxelNumber ) const
  {
    if ( this->m_StreamOutputIsConsole )
    {
      const unsigned long frac =
        static_cast<unsigned long>( this->m_NumberOfVoxels / this->m_NumberOfUpdates );
      if ( currentVoxelNumber % frac == 0 )
      {
        this->PrintProgress(
          static_cast<float>( currentVoxelNumber ) /
          static_cast<float>( this->m_NumberOfVoxels ) );
      }
    }

  } // end PrintProgress()

} // end namespace itk

<commit_msg>MS:<commit_after>#include "elxProgressCommand.h"
#include "xoutmain.h"
#include "vnl/vnl_math.h"

namespace elastix
{
  using namespace itk;

  /**
	 * ******************* Constructor ***********************
	 */

  ProgressCommand::ProgressCommand()
  {
    this->m_StartString = "Progress: ";
    this->m_EndString = "%";
    this->m_Tag = 0;
    this->m_TagIsSet = false;
    this->m_ObservedProcessObject = 0;
    this->m_NumberOfVoxels = 0;
    this->m_NumberOfUpdates = 0;

    /** Check if the output of the stream is a console. */
    this->m_StreamOutputIsConsole = false;
    std::string streamOutput = "cout";
    int currentPos = xl::xout["coutonly"].GetCOutputs().find( streamOutput )->second->tellp();
    if ( currentPos == -1 )
    {
      this->m_StreamOutputIsConsole = true;
    }

  } // end Constructor()

  /**
	 * ******************* Destructor ***********************
	 */

  ProgressCommand::~ProgressCommand()
  {
    this->DisconnectObserver( this->m_ObservedProcessObject );

  } // end Destructor()

  /**
	 * ******************* SetUpdateFrequency ***********************
	 */

  void ProgressCommand
    ::SetUpdateFrequency(
    const unsigned long numberOfVoxels,
    const unsigned long numberOfUpdates )
  {
    /** Set the member variables. */
    this->m_NumberOfVoxels  = numberOfVoxels;
    this->m_NumberOfUpdates = numberOfUpdates;

    /** Make sure we have at least one pixel. */
    if ( this->m_NumberOfVoxels < 1 )
    {
      this->m_NumberOfVoxels = 1;
    }

    /** We cannot update more times than there are pixels. */
    if ( this->m_NumberOfUpdates > this->m_NumberOfVoxels )
    {
      this->m_NumberOfUpdates = this->m_NumberOfVoxels;
    }

    /** Make sure we update at least once. */
    if ( this->m_NumberOfUpdates < 1 )
    {
      this->m_NumberOfUpdates = 1;
    }

  } // end SetUpdateFrequency()

  /**
	 * ******************* ConnectObserver ***********************
	 */

  void ProgressCommand
    ::ConnectObserver( ProcessObject * filter )
  {
    /** Disconnect from old observed filters. */
    this->DisconnectObserver( this->m_ObservedProcessObject );

    /** Connect to the new filter. */
    if ( this->m_StreamOutputIsConsole )
    {
      this->m_Tag = filter->AddObserver( itk::ProgressEvent(), this );
      this->m_TagIsSet = true;
      this->m_ObservedProcessObject = filter;
    }

  } // end ConnectObserver()

  /**
	 * ******************* DisconnectObserver ***********************
	 */

  void ProgressCommand
    ::DisconnectObserver( ProcessObject * filter )
  {
    if ( this->m_StreamOutputIsConsole )
    {
      if ( this->m_TagIsSet )
      {
        filter->RemoveObserver( this->m_Tag );
        this->m_TagIsSet = false;
        this->m_ObservedProcessObject = 0;
      }
    }

  } // end DisconnectObserver()

  /**
	 * ******************* Execute ***********************
	 */

  void ProgressCommand
    ::Execute( Object *caller, const EventObject &event )
  {
    ProcessObject *po = dynamic_cast<ProcessObject *>( caller );
    if ( !po ) return;

    if ( typeid( event ) == typeid( ProgressEvent ) )
    {
      this->PrintProgress( po->GetProgress() );
    }

  } // end Execute()

  /**
	 * ******************* Execute ***********************
	 */

  void ProgressCommand
    ::Execute( const Object *caller, const EventObject &event )
  {
    const ProcessObject *po = dynamic_cast<const ProcessObject *>( caller );
    if ( !po ) return;

    if ( typeid( event ) == typeid( ProgressEvent ) )
    {
      this->PrintProgress( po->GetProgress() );
    }

  } // end Execute()

  /**
	 * ******************* PrintProgress ***********************
	 */

  void ProgressCommand
    ::PrintProgress( const float & progress ) const
  {
    /** Print the progress to the screen. */
    int progressInt = vnl_math_rnd( 100 * progress );
    xl::xout["coutonly"]
      << "\r"
      << this->m_StartString
      << progressInt
      << this->m_EndString;
    xl::xout["coutonly"] << std::flush;

    /** If the process is completed, print an end-of-line. */
    if ( progress > 0.99999 )
    {
      xl::xout["coutonly"] << std::endl;
    }

  } // end PrintProgress()

  /**
	 * ******************* PrintProgress ***********************
	 */

  void ProgressCommand
    ::UpdateAndPrintProgress( const unsigned long & currentVoxelNumber ) const
  {
    if ( this->m_StreamOutputIsConsole )
    {
      const unsigned long frac =
        static_cast<unsigned long>( this->m_NumberOfVoxels / this->m_NumberOfUpdates );
      if ( currentVoxelNumber % frac == 0 )
      {
        this->PrintProgress(
          static_cast<float>( currentVoxelNumber ) /
          static_cast<float>( this->m_NumberOfVoxels ) );
      }
    }

  } // end PrintProgress()

} // end namespace itk

<|endoftext|>


<commit_before>/*
    Copyright 2012 Frederik Gladhorn <gladhorn@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "mainwindow.h"

#include <qitemselectionmodel.h>
#include <qplaintextedit.h>
#include <qstring.h>
#include <qtreeview.h>

#include "kdeaccessibilityclient/registry.h"
#include "kdeaccessibilityclient/accessibleobject.h"

#include "accessibletree.h"

#include "tests_auto_modeltest_modeltest.h"

using namespace KAccessibleClient;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), m_model(0)
{
    ui.setupUi(this);

    m_registry = new KAccessibleClient::Registry(this);
    connect(m_registry, SIGNAL(focusChanged(KAccessibleClient::AccessibleObject)), this, SLOT(focusChanged(KAccessibleClient::AccessibleObject)));
    m_registry->subscribeEventListeners(KAccessibleClient::Registry::Focus);

    m_model = new AccessibleTree(this);
    ui.treeView->setModel(m_model);
    ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(treeCustomContextMenuRequested(QPoint)));
    m_model->setRegistry(m_registry);

    // The ultimate model verificaton helper :p
    new ModelTest(m_model, this);

    connect(ui.treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(selectionChanged(QModelIndex,QModelIndex)));
    connect(ui.action_Reset_tree, SIGNAL(triggered()), m_model, SLOT(resetModel()));
    ui.action_Reset_tree->setShortcut(QKeySequence(QKeySequence::Refresh));
}

void MainWindow::focusChanged(const KAccessibleClient::AccessibleObject &object)
{
    ui.label->setText(tr("Focus changed to: %1 - %2 (%3)").arg(object.name()).arg(object.roleName()).arg(object.role()));

    if (ui.action_Follow_Focus->isChecked()) {
        QModelIndex index = m_model->indexForAccessible(object);
        if (index.isValid()) {
            ui.treeView->scrollTo(index);
            ui.treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
        }
    }
}

void MainWindow::selectionChanged(const QModelIndex& current, const QModelIndex&)
{
    QString text;

    if (current.isValid() && current.internalPointer()) {
        KAccessibleClient::AccessibleObject acc = static_cast<AccessibleWrapper*>(current.internalPointer())->acc;
        text += acc.name() + " (" + acc.description() + ")\n";
        text += "role: " + acc.roleName() + "\n";
        text += "checked: " + (acc.isChecked() ? QLatin1String("yes") : QLatin1String("no")) + '\n';

        text += "\nchildCount: " + QString::number(acc.childCount()) + "\n";
        foreach (const KAccessibleClient::AccessibleObject &child, acc.children()) {
            text += "child: " + child.name() + " (" + child.roleName() + ")\n";
        }

        Q_FOREACH(QAction *a, acc.actions()) {
            ui.treeView->insertAction(0, a);
        }

        QRect rect = acc.boundingRect();
        text += "\nCurrent Focus Coords: ( " + QString::number(rect.x()+rect.width()/2);
        text += " , " + QString::number(rect.y()+rect.height()/2) + " )\n";

        rect = acc.characterRect();
        text += "\nCurrent Text Focus: ( " + QString::number(rect.x()+rect.width()/2);
        text += " , " + QString::number(rect.y()+rect.height()/2) + " )\n";

        QStringList interfaces = acc.supportedInterfaces();
        text += "\nImplements Component Interface: ";
        text += QString(interfaces.contains("org.a11y.atspi.Component") ? "True" : "False") + "\n";
        text += "\nImplements Text Interface: ";
        text += QString(interfaces.contains("org.a11y.atspi.Text") ? "True" : "False") + "\n";
        text += "\nImplements Action Interface: ";
        text += QString(interfaces.contains("org.a11y.atspi.Action") ? "True" : "False") + "\n";

        text += "\nList of Interfaces:-";
        for (int i=0 ; i<interfaces.size() ; ++i)
            text += "\n\t" + interfaces.at(i);
    }

    ui.plainTextEdit->setPlainText(text);
}

void MainWindow::treeCustomContextMenuRequested(const QPoint &pos)
{
    QModelIndex current = ui.treeView->currentIndex();
    if (!current.isValid())
        return;
    KAccessibleClient::AccessibleObject acc = static_cast<AccessibleWrapper*>(current.internalPointer())->acc;
    QMenu *menu = new QMenu(this);
    connect(menu, SIGNAL(aboutToHide()), menu, SLOT(deleteLater()));
    Q_FOREACH(QAction *a, acc.actions()) {
        menu->addAction(a);
    }
    menu->popup(ui.treeView->mapToGlobal(pos));
}
<commit_msg>Not needed any longer<commit_after>/*
    Copyright 2012 Frederik Gladhorn <gladhorn@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "mainwindow.h"

#include <qitemselectionmodel.h>
#include <qplaintextedit.h>
#include <qstring.h>
#include <qtreeview.h>

#include "kdeaccessibilityclient/registry.h"
#include "kdeaccessibilityclient/accessibleobject.h"

#include "accessibletree.h"

#include "tests_auto_modeltest_modeltest.h"

using namespace KAccessibleClient;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), m_model(0)
{
    ui.setupUi(this);

    m_registry = new KAccessibleClient::Registry(this);
    connect(m_registry, SIGNAL(focusChanged(KAccessibleClient::AccessibleObject)), this, SLOT(focusChanged(KAccessibleClient::AccessibleObject)));
    m_registry->subscribeEventListeners(KAccessibleClient::Registry::Focus);

    m_model = new AccessibleTree(this);
    ui.treeView->setModel(m_model);
    ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(treeCustomContextMenuRequested(QPoint)));
    m_model->setRegistry(m_registry);

    // The ultimate model verificaton helper :p
    new ModelTest(m_model, this);

    connect(ui.treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(selectionChanged(QModelIndex,QModelIndex)));
    connect(ui.action_Reset_tree, SIGNAL(triggered()), m_model, SLOT(resetModel()));
    ui.action_Reset_tree->setShortcut(QKeySequence(QKeySequence::Refresh));
}

void MainWindow::focusChanged(const KAccessibleClient::AccessibleObject &object)
{
    ui.label->setText(tr("Focus changed to: %1 - %2 (%3)").arg(object.name()).arg(object.roleName()).arg(object.role()));

    if (ui.action_Follow_Focus->isChecked()) {
        QModelIndex index = m_model->indexForAccessible(object);
        if (index.isValid()) {
            ui.treeView->scrollTo(index);
            ui.treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
        }
    }
}

void MainWindow::selectionChanged(const QModelIndex& current, const QModelIndex&)
{
    QString text;

    if (current.isValid() && current.internalPointer()) {
        KAccessibleClient::AccessibleObject acc = static_cast<AccessibleWrapper*>(current.internalPointer())->acc;
        text += acc.name() + " (" + acc.description() + ")\n";
        text += "role: " + acc.roleName() + "\n";
        text += "checked: " + (acc.isChecked() ? QLatin1String("yes") : QLatin1String("no")) + '\n';

        text += "\nchildCount: " + QString::number(acc.childCount()) + "\n";
        foreach (const KAccessibleClient::AccessibleObject &child, acc.children()) {
            text += "child: " + child.name() + " (" + child.roleName() + ")\n";
        }

        QRect rect = acc.boundingRect();
        text += "\nCurrent Focus Coords: ( " + QString::number(rect.x()+rect.width()/2);
        text += " , " + QString::number(rect.y()+rect.height()/2) + " )\n";

        rect = acc.characterRect();
        text += "\nCurrent Text Focus: ( " + QString::number(rect.x()+rect.width()/2);
        text += " , " + QString::number(rect.y()+rect.height()/2) + " )\n";

        QStringList interfaces = acc.supportedInterfaces();
        text += "\nImplements Component Interface: ";
        text += QString(interfaces.contains("org.a11y.atspi.Component") ? "True" : "False") + "\n";
        text += "\nImplements Text Interface: ";
        text += QString(interfaces.contains("org.a11y.atspi.Text") ? "True" : "False") + "\n";
        text += "\nImplements Action Interface: ";
        text += QString(interfaces.contains("org.a11y.atspi.Action") ? "True" : "False") + "\n";

        text += "\nList of Interfaces:-";
        for (int i=0 ; i<interfaces.size() ; ++i)
            text += "\n\t" + interfaces.at(i);
    }

    ui.plainTextEdit->setPlainText(text);
}

void MainWindow::treeCustomContextMenuRequested(const QPoint &pos)
{
    QModelIndex current = ui.treeView->currentIndex();
    if (!current.isValid())
        return;
    KAccessibleClient::AccessibleObject acc = static_cast<AccessibleWrapper*>(current.internalPointer())->acc;
    QMenu *menu = new QMenu(this);
    connect(menu, SIGNAL(aboutToHide()), menu, SLOT(deleteLater()));
    Q_FOREACH(QAction *a, acc.actions()) {
        menu->addAction(a);
    }
    menu->popup(ui.treeView->mapToGlobal(pos));
}
<|endoftext|>


<commit_before>#include <iostream>
#include <TFile.h>

int GenerateFile(const TString& library, const TString& file)
{
    std::cout << "Loading " << library << std::endl;
    gSystem->Load(library);

    std::cout << "Filling " << file << std::endl;
    TMyClass obj("A description");
	obj.SetName("Hello");
	obj.fFloats[2] = 5;

    TFile out(file, "RECREATE");
    obj.Write();

    return 0;
}
<commit_msg>Add a vector at first level in the test root file<commit_after>#include <iostream>
#include <TFile.h>
#include <TVector.h>

int GenerateFile(const TString& library, const TString& file)
{
    std::cout << "Loading " << library << std::endl;
    gSystem->Load(library);

    std::cout << "Filling " << file << std::endl;
    TMyClass obj("A description");
	obj.SetName("Hello");
	obj.fFloats[2] = 5;

    TVector firstLevelVector;
    firstLevelVector.ResizeTo(20);
    for (size_t i = 0; i < firstLevelVector.GetNoElements(); ++i)
        firstLevelVector[i] = 42;

    TFile out(file, "RECREATE");
    obj.Write();
    firstLevelVector.Write();

    return 0;
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2009 Volker Krause <vkrause@kde.org>

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

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

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

#include "move.h"

#include <akonadiconnection.h>
#include <entities.h>
#include <imapstreamparser.h>
#include <handlerhelper.h>
#include <storage/datastore.h>
#include <storage/itemretriever.h>
#include <storage/itemqueryhelper.h>
#include <storage/selectquerybuilder.h>
#include <storage/transaction.h>
#include <storage/collectionqueryhelper.h>

namespace Akonadi {

Move::Move( Scope::SelectionScope scope ) :
  mScope( scope )
{
}

bool Move::parseStream()
{
  mScope.parseScope( m_streamParser );

  Scope destScope( mScope.scope() );
  destScope.parseScope( m_streamParser );
  const Collection destination = CollectionQueryHelper::singleCollectionFromScope( destScope, connection() );
  const Resource destResource = destination.resource();

  // make sure all the items we want to move are in the cache
  ItemRetriever retriever( connection() );
  retriever.setScope( mScope );
  retriever.setRetrieveFullPayload( true );
  if (!retriever.exec()) {
    return failureResponse( retriever.lastError() );
  }

  DataStore *store = connection()->storageBackend();
  Transaction transaction( store );

  SelectQueryBuilder<PimItem> qb;
  ItemQueryHelper::scopeToQuery( mScope, connection(), qb );
  qb.addValueCondition( PimItem::collectionIdFullColumnName(), Query::NotEquals, destination.id() );

  const QDateTime mtime = QDateTime::currentDateTime();

  if ( qb.exec() ) {
    const QVector<PimItem> items = qb.result();
    if ( items.isEmpty() )
      throw HandlerException( "No items found" );

    // Split the list by source collection
    QMap<Entity::Id /* collection */, PimItem> toMove;
    QMap<Entity::Id /* collection */, Collection> sources;
    Q_FOREACH ( /*sic!*/ PimItem item, items ) {
      const Collection source = items.first().collection();
      if ( !source.isValid() )
        throw HandlerException( "Item without collection found!?" );
      if ( !sources.contains( source.id() ) ) {
        sources.insert( source.id(), source );
      }

      if ( !item.isValid() )
        throw HandlerException( "Invalid item in result set!?" );
      Q_ASSERT( item.collectionId() != destination.id() );

      item.setCollectionId( destination.id() );
      item.setAtime( mtime );
      item.setDatetime( mtime );
      // if the resource moved itself, we assume it did so because the change happend in the backend
      if ( connection()->resourceContext().id() != destResource.id() )
        item.setDirty( true );

      toMove.insertMulti( source.id(), item );
    }

    // Emit notification for each source collection separately
    Q_FOREACH ( const Entity::Id &sourceId, toMove.uniqueKeys() ) {
      const PimItem::List &itemsToMove = toMove.values( sourceId ).toVector();
      const Collection &source = sources.value( sourceId );
      store->notificationCollector()->itemsMoved( itemsToMove, source, destination );

      Q_FOREACH ( PimItem moved, toMove.values( sourceId ) ) {
        // reset RID on inter-resource moves, but only after generating the change notification
        // so that this still contains the old one for the source resource
        const bool isInterResourceMove = moved.collection().resource().id() != destResource.id();
        if ( isInterResourceMove )
          moved.setRemoteId( QString() );

        // FIXME Could we aggregate the changes to a single SQL query?
        if ( !moved.update() ) {
          throw HandlerException( "Unable to update item" );
        }
      }
    }
  } else {
    throw HandlerException( "Unable to execute query" );
  }

  if ( !transaction.commit() )
    return failureResponse( "Unable to commit transaction." );

  return successResponse( "MOVE complete" );
}

}

<commit_msg>coding style<commit_after>/*
    Copyright (c) 2009 Volker Krause <vkrause@kde.org>

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

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

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

#include "move.h"

#include <akonadiconnection.h>
#include <entities.h>
#include <imapstreamparser.h>
#include <handlerhelper.h>
#include <storage/datastore.h>
#include <storage/itemretriever.h>
#include <storage/itemqueryhelper.h>
#include <storage/selectquerybuilder.h>
#include <storage/transaction.h>
#include <storage/collectionqueryhelper.h>

namespace Akonadi {

Move::Move( Scope::SelectionScope scope ) :
  mScope( scope )
{
}

bool Move::parseStream()
{
  mScope.parseScope( m_streamParser );

  Scope destScope( mScope.scope() );
  destScope.parseScope( m_streamParser );
  const Collection destination = CollectionQueryHelper::singleCollectionFromScope( destScope, connection() );
  const Resource destResource = destination.resource();

  // make sure all the items we want to move are in the cache
  ItemRetriever retriever( connection() );
  retriever.setScope( mScope );
  retriever.setRetrieveFullPayload( true );
  if (!retriever.exec()) {
    return failureResponse( retriever.lastError() );
  }

  DataStore *store = connection()->storageBackend();
  Transaction transaction( store );

  SelectQueryBuilder<PimItem> qb;
  ItemQueryHelper::scopeToQuery( mScope, connection(), qb );
  qb.addValueCondition( PimItem::collectionIdFullColumnName(), Query::NotEquals, destination.id() );

  const QDateTime mtime = QDateTime::currentDateTime();

  if ( qb.exec() ) {
    const QVector<PimItem> items = qb.result();
    if ( items.isEmpty() ) {
      throw HandlerException( "No items found" );
    }

    // Split the list by source collection
    QMap<Entity::Id /* collection */, PimItem> toMove;
    QMap<Entity::Id /* collection */, Collection> sources;
    Q_FOREACH ( /*sic!*/ PimItem item, items ) {
      const Collection source = items.first().collection();
      if ( !source.isValid() ) {
        throw HandlerException( "Item without collection found!?" );
      }
      if ( !sources.contains( source.id() ) ) {
        sources.insert( source.id(), source );
      }

      if ( !item.isValid() ) {
        throw HandlerException( "Invalid item in result set!?" );
      }
      Q_ASSERT( item.collectionId() != destination.id() );

      item.setCollectionId( destination.id() );
      item.setAtime( mtime );
      item.setDatetime( mtime );
      // if the resource moved itself, we assume it did so because the change happend in the backend
      if ( connection()->resourceContext().id() != destResource.id() ) {
        item.setDirty( true );
      }

      toMove.insertMulti( source.id(), item );
    }

    // Emit notification for each source collection separately
    Q_FOREACH ( const Entity::Id &sourceId, toMove.uniqueKeys() ) {
      const PimItem::List &itemsToMove = toMove.values( sourceId ).toVector();
      const Collection &source = sources.value( sourceId );
      store->notificationCollector()->itemsMoved( itemsToMove, source, destination );

      Q_FOREACH ( PimItem moved, toMove.values( sourceId ) ) {
        // reset RID on inter-resource moves, but only after generating the change notification
        // so that this still contains the old one for the source resource
        const bool isInterResourceMove = moved.collection().resource().id() != destResource.id();
        if ( isInterResourceMove ) {
          moved.setRemoteId( QString() );
        }

        // FIXME Could we aggregate the changes to a single SQL query?
        if ( !moved.update() ) {
          throw HandlerException( "Unable to update item" );
        }
      }
    }
  } else {
    throw HandlerException( "Unable to execute query" );
  }

  if ( !transaction.commit() ) {
    return failureResponse( "Unable to commit transaction." );
  }

  return successResponse( "MOVE complete" );
}

}
<|endoftext|>


<commit_before>/*
 * File:   virusscan.c
 *
 * Copyright 2013 Heinrich Schuchardt <xypron.glpk@gmx.de>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 VirusScan.cc
 * @brief Scans files for viruses.
 */
#include <cstring>
#include <limits.h>
#include <signal.h>
#include <sstream>
#include <stdio.h>
#include <syslog.h>
#include "unistd.h"
#include "VirusScan.h"
#include "Messaging.h"

/**
 * @brief Initializes virus scan engine.
 */
VirusScan::VirusScan(Environment * e) {
    int ret;

    env = e;
    status = RUNNING;
    pthread_mutex_init(&mutexEngine, NULL);
    pthread_mutex_init(&mutexUpdate, NULL);

    ret = cl_init(CL_INIT_DEFAULT);
    if (ret != CL_SUCCESS) {
        std::stringstream msg;
        msg << "cl_init() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        throw SCANERROR;
    }

    // Create virus scan engine.
    engine = createEngine();
    // Initialize monitoring of pattern update.
    dbstat_clear();

    if (createThread()) {
        Messaging::message(Messaging::ERROR, "Cannot create thread.");
        cl_engine_free(engine);
        throw SCANERROR;
    }
}

/**
 * @brief Creates a new virus scan engine.
 *
 * @return virus scan engine
 */
struct cl_engine *VirusScan::createEngine() {
    int ret;
    unsigned int sigs;
    cl_engine *e;

    Messaging::message(Messaging::DEBUG, "Loading virus database");
    e = cl_engine_new();
    if (e == NULL) {
        Messaging::message(Messaging::ERROR,
                "Can't create new virus scan engine.");
        throw SCANERROR;
    }
    // sigs must be zero before calling cl_load.
    sigs = 0;
    ret = cl_load(cl_retdbdir(), e, &sigs, CL_DB_STDOPT);
    if (ret != CL_SUCCESS) {
        std::stringstream msg;
        msg << "cl_retdbdir() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        cl_engine_free(e);
        throw SCANERROR;
    } else {
        std::stringstream msg;
        msg << sigs << "  signatures loaded";
        Messaging::message(Messaging::DEBUG, msg.str());
    }
    if ((ret = cl_engine_compile(e)) != CL_SUCCESS) {
        std::stringstream msg;
        msg << "cl_engine_compile() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        cl_engine_free(e);
        throw SCANERROR;
    }
    return e;
}

/**
 * Destroys virus scan engine.
 * @param e virus scan engine
 */
void VirusScan::destroyEngine(cl_engine *e) {
    int ret;
    ret = cl_engine_free(e);
    if (ret != 0) {
        std::stringstream msg;
        msg << "cl_engine_free() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        throw SCANERROR;
    }
}

/**
 * @brief Gets reference to virus scan engine.
 *
 * @return scan engine
 */
struct cl_engine *VirusScan::getEngine() {
    struct cl_engine *ret = NULL;

    // Wait for update to complete
    pthread_mutex_lock(&mutexUpdate);
    pthread_mutex_unlock(&mutexUpdate);

    pthread_mutex_lock(&mutexEngine);
    ret = engine;
    engineRefCount++;
    pthread_mutex_unlock(&mutexEngine);
    return ret;
}

/**
 * @brief Creates a new thread for managing the scan engine.
 *
 * @return success = 0
 */
int VirusScan::createThread() {
    int ret;

    if (pthread_create(&updateThread, NULL, updater, this)) {
        ret = 1;
    } else {
        ret = 0;
    }
    return ret;
}

/**
 * @brief Checks if database has changed.
 * @returned 0 = unchanged, 1 = changed
 */
int VirusScan::dbstat_check() {
    int ret = 0;
    if (cl_statchkdir(&dbstat) == 1) {
        ret = 1;
        cl_statfree(&dbstat);
        cl_statinidir(cl_retdbdir(), &dbstat);
    }
    return ret;
}

/**
 * @brief Clears database status.
 */
void VirusScan::dbstat_clear() {
    memset(&dbstat, 0, sizeof (struct cl_stat));
    cl_statinidir(cl_retdbdir(), &dbstat);
}

/**
 * @brief Frees database status.
 */
void VirusScan::dbstat_free() {
    cl_statfree(&dbstat);
}

/**
 * @brief Writes log entry.
 *
 * @param fd file descriptor
 * @param virname name of virus
 */
void VirusScan::log_virus_found(const int fd, const char *virname) {
    int path_len;
    char path[PATH_MAX + 1];
    std::stringstream msg;

    snprintf(path, sizeof (path), "/proc/self/fd/%d", fd);
    path_len = readlink(path, path, sizeof (path) - 1);
    if (path_len < 0) {
        path_len = 0;
    }
    path[path_len] = '\0';
    msg << "Virus \"" << virname << "\" detected in file \"" << path << "\".";
    Messaging::message(Messaging::ERROR, msg.str());
}

/**
 * Decreases the viurs engine reference count.
 */
void VirusScan::releaseEngine() {
    pthread_mutex_lock(&mutexEngine);
    engineRefCount--;
    pthread_mutex_unlock(&mutexEngine);
}

/**
 * @brief Scans file for virus.
 *
 * @return success
 */
int VirusScan::scan(const int fd) {
    int success = SCANOK;
    int ret;
    const char *virname;

    ret = cl_scandesc(fd, &virname, NULL, getEngine(), CL_SCAN_STDOPT);
    switch (ret) {
        case CL_CLEAN:
            success = SCANOK;
            break;
        case CL_VIRUS:
            log_virus_found(fd, virname);
            success = SCANVIRUS;
            break;
        default:
            std::stringstream msg;
            msg << "cl_scandesc() error: " << cl_strerror(ret);
            Messaging::message(Messaging::ERROR, msg.str());
            success = SCANOK;
            break;
    }
    releaseEngine();
    return success;
}

/**
 * @brief Thread to update engine.
 *
 * @param threadPool thread pool
 * @return return value
 */
void * VirusScan::updater(void *virusScan) {
    int count = 0;
    cl_engine *e;
    struct timespec interval = {
        1,
        0
    };
    struct timespec interval2 = {
        0,
        100000
    };
    VirusScan *vs;

    vs = (VirusScan *) virusScan;

    for (;;) {
        if (vs->status == STOPPING) {
            break;
        }
        nanosleep(&interval, NULL);
        count++;
        // Every minute check for virus database updates
        if (count >= 60) {
            if (vs->dbstat_check()) {
                Messaging::message(Messaging::DEBUG,
                        "Database update detected.");
                try {
                    // Create the new engine.
                    e = vs->createEngine();
                    // Stop scanning.
                    pthread_mutex_lock(&(vs->mutexUpdate));
                    // Wait for all running scans to be finished.
                    for (;;) {
                        pthread_mutex_lock(&(vs->mutexEngine));
                        if (vs->engineRefCount == 0) {
                            break;
                        }
                        pthread_mutex_unlock(&(vs->mutexEngine));
                        nanosleep(&interval2, NULL);
                    }
                    // Destroy the old engine
                    vs->destroyEngine(vs->engine);
                    vs->engine = e;
                    vs->env->getScanCache()->clear();
                    pthread_mutex_unlock(&(vs->mutexEngine));
                    Messaging::message(Messaging::DEBUG,
                            "Using updated database.");
                } catch (Status e) {
                }
                // Allow scanning.
                pthread_mutex_unlock(&(vs->mutexUpdate));
            }
        }
    }
    vs->status = STOPPED;
    return NULL;
}

/**
 * @brief Deletes the virus scanner.
 */
VirusScan::~VirusScan() {
    struct timespec interval = {
        0,
        1000000
    };

    status = STOPPING;
    do {
        nanosleep(&interval, NULL);
    } while (status == STOPPING);

    destroyEngine(engine);
    pthread_mutex_destroy(&mutexUpdate);
    pthread_mutex_destroy(&mutexEngine);
    dbstat_free();
}
<commit_msg>VirusScan: Message level for changed database<commit_after>/*
 * File:   virusscan.c
 *
 * Copyright 2013 Heinrich Schuchardt <xypron.glpk@gmx.de>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 VirusScan.cc
 * @brief Scans files for viruses.
 */
#include <cstring>
#include <limits.h>
#include <signal.h>
#include <sstream>
#include <stdio.h>
#include <syslog.h>
#include "unistd.h"
#include "VirusScan.h"
#include "Messaging.h"

/**
 * @brief Initializes virus scan engine.
 */
VirusScan::VirusScan(Environment * e) {
    int ret;

    env = e;
    status = RUNNING;
    pthread_mutex_init(&mutexEngine, NULL);
    pthread_mutex_init(&mutexUpdate, NULL);

    ret = cl_init(CL_INIT_DEFAULT);
    if (ret != CL_SUCCESS) {
        std::stringstream msg;
        msg << "cl_init() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        throw SCANERROR;
    }

    // Create virus scan engine.
    engine = createEngine();
    // Initialize monitoring of pattern update.
    dbstat_clear();

    if (createThread()) {
        Messaging::message(Messaging::ERROR, "Cannot create thread.");
        cl_engine_free(engine);
        throw SCANERROR;
    }
}

/**
 * @brief Creates a new virus scan engine.
 *
 * @return virus scan engine
 */
struct cl_engine *VirusScan::createEngine() {
    int ret;
    unsigned int sigs;
    cl_engine *e;

    Messaging::message(Messaging::DEBUG, "Loading virus database");
    e = cl_engine_new();
    if (e == NULL) {
        Messaging::message(Messaging::ERROR,
                "Can't create new virus scan engine.");
        throw SCANERROR;
    }
    // sigs must be zero before calling cl_load.
    sigs = 0;
    ret = cl_load(cl_retdbdir(), e, &sigs, CL_DB_STDOPT);
    if (ret != CL_SUCCESS) {
        std::stringstream msg;
        msg << "cl_retdbdir() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        cl_engine_free(e);
        throw SCANERROR;
    } else {
        std::stringstream msg;
        msg << sigs << "  signatures loaded";
        Messaging::message(Messaging::DEBUG, msg.str());
    }
    if ((ret = cl_engine_compile(e)) != CL_SUCCESS) {
        std::stringstream msg;
        msg << "cl_engine_compile() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        cl_engine_free(e);
        throw SCANERROR;
    }
    return e;
}

/**
 * Destroys virus scan engine.
 * @param e virus scan engine
 */
void VirusScan::destroyEngine(cl_engine *e) {
    int ret;
    ret = cl_engine_free(e);
    if (ret != 0) {
        std::stringstream msg;
        msg << "cl_engine_free() error: " << cl_strerror(ret);
        Messaging::message(Messaging::ERROR, msg.str());
        throw SCANERROR;
    }
}

/**
 * @brief Gets reference to virus scan engine.
 *
 * @return scan engine
 */
struct cl_engine *VirusScan::getEngine() {
    struct cl_engine *ret = NULL;

    // Wait for update to complete
    pthread_mutex_lock(&mutexUpdate);
    pthread_mutex_unlock(&mutexUpdate);

    pthread_mutex_lock(&mutexEngine);
    ret = engine;
    engineRefCount++;
    pthread_mutex_unlock(&mutexEngine);
    return ret;
}

/**
 * @brief Creates a new thread for managing the scan engine.
 *
 * @return success = 0
 */
int VirusScan::createThread() {
    int ret;

    if (pthread_create(&updateThread, NULL, updater, this)) {
        ret = 1;
    } else {
        ret = 0;
    }
    return ret;
}

/**
 * @brief Checks if database has changed.
 * @returned 0 = unchanged, 1 = changed
 */
int VirusScan::dbstat_check() {
    int ret = 0;
    if (cl_statchkdir(&dbstat) == 1) {
        ret = 1;
        cl_statfree(&dbstat);
        cl_statinidir(cl_retdbdir(), &dbstat);
    }
    return ret;
}

/**
 * @brief Clears database status.
 */
void VirusScan::dbstat_clear() {
    memset(&dbstat, 0, sizeof (struct cl_stat));
    cl_statinidir(cl_retdbdir(), &dbstat);
}

/**
 * @brief Frees database status.
 */
void VirusScan::dbstat_free() {
    cl_statfree(&dbstat);
}

/**
 * @brief Writes log entry.
 *
 * @param fd file descriptor
 * @param virname name of virus
 */
void VirusScan::log_virus_found(const int fd, const char *virname) {
    int path_len;
    char path[PATH_MAX + 1];
    std::stringstream msg;

    snprintf(path, sizeof (path), "/proc/self/fd/%d", fd);
    path_len = readlink(path, path, sizeof (path) - 1);
    if (path_len < 0) {
        path_len = 0;
    }
    path[path_len] = '\0';
    msg << "Virus \"" << virname << "\" detected in file \"" << path << "\".";
    Messaging::message(Messaging::ERROR, msg.str());
}

/**
 * Decreases the viurs engine reference count.
 */
void VirusScan::releaseEngine() {
    pthread_mutex_lock(&mutexEngine);
    engineRefCount--;
    pthread_mutex_unlock(&mutexEngine);
}

/**
 * @brief Scans file for virus.
 *
 * @return success
 */
int VirusScan::scan(const int fd) {
    int success = SCANOK;
    int ret;
    const char *virname;

    ret = cl_scandesc(fd, &virname, NULL, getEngine(), CL_SCAN_STDOPT);
    switch (ret) {
        case CL_CLEAN:
            success = SCANOK;
            break;
        case CL_VIRUS:
            log_virus_found(fd, virname);
            success = SCANVIRUS;
            break;
        default:
            std::stringstream msg;
            msg << "cl_scandesc() error: " << cl_strerror(ret);
            Messaging::message(Messaging::ERROR, msg.str());
            success = SCANOK;
            break;
    }
    releaseEngine();
    return success;
}

/**
 * @brief Thread to update engine.
 *
 * @param threadPool thread pool
 * @return return value
 */
void * VirusScan::updater(void *virusScan) {
    int count = 0;
    cl_engine *e;
    struct timespec interval = {
        1,
        0
    };
    struct timespec interval2 = {
        0,
        100000
    };
    VirusScan *vs;

    vs = (VirusScan *) virusScan;

    for (;;) {
        if (vs->status == STOPPING) {
            break;
        }
        nanosleep(&interval, NULL);
        count++;
        // Every minute check for virus database updates
        if (count >= 60) {
            if (vs->dbstat_check()) {
                Messaging::message(Messaging::INFORMATION,
                        "ClamAV database update detected.");
                try {
                    // Create the new engine.
                    e = vs->createEngine();
                    // Stop scanning.
                    pthread_mutex_lock(&(vs->mutexUpdate));
                    // Wait for all running scans to be finished.
                    for (;;) {
                        pthread_mutex_lock(&(vs->mutexEngine));
                        if (vs->engineRefCount == 0) {
                            break;
                        }
                        pthread_mutex_unlock(&(vs->mutexEngine));
                        nanosleep(&interval2, NULL);
                    }
                    // Destroy the old engine
                    vs->destroyEngine(vs->engine);
                    vs->engine = e;
                    vs->env->getScanCache()->clear();
                    pthread_mutex_unlock(&(vs->mutexEngine));
                    Messaging::message(Messaging::INFORMATION,
                            "Using updated ClamAV database.");
                } catch (Status e) {
                }
                // Allow scanning.
                pthread_mutex_unlock(&(vs->mutexUpdate));
            }
        }
    }
    vs->status = STOPPED;
    return NULL;
}

/**
 * @brief Deletes the virus scanner.
 */
VirusScan::~VirusScan() {
    struct timespec interval = {
        0,
        1000000
    };

    status = STOPPING;
    do {
        nanosleep(&interval, NULL);
    } while (status == STOPPING);

    destroyEngine(engine);
    pthread_mutex_destroy(&mutexUpdate);
    pthread_mutex_destroy(&mutexEngine);
    dbstat_free();
}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2017      Mellanox Technologies Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <inttypes.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include <infiniband/verbs_exp.h>

#include "env.h"

#define SZ 1024

struct ibvt_qp_sig : public ibvt_qp_rc {
	ibvt_qp_sig(ibvt_env &e, ibvt_pd &p, ibvt_cq &c) :
		ibvt_qp_rc(e, p, c) {}

	virtual void init_attr(struct ibv_qp_init_attr_ex &attr) {
		ibvt_qp_rc::init_attr(attr);
		attr.comp_mask |= IBV_EXP_QP_INIT_ATTR_CREATE_FLAGS;
		attr.exp_create_flags |= IBV_EXP_QP_CREATE_SIGNATURE_EN;
	}
};

struct ibvt_mr_sig : public ibvt_mr {
	ibvt_mr_sig(ibvt_env &e, ibvt_pd &p, size_t s) :
		ibvt_mr(e, p, s) {}

	virtual void init() {
		struct ibv_exp_create_mr_in in = {};
		if (mr)
			return;

		in.pd = pd.pd;
		in.attr.max_klm_list_size = 1;
		in.attr.create_flags = IBV_EXP_MR_SIGNATURE_EN;
		in.attr.exp_access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE;
		SET(mr, ibv_exp_create_mr(&in));
	}
};

struct sig_test : public testing::Test, public ibvt_env {
	struct ibvt_ctx ctx;
	struct ibvt_pd pd;
	struct ibvt_cq cq;
	struct ibvt_qp_sig send_qp;
	struct ibvt_qp_sig recv_qp;
	struct ibvt_mr src_mr;
	struct ibvt_mr mid_mr;
	struct ibvt_mr dst_mr;
	struct ibvt_mr_sig insert_mr;
	struct ibvt_mr_sig strip_mr;

	sig_test() :
		ctx(*this, NULL),
		pd(*this, ctx),
		cq(*this, ctx),
		send_qp(*this, pd, cq),
		recv_qp(*this, pd, cq),
		src_mr(*this, pd, 1024),
		mid_mr(*this, pd, 1040),
		dst_mr(*this, pd, 1024),
		insert_mr(*this, pd, 1040),
		strip_mr(*this, pd, 1040)
	{ }

	#define CHECK_REF_TAG 0x0f
	#define CHECK_APP_TAG 0x30
	#define CHECK_GUARD   0xc0

	virtual void config(ibvt_mr &sig_mr, ibvt_mr &data_mr, int dir) {
		struct ibv_sge sge = data_mr.sge();
		struct ibv_send_wr wr = {};
		struct ibv_send_wr *bad_wr;
		struct ibv_exp_sig_attrs sig = {};

		sig.check_mask |= CHECK_REF_TAG;
		sig.check_mask |= CHECK_APP_TAG;
		sig.check_mask |= CHECK_GUARD;
		if (dir) {
			sig.mem.sig_type = IBV_EXP_SIG_TYPE_T10_DIF;
			sig.mem.sig.dif.bg_type = IBV_EXP_T10DIF_CRC;
			sig.mem.sig.dif.pi_interval = 512;
			sig.mem.sig.dif.bg = 0x1234;
			sig.mem.sig.dif.app_tag = 0x5678;
			sig.mem.sig.dif.ref_tag = 0xabcdef90;
			sig.mem.sig.dif.ref_remap = 1;
			sig.mem.sig.dif.app_escape = 1;
			sig.mem.sig.dif.ref_escape = 1;
			sig.mem.sig.dif.apptag_check_mask = 0xffff;
		} else {
			sig.mem.sig_type = IBV_EXP_SIG_TYPE_NONE;
		}

		if (dir) {
			sig.wire.sig_type = IBV_EXP_SIG_TYPE_NONE;
		} else {
			sig.wire.sig_type = IBV_EXP_SIG_TYPE_T10_DIF;
			sig.wire.sig.dif.bg_type = IBV_EXP_T10DIF_CRC;
			sig.wire.sig.dif.pi_interval = 512;
			sig.wire.sig.dif.bg = 0x1234;
			sig.wire.sig.dif.app_tag = 0x5678;
			sig.wire.sig.dif.ref_tag = 0xabcdef90;
			sig.wire.sig.dif.ref_remap = 1;
			sig.wire.sig.dif.app_escape = 1;
			sig.wire.sig.dif.ref_escape = 1;
			sig.wire.sig.dif.apptag_check_mask = 0xffff;
		}

		wr.exp_opcode = IBV_EXP_WR_REG_SIG_MR;
		wr.exp_send_flags = IBV_EXP_SEND_SIGNALED;
		wr.ext_op.sig_handover.sig_attrs = &sig;
		wr.ext_op.sig_handover.sig_mr = sig_mr.mr;
		wr.ext_op.sig_handover.access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE;
		wr.ext_op.sig_handover.prot = NULL;

		wr.num_sge = 1;
		wr.sg_list = &sge;

		DO(ibv_post_send(send_qp.qp, &wr, &bad_wr));
	}

	void mr_status(ibvt_mr &mr, int expected) {
		struct ibv_exp_mr_status status;

		DO(ibv_exp_check_mr_status(mr.mr, IBV_EXP_MR_CHECK_SIG_STATUS,
					   &status));
		VERBS_INFO("SEGERR %d %x %x %lx\n",
			   status.sig_err.err_type,
			   status.sig_err.expected,
			   status.sig_err.actual,
			   status.sig_err.sig_err_offset);
		ASSERT_EQ(expected, status.fail_status);
	}

	virtual void SetUp() {
		INIT(ctx.init());
		if (skip)
			return;
		INIT(send_qp.init());
		INIT(recv_qp.init());
		INIT(send_qp.connect(&recv_qp));
		INIT(recv_qp.connect(&send_qp));
		INIT(insert_mr.init());
		INIT(strip_mr.init());
		INIT(src_mr.fill());
		INIT(mid_mr.init());
		INIT(dst_mr.init());
		INIT(cq.arm());
	}

	virtual void TearDown() {
		ASSERT_FALSE(HasFailure());
	}
};

TEST_F(sig_test, t0) {
	CHK_SUT(sig_handover);
	EXEC(config(this->insert_mr, this->src_mr, 0));
	EXEC(cq.poll(1));
	EXEC(config(this->strip_mr, this->mid_mr, 1));
	EXEC(cq.poll(1));
	EXEC(send_qp.rdma(this->insert_mr.sge(), this->mid_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(recv_qp.rdma(this->dst_mr.sge(), this->strip_mr.sge(), IBV_WR_RDMA_READ));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 0));
	EXEC(dst_mr.check());
}

TEST_F(sig_test, t1) {
	CHK_SUT(sig_handover);
	EXEC(config(this->strip_mr, this->mid_mr, 1));
	EXEC(cq.poll(1));
	EXEC(recv_qp.rdma(this->dst_mr.sge(), this->strip_mr.sge(), IBV_WR_RDMA_READ));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 1));
}

<commit_msg>Add SIG pipeline tests<commit_after>/**
 * Copyright (C) 2017      Mellanox Technologies Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <inttypes.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include <infiniband/verbs_exp.h>

#include "env.h"

#define SZ 1024

struct ibvt_qp_sig : public ibvt_qp_rc {
	ibvt_qp_sig(ibvt_env &e, ibvt_pd &p, ibvt_cq &c) :
		ibvt_qp_rc(e, p, c) {}

	virtual void init_attr(struct ibv_qp_init_attr_ex &attr) {
		ibvt_qp_rc::init_attr(attr);
		attr.comp_mask |= IBV_EXP_QP_INIT_ATTR_CREATE_FLAGS;
		attr.exp_create_flags |= IBV_EXP_QP_CREATE_SIGNATURE_EN;
	}

	virtual void send_2wr(ibv_sge sge, ibv_sge sge2) {
		struct ibv_send_wr wr = {};
		struct ibv_send_wr wr2 = {};
		struct ibv_send_wr *bad_wr = NULL;

		wr.next = &wr2;
		wr.sg_list = &sge;
		wr.num_sge = 1;
		wr._wr_opcode = IBV_WR_SEND;

		wr2.sg_list = &sge2;
		wr2.num_sge = 1;
		wr2._wr_opcode = IBV_WR_SEND;
		wr2._wr_send_flags = IBV_EXP_SEND_SIGNALED |
				     IBV_EXP_SEND_SIG_PIPELINED;

		DO(ibv_post_send(qp, &wr, &bad_wr));
	}

};

struct ibvt_qp_sig_pipeline : public ibvt_qp_sig {
	ibvt_qp_sig_pipeline(ibvt_env &e, ibvt_pd &p, ibvt_cq &c) :
		ibvt_qp_sig(e, p, c) {}

	virtual void init_attr(struct ibv_qp_init_attr_ex &attr) {
		ibvt_qp_sig::init_attr(attr);
		attr.exp_create_flags |= IBV_EXP_QP_CREATE_SIGNATURE_PIPELINE;
	}

};

struct ibvt_mr_sig : public ibvt_mr {
	ibvt_mr_sig(ibvt_env &e, ibvt_pd &p, size_t s) :
		ibvt_mr(e, p, s) {}

	virtual void init() {
		struct ibv_exp_create_mr_in in = {};
		if (mr)
			return;

		in.pd = pd.pd;
		in.attr.max_klm_list_size = 1;
		in.attr.create_flags = IBV_EXP_MR_SIGNATURE_EN;
		in.attr.exp_access_flags = IBV_ACCESS_LOCAL_WRITE |
					   IBV_ACCESS_REMOTE_READ |
					   IBV_ACCESS_REMOTE_WRITE;
		SET(mr, ibv_exp_create_mr(&in));
	}
};

template <typename QP>
struct sig_test_base : public testing::Test, public ibvt_env {
	ibvt_ctx ctx;
	ibvt_pd pd;
	ibvt_cq cq;
	QP send_qp;
	QP recv_qp;
	ibvt_mr src_mr;
	ibvt_mr mid_mr;
	ibvt_mr mid2_mr;
	ibvt_mr dst_mr;
	ibvt_mr_sig insert_mr;
	ibvt_mr_sig check_mr;
	ibvt_mr_sig strip_mr;

	sig_test_base() :
		ctx(*this, NULL),
		pd(*this, ctx),
		cq(*this, ctx),
		send_qp(*this, pd, cq),
		recv_qp(*this, pd, cq),
		src_mr(*this, pd, 1024),
		mid_mr(*this, pd, 1040),
		mid2_mr(*this, pd, 1040),
		dst_mr(*this, pd, 1024),
		insert_mr(*this, pd, 1040),
		check_mr(*this, pd, 1040),
		strip_mr(*this, pd, 1024)
	{ }

	#define CHECK_REF_TAG 0x0f
	#define CHECK_APP_TAG 0x30
	#define CHECK_GUARD   0xc0

	virtual void config(ibvt_mr &sig_mr, struct ibv_sge data, int mem, int wire) {
		struct ibv_send_wr wr = {};
		struct ibv_send_wr *bad_wr;
		struct ibv_exp_sig_attrs sig = {};

		sig.check_mask |= CHECK_REF_TAG;
		sig.check_mask |= CHECK_APP_TAG;
		sig.check_mask |= CHECK_GUARD;
		if (mem) {
			sig.mem.sig_type = IBV_EXP_SIG_TYPE_T10_DIF;
			sig.mem.sig.dif.bg_type = IBV_EXP_T10DIF_CRC;
			sig.mem.sig.dif.pi_interval = 512;
			sig.mem.sig.dif.bg = 0x1234;
			sig.mem.sig.dif.app_tag = 0x5678;
			sig.mem.sig.dif.ref_tag = 0xabcdef90;
			sig.mem.sig.dif.ref_remap = 1;
			sig.mem.sig.dif.app_escape = 1;
			sig.mem.sig.dif.ref_escape = 1;
			sig.mem.sig.dif.apptag_check_mask = 0xffff;
		} else {
			sig.mem.sig_type = IBV_EXP_SIG_TYPE_NONE;
		}

		if (wire) {
			sig.wire.sig_type = IBV_EXP_SIG_TYPE_T10_DIF;
			sig.wire.sig.dif.bg_type = IBV_EXP_T10DIF_CRC;
			sig.wire.sig.dif.pi_interval = 512;
			sig.wire.sig.dif.bg = 0x1234;
			sig.wire.sig.dif.app_tag = 0x5678;
			sig.wire.sig.dif.ref_tag = 0xabcdef90;
			sig.wire.sig.dif.ref_remap = 1;
			sig.wire.sig.dif.app_escape = 1;
			sig.wire.sig.dif.ref_escape = 1;
			sig.wire.sig.dif.apptag_check_mask = 0xffff;
		} else {
			sig.wire.sig_type = IBV_EXP_SIG_TYPE_NONE;
		}

		wr.exp_opcode = IBV_EXP_WR_REG_SIG_MR;
		wr.exp_send_flags = IBV_EXP_SEND_SIGNALED;
		wr.ext_op.sig_handover.sig_attrs = &sig;
		wr.ext_op.sig_handover.sig_mr = sig_mr.mr;
		wr.ext_op.sig_handover.access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE;
		wr.ext_op.sig_handover.prot = NULL;

		wr.num_sge = 1;
		wr.sg_list = &data;

		DO(ibv_post_send(send_qp.qp, &wr, &bad_wr));
		EXEC(cq.poll(1));
	}

	void mr_status(ibvt_mr &mr, int expected) {
		struct ibv_exp_mr_status status;

		DO(ibv_exp_check_mr_status(mr.mr, IBV_EXP_MR_CHECK_SIG_STATUS,
					   &status));
		VERBS_INFO("SEGERR %d %x %x %lx\n",
			   status.sig_err.err_type,
			   status.sig_err.expected,
			   status.sig_err.actual,
			   status.sig_err.sig_err_offset);
		ASSERT_EQ(expected, status.fail_status);
	}

	void ae() {
		struct ibv_async_event event;

		DO(ibv_get_async_event(this->ctx.ctx, &event));
		ibv_ack_async_event(&event);
	}

	virtual void SetUp() {
		INIT(ctx.init());
		if (skip)
			return;
		INIT(send_qp.init());
		INIT(recv_qp.init());
		INIT(send_qp.connect(&recv_qp));
		INIT(recv_qp.connect(&send_qp));
		INIT(insert_mr.init());
		INIT(check_mr.init());
		INIT(strip_mr.init());
		INIT(src_mr.fill());
		INIT(mid_mr.init());
		INIT(mid2_mr.init());
		INIT(dst_mr.init());
		INIT(cq.arm());
	}

	virtual void TearDown() {
		ASSERT_FALSE(HasFailure());
	}
};

typedef sig_test_base<ibvt_qp_sig> sig_test;
typedef sig_test_base<ibvt_qp_sig_pipeline> sig_test_pipeline;

TEST_F(sig_test, c0) {
	CHK_SUT(sig_handover);
	EXEC(config(this->insert_mr, this->src_mr.sge(), 0, 1));
	EXEC(config(this->strip_mr, this->mid_mr.sge(), 1, 0));
	EXEC(send_qp.rdma(this->mid_mr.sge(), this->insert_mr.sge(), IBV_WR_RDMA_READ));
	EXEC(cq.poll(1));
	EXEC(send_qp.rdma(this->dst_mr.sge(), this->strip_mr.sge(), IBV_WR_RDMA_READ));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 0));
	EXEC(dst_mr.check());
}

TEST_F(sig_test, c1) {
	CHK_SUT(sig_handover);
	EXEC(config(this->insert_mr, this->src_mr.sge(), 0, 1));
	EXEC(config(this->strip_mr, this->mid_mr.sge(), 1, 0));
	EXEC(send_qp.rdma(this->insert_mr.sge(), this->mid_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(send_qp.rdma(this->strip_mr.sge(), this->dst_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 0));
	EXEC(dst_mr.check());
}

TEST_F(sig_test, c2) {
	CHK_SUT(sig_handover);
	EXEC(config(this->insert_mr, this->src_mr.sge(), 0, 1));
	EXEC(config(this->check_mr, this->mid_mr.sge(), 1, 1));
	EXEC(config(this->strip_mr, this->mid2_mr.sge(), 1, 0));
	EXEC(send_qp.rdma(this->insert_mr.sge(), this->mid_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(send_qp.rdma(this->check_mr.sge(), this->mid2_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(send_qp.rdma(this->strip_mr.sge(), this->dst_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 0));
	EXEC(dst_mr.check());
}

TEST_F(sig_test, e0) {
	CHK_SUT(sig_handover);
	EXEC(config(this->strip_mr, this->mid_mr.sge(), 1, 0));
	EXEC(send_qp.rdma(this->dst_mr.sge(), this->strip_mr.sge(), IBV_WR_RDMA_READ));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 1));
}

TEST_F(sig_test, e1) {
	CHK_SUT(sig_handover);
	EXEC(config(this->check_mr, this->mid_mr.sge(), 1, 1));
	EXEC(send_qp.rdma(this->check_mr.sge(), this->mid2_mr.sge(), IBV_WR_RDMA_WRITE));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->check_mr, 1));
}

TEST_F(sig_test_pipeline, p0) {
	CHK_SUT(sig_handover);
	EXEC(config(this->strip_mr, this->mid_mr.sge(), 1, 0));
	EXEC(recv_qp.recv(this->dst_mr.sge()));
	EXEC(recv_qp.recv(this->dst_mr.sge()));
	EXEC(send_qp.send_2wr(this->strip_mr.sge(0,1024), this->src_mr.sge()));
	EXEC(cq.poll(1));
	EXEC(ae());
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 1));
}

TEST_F(sig_test_pipeline, p1) {
	CHK_SUT(sig_handover);
	EXEC(config(this->strip_mr, this->mid_mr.sge(), 1, 0));
	EXEC(recv_qp.recv(this->dst_mr.sge()));
	EXEC(recv_qp.recv(this->dst_mr.sge()));
	EXEC(send_qp.send_2wr(this->strip_mr.sge(0,1024), this->src_mr.sge()));
	EXEC(cq.poll(1));
	EXEC(cq.poll(1));
	EXEC(mr_status(this->strip_mr, 1));
}

<|endoftext|>


<commit_before>#include "xchainer/check_backward.h"

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "xchainer/array.h"
#include "xchainer/array_node.h"
#include "xchainer/backward.h"
#include "xchainer/error.h"
#include "xchainer/numeric.h"
#include "xchainer/numerical_gradient.h"

namespace xchainer {
namespace {

std::vector<nonstd::optional<Array>> BackwardGradients(
        const std::function<std::vector<Array>(const std::vector<Array>&)>& func,
        std::vector<Array>& inputs,
        const std::vector<Array>& grad_outputs,
        const GraphId& graph_id) {
    for (const auto& input : inputs) {
        if (internal::HasArrayNode(input, graph_id) && internal::GetArrayNode(input, graph_id)->next_node()) {
            throw XchainerError("BackwardGradients: All inputs must be leaf nodes of computational graph");
        }
    }

    std::vector<Array> outputs = func(inputs);

    const std::size_t nout = outputs.size();
    if (nout != grad_outputs.size()) {
        throw XchainerError(
                "BackwardGradients: Size of function outputs: " + std::to_string(nout) +
                " and size of grad outputs: " + std::to_string(grad_outputs.size()) + " must be same");
    }

    for (std::size_t i = 0; i < nout; ++i) {
        if (outputs[i].IsGradRequired(graph_id)) {
            outputs[i].SetGrad(grad_outputs[i], graph_id);
        }
    }

    // Clear gradients which may exist if func calls backward inside of itself.
    for (Array& input : inputs) {
        if (input.IsGradRequired(graph_id)) {
            input.ClearGrad(graph_id);
        }
    }

    std::vector<ConstArrayRef> outputs_ref{outputs.begin(), outputs.end()};
    std::vector<ConstArrayRef> outputs_requiring_grad;
    std::copy_if(outputs_ref.begin(), outputs_ref.end(), std::back_inserter(outputs_requiring_grad), [&graph_id](const Array& a) {
        return a.IsGradRequired(graph_id);
    });
    Backward(outputs_requiring_grad, graph_id, DoubleBackpropOption::kEnable);

    std::vector<nonstd::optional<Array>> backward_grads;
    std::transform(
            inputs.begin(), inputs.end(), std::back_inserter(backward_grads), [&graph_id](const Array& input) -> nonstd::optional<Array> {
                if (!input.IsGradRequired(graph_id)) {
                    return nonstd::nullopt;
                }
                return input.GetGrad(graph_id);
            });

    return backward_grads;
}

}  // namespace

void CheckBackwardComputation(
        const std::function<std::vector<Array>(const std::vector<Array>&)>& func,
        const std::vector<Array>& inputs,
        const std::vector<Array>& grad_outputs,
        const std::vector<Array>& eps,
        double atol,
        double rtol,
        const GraphId& graph_id) {
    std::vector<Array> inputs_copy{inputs};
    const std::vector<Array> numerical_grads = CalculateNumericalGradient(func, inputs, grad_outputs, eps, graph_id);
    const std::vector<nonstd::optional<Array>> backward_grads = BackwardGradients(func, inputs_copy, grad_outputs, graph_id);
    if (backward_grads.size() != numerical_grads.size()) {
        throw XchainerError("Number of gradient arrays mismatched b/w backprop and numerical grad");
    }

    std::ostringstream failure_os;
    const int nin = backward_grads.size();
    for (int i = 0; i < nin; ++i) {
        if (backward_grads[i]) {  // All inputs do not necessarily require gradients
            if (!AllClose(*backward_grads[i], numerical_grads[i], atol, rtol)) {
                failure_os << "Backward check failure on input " << i << " (Total inputs: " << inputs.size() << ")\n"
                           << "Graph name: " << graph_id << "\n"
                           << "Atol: " << atol << "\n"
                           << "Rtol: " << rtol << "\n"
                           << "Eps (perturbation):\n"
                           << eps[i] << "\n"
                           << "Backward gradients:\n"
                           << *backward_grads[i] << "\n"
                           << "Numerical gradients:\n"
                           << numerical_grads[i];
            }
        }
    }

    // Do nothing if all backward-numerical gradient pairs were close, else generate a nonfatal failure
    std::string failure_message = failure_os.str();
    if (!failure_message.empty()) {
        throw GradientCheckError(failure_message);
    }
}

void CheckDoubleBackwardComputation(
        const std::function<std::vector<Array>(const std::vector<Array>&)>& func,
        const std::vector<Array>& inputs,
        const std::vector<Array>& grad_outputs,
        const std::vector<Array>& grad_grad_inputs,
        const std::vector<Array>& eps,
        double atol,
        double rtol,
        const GraphId& graph_id) {
    // LIMITATION: All inputs must require gradients unlike CheckBackwardComputation
    for (const auto& input : inputs) {
        if (!input.IsGradRequired(graph_id)) {
            throw XchainerError("All inputs must require gradients");
        }
    }

    const std::size_t nin = inputs.size();
    const std::size_t n_grad_outputs = grad_outputs.size();

    // Just merge inputs and grad_outputs into inputs_and_grad_outputs to pass into below `first_order_grad_func`.
    // Since move assignment operator of Array is deleted, we can not use std::vector::insert. Instead use reserve, and std::copy
    std::vector<Array> inputs_and_grad_outputs;
    inputs_and_grad_outputs.reserve(nin + n_grad_outputs);
    std::copy(inputs.begin(), inputs.end(), std::back_inserter(inputs_and_grad_outputs));
    std::copy(grad_outputs.begin(), grad_outputs.end(), std::back_inserter(inputs_and_grad_outputs));

    auto first_order_grad_func = [&func, nin, n_grad_outputs, &graph_id](const std::vector<Array>& inputs_and_grad_outputs) {
        // Just revert (split) inputs_and_grad_outputs into inputs and grad_outputs
        std::vector<Array> inputs{inputs_and_grad_outputs.begin(), inputs_and_grad_outputs.begin() + nin};
        std::vector<Array> grad_outputs{inputs_and_grad_outputs.begin() + nin, inputs_and_grad_outputs.end()};

        std::vector<nonstd::optional<Array>> optional_backward_grads = BackwardGradients(func, inputs, grad_outputs, graph_id);

        // Just convert std::vector<nonstd::optional<Array>> to std::vector<Array> so that CalculateNumericalGradient can accept
        std::vector<Array> backward_grads;
        std::transform(
                optional_backward_grads.begin(),
                optional_backward_grads.end(),
                std::back_inserter(backward_grads),
                [](const nonstd::optional<Array>& optional_backward_grad) {
                    if (!optional_backward_grad.has_value()) {
                        throw XchainerError("All gradients must exist");
                    }
                    return *optional_backward_grad;
                });
        return backward_grads;
    };

    const std::vector<Array> numerical_grads =
            CalculateNumericalGradient(first_order_grad_func, inputs_and_grad_outputs, grad_grad_inputs, eps, graph_id);
    const std::vector<nonstd::optional<Array>> backward_grads =
            BackwardGradients(first_order_grad_func, inputs_and_grad_outputs, grad_grad_inputs, graph_id);
    if (backward_grads.size() != numerical_grads.size()) {
        throw XchainerError("Number of gradient arrays mismatched b/w backprop and numerical grad");
    }

    std::ostringstream failure_os;
    const int n_backward_grads = backward_grads.size();
    for (int i = 0; i < n_backward_grads; ++i) {
        if (!backward_grads[i].has_value()) {
            failure_os << "Backward check failure on input " << i << " (Total inputs: " << inputs.size() << ")\n"
                       << "Graph name: " << graph_id << "\n"
                       << "Missing gradients. Maybe the given function was not twice differentiable.";
        } else if (!AllClose(*backward_grads[i], numerical_grads[i], atol, rtol)) {
            failure_os << "Backward check failure on input " << i << " (Total inputs: " << inputs.size() << ")\n"
                       << "Graph name: " << graph_id << "\n"
                       << "Atol: " << atol << "\n"
                       << "Rtol: " << rtol << "\n"
                       << "Eps (perturbation):\n"
                       << eps[i] << "\n"
                       << "Backward gradients:\n"
                       << *backward_grads[i] << "\n"
                       << "Numerical gradients:\n"
                       << numerical_grads[i];
        }
    }

    // Do nothing if all backward-numerical gradient pairs were close, else generate a nonfatal failure
    std::string failure_message = failure_os.str();
    if (!failure_message.empty()) {
        throw GradientCheckError(failure_message);
    }
}

}  // namespace xchainer
<commit_msg>Fix abbreviation<commit_after>#include "xchainer/check_backward.h"

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "xchainer/array.h"
#include "xchainer/array_node.h"
#include "xchainer/backward.h"
#include "xchainer/error.h"
#include "xchainer/numeric.h"
#include "xchainer/numerical_gradient.h"

namespace xchainer {
namespace {

std::vector<nonstd::optional<Array>> BackwardGradients(
        const std::function<std::vector<Array>(const std::vector<Array>&)>& func,
        std::vector<Array>& inputs,
        const std::vector<Array>& grad_outputs,
        const GraphId& graph_id) {
    for (const auto& input : inputs) {
        if (internal::HasArrayNode(input, graph_id) && internal::GetArrayNode(input, graph_id)->next_node()) {
            throw XchainerError("BackwardGradients: All inputs must be leaf nodes of computational graph");
        }
    }

    std::vector<Array> outputs = func(inputs);

    const std::size_t nout = outputs.size();
    if (nout != grad_outputs.size()) {
        throw XchainerError(
                "BackwardGradients: Size of function outputs: " + std::to_string(nout) +
                " and size of grad outputs: " + std::to_string(grad_outputs.size()) + " must be same");
    }

    for (std::size_t i = 0; i < nout; ++i) {
        if (outputs[i].IsGradRequired(graph_id)) {
            outputs[i].SetGrad(grad_outputs[i], graph_id);
        }
    }

    // Clear gradients which may exist if func calls backward inside of itself.
    for (Array& input : inputs) {
        if (input.IsGradRequired(graph_id)) {
            input.ClearGrad(graph_id);
        }
    }

    std::vector<ConstArrayRef> outputs_ref{outputs.begin(), outputs.end()};
    std::vector<ConstArrayRef> outputs_requiring_grad;
    std::copy_if(outputs_ref.begin(), outputs_ref.end(), std::back_inserter(outputs_requiring_grad), [&graph_id](const Array& a) {
        return a.IsGradRequired(graph_id);
    });
    Backward(outputs_requiring_grad, graph_id, DoubleBackpropOption::kEnable);

    std::vector<nonstd::optional<Array>> backward_grads;
    std::transform(
            inputs.begin(), inputs.end(), std::back_inserter(backward_grads), [&graph_id](const Array& input) -> nonstd::optional<Array> {
                if (!input.IsGradRequired(graph_id)) {
                    return nonstd::nullopt;
                }
                return input.GetGrad(graph_id);
            });

    return backward_grads;
}

}  // namespace

void CheckBackwardComputation(
        const std::function<std::vector<Array>(const std::vector<Array>&)>& func,
        const std::vector<Array>& inputs,
        const std::vector<Array>& grad_outputs,
        const std::vector<Array>& eps,
        double atol,
        double rtol,
        const GraphId& graph_id) {
    std::vector<Array> inputs_copy{inputs};
    const std::vector<Array> numerical_grads = CalculateNumericalGradient(func, inputs, grad_outputs, eps, graph_id);
    const std::vector<nonstd::optional<Array>> backward_grads = BackwardGradients(func, inputs_copy, grad_outputs, graph_id);
    if (backward_grads.size() != numerical_grads.size()) {
        throw XchainerError("Number of gradient arrays mismatched between backprop and numerical grad");
    }

    std::ostringstream failure_os;
    const int nin = backward_grads.size();
    for (int i = 0; i < nin; ++i) {
        if (backward_grads[i]) {  // All inputs do not necessarily require gradients
            if (!AllClose(*backward_grads[i], numerical_grads[i], atol, rtol)) {
                failure_os << "Backward check failure on input " << i << " (Total inputs: " << inputs.size() << ")\n"
                           << "Graph name: " << graph_id << "\n"
                           << "Atol: " << atol << "\n"
                           << "Rtol: " << rtol << "\n"
                           << "Eps (perturbation):\n"
                           << eps[i] << "\n"
                           << "Backward gradients:\n"
                           << *backward_grads[i] << "\n"
                           << "Numerical gradients:\n"
                           << numerical_grads[i];
            }
        }
    }

    // Do nothing if all backward-numerical gradient pairs were close, else generate a nonfatal failure
    std::string failure_message = failure_os.str();
    if (!failure_message.empty()) {
        throw GradientCheckError(failure_message);
    }
}

void CheckDoubleBackwardComputation(
        const std::function<std::vector<Array>(const std::vector<Array>&)>& func,
        const std::vector<Array>& inputs,
        const std::vector<Array>& grad_outputs,
        const std::vector<Array>& grad_grad_inputs,
        const std::vector<Array>& eps,
        double atol,
        double rtol,
        const GraphId& graph_id) {
    // LIMITATION: All inputs must require gradients unlike CheckBackwardComputation
    for (const auto& input : inputs) {
        if (!input.IsGradRequired(graph_id)) {
            throw XchainerError("All inputs must require gradients");
        }
    }

    const std::size_t nin = inputs.size();
    const std::size_t n_grad_outputs = grad_outputs.size();

    // Just merge inputs and grad_outputs into inputs_and_grad_outputs to pass into below `first_order_grad_func`.
    // Since move assignment operator of Array is deleted, we can not use std::vector::insert. Instead use reserve, and std::copy
    std::vector<Array> inputs_and_grad_outputs;
    inputs_and_grad_outputs.reserve(nin + n_grad_outputs);
    std::copy(inputs.begin(), inputs.end(), std::back_inserter(inputs_and_grad_outputs));
    std::copy(grad_outputs.begin(), grad_outputs.end(), std::back_inserter(inputs_and_grad_outputs));

    auto first_order_grad_func = [&func, nin, n_grad_outputs, &graph_id](const std::vector<Array>& inputs_and_grad_outputs) {
        // Just revert (split) inputs_and_grad_outputs into inputs and grad_outputs
        std::vector<Array> inputs{inputs_and_grad_outputs.begin(), inputs_and_grad_outputs.begin() + nin};
        std::vector<Array> grad_outputs{inputs_and_grad_outputs.begin() + nin, inputs_and_grad_outputs.end()};

        std::vector<nonstd::optional<Array>> optional_backward_grads = BackwardGradients(func, inputs, grad_outputs, graph_id);

        // Just convert std::vector<nonstd::optional<Array>> to std::vector<Array> so that CalculateNumericalGradient can accept
        std::vector<Array> backward_grads;
        std::transform(
                optional_backward_grads.begin(),
                optional_backward_grads.end(),
                std::back_inserter(backward_grads),
                [](const nonstd::optional<Array>& optional_backward_grad) {
                    if (!optional_backward_grad.has_value()) {
                        throw XchainerError("All gradients must exist");
                    }
                    return *optional_backward_grad;
                });
        return backward_grads;
    };

    const std::vector<Array> numerical_grads =
            CalculateNumericalGradient(first_order_grad_func, inputs_and_grad_outputs, grad_grad_inputs, eps, graph_id);
    const std::vector<nonstd::optional<Array>> backward_grads =
            BackwardGradients(first_order_grad_func, inputs_and_grad_outputs, grad_grad_inputs, graph_id);
    if (backward_grads.size() != numerical_grads.size()) {
        throw XchainerError("Number of gradient arrays mismatched between backprop and numerical grad");
    }

    std::ostringstream failure_os;
    const int n_backward_grads = backward_grads.size();
    for (int i = 0; i < n_backward_grads; ++i) {
        if (!backward_grads[i].has_value()) {
            failure_os << "Backward check failure on input " << i << " (Total inputs: " << inputs.size() << ")\n"
                       << "Graph name: " << graph_id << "\n"
                       << "Missing gradients. Maybe the given function was not twice differentiable.";
        } else if (!AllClose(*backward_grads[i], numerical_grads[i], atol, rtol)) {
            failure_os << "Backward check failure on input " << i << " (Total inputs: " << inputs.size() << ")\n"
                       << "Graph name: " << graph_id << "\n"
                       << "Atol: " << atol << "\n"
                       << "Rtol: " << rtol << "\n"
                       << "Eps (perturbation):\n"
                       << eps[i] << "\n"
                       << "Backward gradients:\n"
                       << *backward_grads[i] << "\n"
                       << "Numerical gradients:\n"
                       << numerical_grads[i];
        }
    }

    // Do nothing if all backward-numerical gradient pairs were close, else generate a nonfatal failure
    std::string failure_message = failure_os.str();
    if (!failure_message.empty()) {
        throw GradientCheckError(failure_message);
    }
}

}  // namespace xchainer
<|endoftext|>


<commit_before>/* DocumentCollector: Collects sections and runs of text from a
 * file (and styles to go along with them) and writes them
 * to a target file
 *
 * Copyright (C) 2002-2004 William Lachance (william.lachance@sympatico.ca)
 * Copyright (C) 2003-2004 Net Integration Technologies (http://www.net-itech.com)
 * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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
 *
 * For further information visit http://libwpd.sourceforge.net
 *
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#ifndef _DOCUMENTCOLLECTOR_HXX
#define _DOCUMENTCOLLECTOR_HXX
#include "SectionStyle.hxx"

#if defined _MSC_VER
#pragma warning( push, 1 )
#endif
#include <libwpd/libwpd.h>
#if defined _MSC_VER
#pragma warning( pop )
#endif
#include <vector>
#include <map>
#include <stack>
#include <string.h>

class DocumentElement;
class DocumentHandler;
class TagOpenElement;
class FontStyle;
class ListStyle;

class ParagraphStyle;
class SpanStyle;
class TableStyle;
class PageSpan;

// the state we use for writing the final document
typedef struct _WriterDocumentState WriterDocumentState;
struct _WriterDocumentState
{
    _WriterDocumentState();

    bool mbFirstElement;
    bool mbInFakeSection;
    bool mbListElementOpenedAtCurrentLevel;
    bool mbTableCellOpened;
    bool mbHeaderRow;
    bool mbInNote;
};

enum WriterListType { unordered, ordered };

struct ltstr
{
  bool operator()(const WPXString & s1, const WPXString & s2) const
  {
    return strcmp(s1.cstr(), s2.cstr()) < 0;
  }
};

class DocumentCollector : public WPXHLListenerImpl
{
public:
    DocumentCollector(WPXInputStream *pInput, DocumentHandler *pHandler);
    virtual ~DocumentCollector();
    bool filter();

     virtual void setDocumentMetaData(const WPXPropertyList & /* propList */) {}
    virtual void startDocument() {}
    virtual void endDocument() {}

    virtual void openPageSpan(const WPXPropertyList &propList);
    virtual void closePageSpan() {}

    virtual void openSection(const WPXPropertyList &propList, const WPXPropertyListVector &columns);
    virtual void closeSection();

    virtual void openHeader(const WPXPropertyList &propList);
    virtual void closeHeader();
    virtual void openFooter(const WPXPropertyList &propList);
    virtual void closeFooter();

    virtual void openParagraph(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops);
    virtual void closeParagraph();

    virtual void openSpan(const WPXPropertyList &propList);
    virtual void closeSpan();

    virtual void insertTab();
    virtual void insertText(const WPXString &text);
     virtual void insertLineBreak();

    virtual void defineOrderedListLevel(const WPXPropertyList &propList);
    virtual void defineUnorderedListLevel(const WPXPropertyList &propList);
    virtual void openOrderedListLevel(const WPXPropertyList &propList);
    virtual void openUnorderedListLevel(const WPXPropertyList &propList);
    virtual void closeOrderedListLevel();
    virtual void closeUnorderedListLevel();
    virtual void openListElement(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops);
    virtual void closeListElement();

    virtual void openFootnote(const WPXPropertyList &propList);
    virtual void closeFootnote();
    virtual void openEndnote(const WPXPropertyList &propList);
    virtual void closeEndnote();

     virtual void openTable(const WPXPropertyList &propList, const WPXPropertyListVector &columns);
     virtual void openTableRow(const WPXPropertyList &propList);
    virtual void closeTableRow();
     virtual void openTableCell(const WPXPropertyList &propList);
    virtual void closeTableCell();
    virtual void insertCoveredTableCell(const WPXPropertyList &propList);
     virtual void closeTable();
    virtual bool parseSourceDocument(WPXInputStream &input) = 0;

protected:
    void _resetDocumentState();
    bool _writeTargetDocument(DocumentHandler *pHandler);
    void _writeBegin();
    void _writeDefaultStyles(DocumentHandler *pHandler);
    void _writeMasterPages(DocumentHandler *pHandler);
    void _writePageMasters(DocumentHandler *pHandler);
    void _allocateFontName(const WPXString &);

private:
    void _openListLevel(TagOpenElement *pListLevelOpenElement);
    void _closeListLevel(const char *szListType);

        WPXInputStream *mpInput;
        DocumentHandler *mpHandler;
    bool mbUsed; // whether or not it has been before (you can only use me once!)

    WriterDocumentState mWriterDocumentState;

    // paragraph styles
    std::map<WPXString, ParagraphStyle *, ltstr> mTextStyleHash;

        // span styles
        std::map<WPXString, SpanStyle *, ltstr> mSpanStyleHash;

    // font styles
    std::map<WPXString, FontStyle *, ltstr> mFontHash;

    // section styles
    std::vector<SectionStyle *> mSectionStyles;
    float mfSectionSpaceAfter;

    // table styles
    std::vector<TableStyle *> mTableStyles;

    // list styles
    unsigned int miNumListStyles;

    // style elements
    std::vector<DocumentElement *> mStylesElements;
    // content elements
    std::vector<DocumentElement *> mBodyElements;
    // the current set of elements that we're writing to
    std::vector<DocumentElement *> * mpCurrentContentElements;

    // page state
    std::vector<PageSpan *> mPageSpans;
    PageSpan *mpCurrentPageSpan;
    int miNumPageStyles;

    // list styles / state
    ListStyle *mpCurrentListStyle;
    unsigned int miCurrentListLevel;
    unsigned int miLastListLevel;
    unsigned int miLastListNumber;
    std::vector<ListStyle *> mListStyles;
    bool mbListContinueNumbering;
    bool mbListElementOpened;
    bool mbListElementParagraphOpened;

    // table state
    TableStyle *mpCurrentTableStyle;
};

#endif
<commit_msg>INTEGRATION: CWS cmcfixes45 (1.4.8); FILE MERGED 2008/05/12 07:20:05 cmc 1.4.8.1: #i86324# remove unused methods<commit_after>/* DocumentCollector: Collects sections and runs of text from a
 * file (and styles to go along with them) and writes them
 * to a target file
 *
 * Copyright (C) 2002-2004 William Lachance (william.lachance@sympatico.ca)
 * Copyright (C) 2003-2004 Net Integration Technologies (http://www.net-itech.com)
 * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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
 *
 * For further information visit http://libwpd.sourceforge.net
 *
 */

/* "This product is not manufactured, approved, or supported by
 * Corel Corporation or Corel Corporation Limited."
 */

#ifndef _DOCUMENTCOLLECTOR_HXX
#define _DOCUMENTCOLLECTOR_HXX
#include "SectionStyle.hxx"

#if defined _MSC_VER
#pragma warning( push, 1 )
#endif
#include <libwpd/libwpd.h>
#if defined _MSC_VER
#pragma warning( pop )
#endif
#include <vector>
#include <map>
#include <stack>
#include <string.h>

class DocumentElement;
class DocumentHandler;
class TagOpenElement;
class FontStyle;
class ListStyle;

class ParagraphStyle;
class SpanStyle;
class TableStyle;
class PageSpan;

// the state we use for writing the final document
typedef struct _WriterDocumentState WriterDocumentState;
struct _WriterDocumentState
{
    _WriterDocumentState();

    bool mbFirstElement;
    bool mbInFakeSection;
    bool mbListElementOpenedAtCurrentLevel;
    bool mbTableCellOpened;
    bool mbHeaderRow;
    bool mbInNote;
};

enum WriterListType { unordered, ordered };

struct ltstr
{
  bool operator()(const WPXString & s1, const WPXString & s2) const
  {
    return strcmp(s1.cstr(), s2.cstr()) < 0;
  }
};

class DocumentCollector : public WPXHLListenerImpl
{
public:
    DocumentCollector(WPXInputStream *pInput, DocumentHandler *pHandler);
    virtual ~DocumentCollector();
    bool filter();

     virtual void setDocumentMetaData(const WPXPropertyList & /* propList */) {}
    virtual void startDocument() {}
    virtual void endDocument() {}

    virtual void openPageSpan(const WPXPropertyList &propList);
    virtual void closePageSpan() {}

    virtual void openSection(const WPXPropertyList &propList, const WPXPropertyListVector &columns);
    virtual void closeSection();

    virtual void openHeader(const WPXPropertyList &propList);
    virtual void closeHeader();
    virtual void openFooter(const WPXPropertyList &propList);
    virtual void closeFooter();

    virtual void openParagraph(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops);
    virtual void closeParagraph();

    virtual void openSpan(const WPXPropertyList &propList);
    virtual void closeSpan();

    virtual void insertTab();
    virtual void insertText(const WPXString &text);
     virtual void insertLineBreak();

    virtual void defineOrderedListLevel(const WPXPropertyList &propList);
    virtual void defineUnorderedListLevel(const WPXPropertyList &propList);
    virtual void openOrderedListLevel(const WPXPropertyList &propList);
    virtual void openUnorderedListLevel(const WPXPropertyList &propList);
    virtual void closeOrderedListLevel();
    virtual void closeUnorderedListLevel();
    virtual void openListElement(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops);
    virtual void closeListElement();

    virtual void openFootnote(const WPXPropertyList &propList);
    virtual void closeFootnote();
    virtual void openEndnote(const WPXPropertyList &propList);
    virtual void closeEndnote();

     virtual void openTable(const WPXPropertyList &propList, const WPXPropertyListVector &columns);
     virtual void openTableRow(const WPXPropertyList &propList);
    virtual void closeTableRow();
     virtual void openTableCell(const WPXPropertyList &propList);
    virtual void closeTableCell();
    virtual void insertCoveredTableCell(const WPXPropertyList &propList);
     virtual void closeTable();
    virtual bool parseSourceDocument(WPXInputStream &input) = 0;

protected:
    void _resetDocumentState();
    bool _writeTargetDocument(DocumentHandler *pHandler);
    void _writeDefaultStyles(DocumentHandler *pHandler);
    void _writeMasterPages(DocumentHandler *pHandler);
    void _writePageMasters(DocumentHandler *pHandler);
    void _allocateFontName(const WPXString &);

private:
    void _openListLevel(TagOpenElement *pListLevelOpenElement);
    void _closeListLevel(const char *szListType);

        WPXInputStream *mpInput;
        DocumentHandler *mpHandler;
    bool mbUsed; // whether or not it has been before (you can only use me once!)

    WriterDocumentState mWriterDocumentState;

    // paragraph styles
    std::map<WPXString, ParagraphStyle *, ltstr> mTextStyleHash;

        // span styles
        std::map<WPXString, SpanStyle *, ltstr> mSpanStyleHash;

    // font styles
    std::map<WPXString, FontStyle *, ltstr> mFontHash;

    // section styles
    std::vector<SectionStyle *> mSectionStyles;
    float mfSectionSpaceAfter;

    // table styles
    std::vector<TableStyle *> mTableStyles;

    // list styles
    unsigned int miNumListStyles;

    // style elements
    std::vector<DocumentElement *> mStylesElements;
    // content elements
    std::vector<DocumentElement *> mBodyElements;
    // the current set of elements that we're writing to
    std::vector<DocumentElement *> * mpCurrentContentElements;

    // page state
    std::vector<PageSpan *> mPageSpans;
    PageSpan *mpCurrentPageSpan;
    int miNumPageStyles;

    // list styles / state
    ListStyle *mpCurrentListStyle;
    unsigned int miCurrentListLevel;
    unsigned int miLastListLevel;
    unsigned int miLastListNumber;
    std::vector<ListStyle *> mListStyles;
    bool mbListContinueNumbering;
    bool mbListElementOpened;
    bool mbListElementParagraphOpened;

    // table state
    TableStyle *mpCurrentTableStyle;
};

#endif
<|endoftext|>