<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QGraphicsLinearLayout>
#include <QObject>
#include <QRectF>
#include <math.h>

#include "mpositionindicator.h"
#include "mpannableviewport.h"
#include "mpannableviewport_p.h"
#include "mpannableviewportlayout.h"

#include "minputmethodstate.h"

#include <mscenemanager.h>
#include <mondisplaychangeevent.h>

#include "mwidgetcreator.h"
M_REGISTER_WIDGET(MPannableViewport)

namespace
{
    //! Z-value of the panned widget
    const int ZValuePannedWidget = 0;
    //! Z-value of the position indicator
    const int ZValuePosInd       = 1;
}

MPannableViewportPrivate::MPannableViewportPrivate()
    : MPannableWidgetPrivate(),
      pannedWidget(0),
      viewportLayout(0),
      positionIndicator(0),
      rangeHeightExtension(0),
      autoScrollingExtension(0),
      inputMethodAreaHeight(0)
{
}

MPannableViewportPrivate::~MPannableViewportPrivate()
{
}

void MPannableViewportPrivate::setNewRange(const QRectF &newRange)
{
    Q_Q(MPannableViewport);

    QSizeF physRangeSize(newRange.size());

    if (physRangeSize.width() < 0.0) {
        physRangeSize.setWidth(0.0);
    }

    if (physRangeSize.height() < 0.0) {
        physRangeSize.setHeight(0.0);
    }

    const QRectF physRange(newRange.topLeft(),
                           physRangeSize + QSizeF(0, rangeHeightExtension));

    if (physRange != q->physics()->range()) {
        q->physics()->setRange(physRange);
        emit q->rangeChanged(q->range());
    }
}

void MPannableViewportPrivate::setAutoScrollingExtension(qreal extension)
{
    // Increase panning range to so that Intelligent Scrolling can scroll enough.
    autoScrollingExtension = extension;
    updateExtendedVerticalRange();
}

void MPannableViewportPrivate::setInputMethodArea(const QRect &imArea)
{
    Q_Q(MPannableViewport);

    // Assume only bottom part of pannable area is covered by SIP.
    const int overlappingHeight = (q->mapRectFromScene(imArea).toRect()
                                   & q->rect().toRect()).height();

    // Increase panning range to so that user can pan areas beneath
    // software input panel visible.
    inputMethodAreaHeight = overlappingHeight;
    updateExtendedVerticalRange();
}

void MPannableViewportPrivate::updateExtendedVerticalRange()
{
    Q_Q(MPannableViewport);
    const QRectF restoredRange(q->range().adjusted(0, 0, 0, -rangeHeightExtension));

    // Choose whichever is bigger.
    rangeHeightExtension = qMax<qreal>(0.0, qMax<qreal>(inputMethodAreaHeight, autoScrollingExtension));

    setNewRange(restoredRange);
}

void MPannableViewportPrivate::applyAutoRange()
{
    Q_Q(MPannableViewport);
    if (q->autoRange()) {
        if (pannedWidget) {
            setNewRange(QRectF(QPointF(), pannedWidget->size() - q->size()));
        } else {
            setNewRange(QRectF());
        }
    }
}

void MPannableViewportPrivate::scrollTo(const QPointF &endPosition)
{
    Q_Q(MPannableViewport);

    // This privileged scrolling extends the range if necessary.
    const qreal bottomRangeExtension = endPosition.y()
                                       + q->size().height()
                                       - pannedWidget->size().height();
    setAutoScrollingExtension(qMax<qreal>(0.0, bottomRangeExtension));

    scrollToAnimation.stop();
    scrollToAnimation.setStartValue(q->position());
    scrollToAnimation.setEndValue(endPosition);
    scrollToAnimation.setEasingCurve(QEasingCurve::OutCubic);
    scrollToAnimation.setDuration(500);
    scrollToAnimation.start();
}

void MPannableViewportPrivate::sendOnDisplayChangeEventToMWidgets(QGraphicsItem *item,
        MOnDisplayChangeEvent *event)
{
    Q_Q(MPannableViewport);
    bool isMWidget = false;

    if (item->isWidget()) {
        MWidget *mWidget = qobject_cast<MWidget *>(static_cast<QGraphicsWidget *>(item));

        if (mWidget) {
            isMWidget = true;

            // Let that MWidget handle the propagation from now on.
            q->scene()->sendEvent(mWidget, event);
        }
    }

    if (!isMWidget) {
        // That guy won't send the word forward. So we have to do it for him.
        QList<QGraphicsItem *> childItemsList = item->childItems();
        int childItemsCount = childItemsList.count();

        for (int i = 0; i < childItemsCount; i++) {
            sendOnDisplayChangeEventToMWidgets(childItemsList.at(i), event);
        }
    }
}

void MPannableViewportPrivate::_q_resolvePannedWidgetIsOnDisplay()
{
    Q_Q(MPannableViewport);

    if (q->isOnDisplay() && q->sceneManager() != 0 && q->widget() != 0) {
        QRectF visibleSceneRect(QPoint(0, 0), q->sceneManager()->visibleSceneSize());
        MOnDisplayChangeEvent event(MOnDisplayChangeEvent::MustBeResolved, visibleSceneRect);

        // If I just do a send(q->widget(), event) and widget() happens not to be a MWidget
        // (e.g., plain QGraphicsWidget layouting MWidgets inside) the event propagation
        // just won't happen.
        sendOnDisplayChangeEventToMWidgets(q->widget(), &event);
    }
}

void MPannableViewportPrivate::_q_positionIndicatorEnabledChanged()
{
    Q_Q(MPannableViewport);

    if (positionIndicator->isEnabled()) {
        positionIndicator->setRange(q->range());
        positionIndicator->setPosition(q->position());
        positionIndicator->setViewportSize(q->size());

        q->connect(q,
                   SIGNAL(viewportSizeChanged(QSizeF)),
                   positionIndicator,
                   SLOT(setViewportSize(QSizeF)), Qt::UniqueConnection);
        q->connect(q,
                   SIGNAL(positionChanged(QPointF)),
                   positionIndicator,
                   SLOT(setPosition(QPointF)), Qt::UniqueConnection);
        q->connect(q,
                   SIGNAL(rangeChanged(QRectF)),
                   positionIndicator,
                   SLOT(setRange(QRectF)), Qt::UniqueConnection);
    } else {
        q->disconnect(q,
                      SIGNAL(viewportSizeChanged(QSizeF)),
                      positionIndicator,
                      SLOT(setViewportSize(QSizeF)));
        q->disconnect(q,
                      SIGNAL(positionChanged(QPointF)),
                      positionIndicator,
                      SLOT(setPosition(QPointF)));
        q->disconnect(q,
                      SIGNAL(rangeChanged(QRectF)),
                      positionIndicator,
                      SLOT(setRange(QRectF)));
    }
}

void MPannableViewportPrivate::_q_pannedWidgetHeightOutOfViewport()
{
    Q_Q(MPannableViewport);;
    // If current position is bigger than new panned widget size (in panning direction) then
    // position should be updated to avoid unnecessary panning animation.
    if (q->panDirection().testFlag(Qt::Vertical)) {

        // Need to update range so we can use it here.
        applyAutoRange();

        // Note that range also contains the height extension.
        const qreal rangeBottomLimit = q->range().bottom();
        if (rangeBottomLimit < q->position().y()) {
            q->setPosition(QPointF(q->position().x(), rangeBottomLimit));
        }
    }

    // The heightChanged signal is called from an event handler. Singleshot timer
    // will ensure that relocation will be triggered only after sizes of the viewport
    // settle and correct microfocus is returned from scene. This is a workaround
    // until we find out why we don't have the correct value of the microfocus rect
    // returned while calling it from the height changed slot.
    QTimer::singleShot(0, q, SLOT(_q_ensureFocusedPannedWidgetIsVisible()));
}

void MPannableViewportPrivate::_q_pannedWidgetWidthOutOfViewport()
{
    Q_Q(MPannableViewport);;
    // If current position is bigger than new panned widget size (in panning direction) then
    // position should be updated to avoid unnecessary panning animation.
    if (q->panDirection().testFlag(Qt::Horizontal)) {
        qreal updatedPosition = pannedWidget->size().width() - q->size().width();
        if(updatedPosition < q->position().x())
            q->setPosition(QPointF(qMax((qreal)0, updatedPosition), q->position().y()));
    }
}

void MPannableViewportPrivate::_q_ensureFocusedPannedWidgetIsVisible()
{
    Q_Q(MPannableViewport);

    if (q->sceneManager()
        && pannedWidget->focusItem()) {
        q->sceneManager()->ensureCursorVisible();
    }
}

bool MPannableViewportPrivate::isTopmostVerticallyPannableViewport() const
{
    Q_Q(const MPannableViewport);
    const QGraphicsWidget* parentWidget = q->parentWidget();

    while(parentWidget) {
        const MPannableViewport *viewport = qobject_cast<const MPannableViewport *>(parentWidget);
        if (viewport && (viewport->panDirection() & Qt::Vertical)) {
            return false;
        }
        parentWidget = parentWidget->parentWidget();
    }
    return true;
}

void MPannableViewportPrivate::_q_handleInputMethodAreaChanged(const QRect &newArea)
{
    if (isTopmostVerticallyPannableViewport()) {
        setInputMethodArea(newArea);
    } else if (inputMethodAreaHeight != 0) {
        // This is not the topmost pannable viewport anymore.
        inputMethodAreaHeight = 0;
        updateExtendedVerticalRange();
    }
}

MPannableViewport::MPannableViewport(QGraphicsItem *parent)
    : MPannableWidget(new MPannableViewportPrivate(), new MPannableViewportModel, parent)
{
    Q_D(MPannableViewport);
    setFlags(QGraphicsItem::ItemClipsChildrenToShape);

    setPosition(QPointF());
    setRange(QRectF());

    d->positionIndicator = new MPositionIndicator(this);
    d->positionIndicator->setZValue(ZValuePosInd);
    d->_q_positionIndicatorEnabledChanged();

    connect(d->positionIndicator,
            SIGNAL(enabledChanged()),
            SLOT(_q_positionIndicatorEnabledChanged()));

    d->viewportLayout = new MPannableViewportLayout;
    d->viewportLayout->setPanningDirections(panDirection());
    d->viewportLayout->setContentsMargins(0, 0, 0, 0);
    d->viewportLayout->setSpacing(0);
    setLayout(d->viewportLayout);

    connect(this,
            SIGNAL(panningStopped()),
            SLOT(_q_resolvePannedWidgetIsOnDisplay()));

    connect(MInputMethodState::instance(), SIGNAL(inputMethodAreaChanged(QRect)),
            this, SLOT(_q_handleInputMethodAreaChanged(QRect)));

    d->scrollToAnimation.setTargetObject(this);
    d->scrollToAnimation.setPropertyName("position");
}

MPannableViewport::~MPannableViewport()
{
    Q_D(MPannableViewport);

    QGraphicsWidget *oldwidget  = widget();

    d->pannedWidget = NULL;
    d->viewportLayout->setWidget(NULL);

    if (oldwidget) {
        delete oldwidget;
        oldwidget = 0;
    }
}

void MPannableViewport::setAutoRange(bool enable)
{
    Q_D(MPannableViewport);
    model()->setAutoRange(enable);
    d->applyAutoRange();
}

bool MPannableViewport::autoRange() const
{
    return model()->autoRange();
}

void MPannableViewport::setClipping(bool enabled)
{
    model()->setClipWidget(enabled);
    setFlag(QGraphicsItem::ItemClipsChildrenToShape, enabled);
}

bool MPannableViewport::hasClipping() const
{
    return model()->clipWidget();
}

void MPannableViewport::setWidget(QGraphicsWidget *widget)
{
    Q_D(MPannableViewport);

    if (d->pannedWidget) {
        disconnect(d->pannedWidget, SIGNAL(heightChanged()), this, SLOT(_q_pannedWidgetHeightOutOfViewport()));
        disconnect(d->pannedWidget, SIGNAL(widthChanged()), this, SLOT(_q_pannedWidgetWidthOutOfViewport()));
    }

    d->pannedWidget = widget;
    d->viewportLayout->setWidget(widget);

    if (widget) {
        connect(widget, SIGNAL(heightChanged()), this, SLOT(_q_pannedWidgetHeightOutOfViewport()));
        connect(widget, SIGNAL(widthChanged()), this, SLOT(_q_pannedWidgetWidthOutOfViewport()));

        d->viewportLayout->invalidate();
        widget->setZValue(ZValuePannedWidget);
    }

    d->applyAutoRange();
}

QGraphicsWidget *MPannableViewport::widget() const
{
    Q_D(const MPannableViewport);
    return d->pannedWidget;
}

void MPannableViewport::setRange(const QRectF &r)
{
    Q_D(MPannableViewport);

    if (!autoRange())
        d->setNewRange(r);
}

QRectF MPannableViewport::range() const
{
    return MPannableWidget::range();
}

void MPannableViewport::resizeEvent(QGraphicsSceneResizeEvent *event)
{
    Q_D(MPannableViewport);
    Q_UNUSED(event);

    d->applyAutoRange();

    emit viewportSizeChanged(event->newSize());

    d->positionIndicator->resize(event->newSize());
}

void MPannableViewport::updatePosition(const QPointF &p)
{
    Q_D(MPannableViewport);

    QPointF roundedP = QPointF(floorf(p.x()), floorf(p.y()));

    // Parameter p is in the local coordinate system of pannedWidget but
    // pannedWidget position is in pannable viewport's coordinate system.
    //
    // Therefore pannedWidget position is set as a negate of physics position (p),
    // because the panned widget needs to flow to the opposite direction of the
    // panning.

    if (d->pannedWidget && d->pannedWidget->pos() != -roundedP) {
        d->viewportLayout->setPanningPosition(-roundedP);
        emit positionChanged(roundedP);
    }
}

void MPannableViewport::setPanDirection(const Qt::Orientations &panDirection)
{
    Q_D(MPannableViewport);

    MPannableWidget::setPanDirection(panDirection);

    if (d->viewportLayout) {
        d->viewportLayout->setPanningDirections(panDirection);
    }

    updateGeometry();
}

void MPannableViewport::updateGeometry()
{
    Q_D(MPannableViewport);

    d->applyAutoRange();

    updatePosition(position());

    MPannableWidget::updateGeometry();
}

void MPannableViewport::updateData(const QList<const char *> &modifications)
{
    Q_D(MPannableViewport);
    const char *member;

    foreach(member, modifications) {
        if (member == MPannableWidgetModel::VerticalPanningPolicy) {
            if (verticalPanningPolicy() == PanningAlwaysOff) {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() & ~Qt::Vertical);
            } else {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() | Qt::Vertical);
            }
        }

        if (member == MPannableWidgetModel::HorizontalPanningPolicy) {
            if (horizontalPanningPolicy() == PanningAlwaysOff) {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() & ~Qt::Horizontal);
            } else {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() | Qt::Horizontal);
            }
        }
    }
}

void MPannableViewport::setPositionIndicator(MPositionIndicator *positionIndicator)
{
    Q_D(MPannableViewport);

    if (!positionIndicator) {
        return;
    }

    delete d->positionIndicator;

    d->positionIndicator = positionIndicator;
    d->positionIndicator->setZValue(ZValuePosInd);
    d->positionIndicator->setParent(this);
    d->positionIndicator->setParentItem(this);

    d->_q_positionIndicatorEnabledChanged();

    connect(d->positionIndicator,
            SIGNAL(enabledChanged()),
            SLOT(_q_positionIndicatorEnabledChanged()));
}

MPositionIndicator* MPannableViewport::positionIndicator() const
{
    Q_D(const MPannableViewport);

    return d->positionIndicator;
}

#include "moc_mpannableviewport.cpp"
<commit_msg>Fixes: a possible crash in MPannableViewportPrivate::_q_ensureFocusedPannedWidgetIsVisible()<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QGraphicsLinearLayout>
#include <QObject>
#include <QRectF>
#include <math.h>

#include "mpositionindicator.h"
#include "mpannableviewport.h"
#include "mpannableviewport_p.h"
#include "mpannableviewportlayout.h"

#include "minputmethodstate.h"

#include <mscenemanager.h>
#include <mondisplaychangeevent.h>

#include "mwidgetcreator.h"
M_REGISTER_WIDGET(MPannableViewport)

namespace
{
    //! Z-value of the panned widget
    const int ZValuePannedWidget = 0;
    //! Z-value of the position indicator
    const int ZValuePosInd       = 1;
}

MPannableViewportPrivate::MPannableViewportPrivate()
    : MPannableWidgetPrivate(),
      pannedWidget(0),
      viewportLayout(0),
      positionIndicator(0),
      rangeHeightExtension(0),
      autoScrollingExtension(0),
      inputMethodAreaHeight(0)
{
}

MPannableViewportPrivate::~MPannableViewportPrivate()
{
}

void MPannableViewportPrivate::setNewRange(const QRectF &newRange)
{
    Q_Q(MPannableViewport);

    QSizeF physRangeSize(newRange.size());

    if (physRangeSize.width() < 0.0) {
        physRangeSize.setWidth(0.0);
    }

    if (physRangeSize.height() < 0.0) {
        physRangeSize.setHeight(0.0);
    }

    const QRectF physRange(newRange.topLeft(),
                           physRangeSize + QSizeF(0, rangeHeightExtension));

    if (physRange != q->physics()->range()) {
        q->physics()->setRange(physRange);
        emit q->rangeChanged(q->range());
    }
}

void MPannableViewportPrivate::setAutoScrollingExtension(qreal extension)
{
    // Increase panning range to so that Intelligent Scrolling can scroll enough.
    autoScrollingExtension = extension;
    updateExtendedVerticalRange();
}

void MPannableViewportPrivate::setInputMethodArea(const QRect &imArea)
{
    Q_Q(MPannableViewport);

    // Assume only bottom part of pannable area is covered by SIP.
    const int overlappingHeight = (q->mapRectFromScene(imArea).toRect()
                                   & q->rect().toRect()).height();

    // Increase panning range to so that user can pan areas beneath
    // software input panel visible.
    inputMethodAreaHeight = overlappingHeight;
    updateExtendedVerticalRange();
}

void MPannableViewportPrivate::updateExtendedVerticalRange()
{
    Q_Q(MPannableViewport);
    const QRectF restoredRange(q->range().adjusted(0, 0, 0, -rangeHeightExtension));

    // Choose whichever is bigger.
    rangeHeightExtension = qMax<qreal>(0.0, qMax<qreal>(inputMethodAreaHeight, autoScrollingExtension));

    setNewRange(restoredRange);
}

void MPannableViewportPrivate::applyAutoRange()
{
    Q_Q(MPannableViewport);
    if (q->autoRange()) {
        if (pannedWidget) {
            setNewRange(QRectF(QPointF(), pannedWidget->size() - q->size()));
        } else {
            setNewRange(QRectF());
        }
    }
}

void MPannableViewportPrivate::scrollTo(const QPointF &endPosition)
{
    Q_Q(MPannableViewport);

    // This privileged scrolling extends the range if necessary.
    const qreal bottomRangeExtension = endPosition.y()
                                       + q->size().height()
                                       - pannedWidget->size().height();
    setAutoScrollingExtension(qMax<qreal>(0.0, bottomRangeExtension));

    scrollToAnimation.stop();
    scrollToAnimation.setStartValue(q->position());
    scrollToAnimation.setEndValue(endPosition);
    scrollToAnimation.setEasingCurve(QEasingCurve::OutCubic);
    scrollToAnimation.setDuration(500);
    scrollToAnimation.start();
}

void MPannableViewportPrivate::sendOnDisplayChangeEventToMWidgets(QGraphicsItem *item,
        MOnDisplayChangeEvent *event)
{
    Q_Q(MPannableViewport);
    bool isMWidget = false;

    if (item->isWidget()) {
        MWidget *mWidget = qobject_cast<MWidget *>(static_cast<QGraphicsWidget *>(item));

        if (mWidget) {
            isMWidget = true;

            // Let that MWidget handle the propagation from now on.
            q->scene()->sendEvent(mWidget, event);
        }
    }

    if (!isMWidget) {
        // That guy won't send the word forward. So we have to do it for him.
        QList<QGraphicsItem *> childItemsList = item->childItems();
        int childItemsCount = childItemsList.count();

        for (int i = 0; i < childItemsCount; i++) {
            sendOnDisplayChangeEventToMWidgets(childItemsList.at(i), event);
        }
    }
}

void MPannableViewportPrivate::_q_resolvePannedWidgetIsOnDisplay()
{
    Q_Q(MPannableViewport);

    if (q->isOnDisplay() && q->sceneManager() != 0 && q->widget() != 0) {
        QRectF visibleSceneRect(QPoint(0, 0), q->sceneManager()->visibleSceneSize());
        MOnDisplayChangeEvent event(MOnDisplayChangeEvent::MustBeResolved, visibleSceneRect);

        // If I just do a send(q->widget(), event) and widget() happens not to be a MWidget
        // (e.g., plain QGraphicsWidget layouting MWidgets inside) the event propagation
        // just won't happen.
        sendOnDisplayChangeEventToMWidgets(q->widget(), &event);
    }
}

void MPannableViewportPrivate::_q_positionIndicatorEnabledChanged()
{
    Q_Q(MPannableViewport);

    if (positionIndicator->isEnabled()) {
        positionIndicator->setRange(q->range());
        positionIndicator->setPosition(q->position());
        positionIndicator->setViewportSize(q->size());

        q->connect(q,
                   SIGNAL(viewportSizeChanged(QSizeF)),
                   positionIndicator,
                   SLOT(setViewportSize(QSizeF)), Qt::UniqueConnection);
        q->connect(q,
                   SIGNAL(positionChanged(QPointF)),
                   positionIndicator,
                   SLOT(setPosition(QPointF)), Qt::UniqueConnection);
        q->connect(q,
                   SIGNAL(rangeChanged(QRectF)),
                   positionIndicator,
                   SLOT(setRange(QRectF)), Qt::UniqueConnection);
    } else {
        q->disconnect(q,
                      SIGNAL(viewportSizeChanged(QSizeF)),
                      positionIndicator,
                      SLOT(setViewportSize(QSizeF)));
        q->disconnect(q,
                      SIGNAL(positionChanged(QPointF)),
                      positionIndicator,
                      SLOT(setPosition(QPointF)));
        q->disconnect(q,
                      SIGNAL(rangeChanged(QRectF)),
                      positionIndicator,
                      SLOT(setRange(QRectF)));
    }
}

void MPannableViewportPrivate::_q_pannedWidgetHeightOutOfViewport()
{
    Q_Q(MPannableViewport);;
    // If current position is bigger than new panned widget size (in panning direction) then
    // position should be updated to avoid unnecessary panning animation.
    if (q->panDirection().testFlag(Qt::Vertical)) {

        // Need to update range so we can use it here.
        applyAutoRange();

        // Note that range also contains the height extension.
        const qreal rangeBottomLimit = q->range().bottom();
        if (rangeBottomLimit < q->position().y()) {
            q->setPosition(QPointF(q->position().x(), rangeBottomLimit));
        }
    }

    // The heightChanged signal is called from an event handler. Singleshot timer
    // will ensure that relocation will be triggered only after sizes of the viewport
    // settle and correct microfocus is returned from scene. This is a workaround
    // until we find out why we don't have the correct value of the microfocus rect
    // returned while calling it from the height changed slot.
    QTimer::singleShot(0, q, SLOT(_q_ensureFocusedPannedWidgetIsVisible()));
}

void MPannableViewportPrivate::_q_pannedWidgetWidthOutOfViewport()
{
    Q_Q(MPannableViewport);;
    // If current position is bigger than new panned widget size (in panning direction) then
    // position should be updated to avoid unnecessary panning animation.
    if (q->panDirection().testFlag(Qt::Horizontal)) {
        qreal updatedPosition = pannedWidget->size().width() - q->size().width();
        if(updatedPosition < q->position().x())
            q->setPosition(QPointF(qMax((qreal)0, updatedPosition), q->position().y()));
    }
}

void MPannableViewportPrivate::_q_ensureFocusedPannedWidgetIsVisible()
{
    Q_Q(MPannableViewport);

    if (q->sceneManager() &&
        pannedWidget && pannedWidget->focusItem()) {
        q->sceneManager()->ensureCursorVisible();
    }
}

bool MPannableViewportPrivate::isTopmostVerticallyPannableViewport() const
{
    Q_Q(const MPannableViewport);
    const QGraphicsWidget* parentWidget = q->parentWidget();

    while(parentWidget) {
        const MPannableViewport *viewport = qobject_cast<const MPannableViewport *>(parentWidget);
        if (viewport && (viewport->panDirection() & Qt::Vertical)) {
            return false;
        }
        parentWidget = parentWidget->parentWidget();
    }
    return true;
}

void MPannableViewportPrivate::_q_handleInputMethodAreaChanged(const QRect &newArea)
{
    if (isTopmostVerticallyPannableViewport()) {
        setInputMethodArea(newArea);
    } else if (inputMethodAreaHeight != 0) {
        // This is not the topmost pannable viewport anymore.
        inputMethodAreaHeight = 0;
        updateExtendedVerticalRange();
    }
}

MPannableViewport::MPannableViewport(QGraphicsItem *parent)
    : MPannableWidget(new MPannableViewportPrivate(), new MPannableViewportModel, parent)
{
    Q_D(MPannableViewport);
    setFlags(QGraphicsItem::ItemClipsChildrenToShape);

    setPosition(QPointF());
    setRange(QRectF());

    d->positionIndicator = new MPositionIndicator(this);
    d->positionIndicator->setZValue(ZValuePosInd);
    d->_q_positionIndicatorEnabledChanged();

    connect(d->positionIndicator,
            SIGNAL(enabledChanged()),
            SLOT(_q_positionIndicatorEnabledChanged()));

    d->viewportLayout = new MPannableViewportLayout;
    d->viewportLayout->setPanningDirections(panDirection());
    d->viewportLayout->setContentsMargins(0, 0, 0, 0);
    d->viewportLayout->setSpacing(0);
    setLayout(d->viewportLayout);

    connect(this,
            SIGNAL(panningStopped()),
            SLOT(_q_resolvePannedWidgetIsOnDisplay()));

    connect(MInputMethodState::instance(), SIGNAL(inputMethodAreaChanged(QRect)),
            this, SLOT(_q_handleInputMethodAreaChanged(QRect)));

    d->scrollToAnimation.setTargetObject(this);
    d->scrollToAnimation.setPropertyName("position");
}

MPannableViewport::~MPannableViewport()
{
    Q_D(MPannableViewport);

    QGraphicsWidget *oldwidget  = widget();

    d->pannedWidget = NULL;
    d->viewportLayout->setWidget(NULL);

    if (oldwidget) {
        delete oldwidget;
        oldwidget = 0;
    }
}

void MPannableViewport::setAutoRange(bool enable)
{
    Q_D(MPannableViewport);
    model()->setAutoRange(enable);
    d->applyAutoRange();
}

bool MPannableViewport::autoRange() const
{
    return model()->autoRange();
}

void MPannableViewport::setClipping(bool enabled)
{
    model()->setClipWidget(enabled);
    setFlag(QGraphicsItem::ItemClipsChildrenToShape, enabled);
}

bool MPannableViewport::hasClipping() const
{
    return model()->clipWidget();
}

void MPannableViewport::setWidget(QGraphicsWidget *widget)
{
    Q_D(MPannableViewport);

    if (d->pannedWidget) {
        disconnect(d->pannedWidget, SIGNAL(heightChanged()), this, SLOT(_q_pannedWidgetHeightOutOfViewport()));
        disconnect(d->pannedWidget, SIGNAL(widthChanged()), this, SLOT(_q_pannedWidgetWidthOutOfViewport()));
    }

    d->pannedWidget = widget;
    d->viewportLayout->setWidget(widget);

    if (widget) {
        connect(widget, SIGNAL(heightChanged()), this, SLOT(_q_pannedWidgetHeightOutOfViewport()));
        connect(widget, SIGNAL(widthChanged()), this, SLOT(_q_pannedWidgetWidthOutOfViewport()));

        d->viewportLayout->invalidate();
        widget->setZValue(ZValuePannedWidget);
    }

    d->applyAutoRange();
}

QGraphicsWidget *MPannableViewport::widget() const
{
    Q_D(const MPannableViewport);
    return d->pannedWidget;
}

void MPannableViewport::setRange(const QRectF &r)
{
    Q_D(MPannableViewport);

    if (!autoRange())
        d->setNewRange(r);
}

QRectF MPannableViewport::range() const
{
    return MPannableWidget::range();
}

void MPannableViewport::resizeEvent(QGraphicsSceneResizeEvent *event)
{
    Q_D(MPannableViewport);
    Q_UNUSED(event);

    d->applyAutoRange();

    emit viewportSizeChanged(event->newSize());

    d->positionIndicator->resize(event->newSize());
}

void MPannableViewport::updatePosition(const QPointF &p)
{
    Q_D(MPannableViewport);

    QPointF roundedP = QPointF(floorf(p.x()), floorf(p.y()));

    // Parameter p is in the local coordinate system of pannedWidget but
    // pannedWidget position is in pannable viewport's coordinate system.
    //
    // Therefore pannedWidget position is set as a negate of physics position (p),
    // because the panned widget needs to flow to the opposite direction of the
    // panning.

    if (d->pannedWidget && d->pannedWidget->pos() != -roundedP) {
        d->viewportLayout->setPanningPosition(-roundedP);
        emit positionChanged(roundedP);
    }
}

void MPannableViewport::setPanDirection(const Qt::Orientations &panDirection)
{
    Q_D(MPannableViewport);

    MPannableWidget::setPanDirection(panDirection);

    if (d->viewportLayout) {
        d->viewportLayout->setPanningDirections(panDirection);
    }

    updateGeometry();
}

void MPannableViewport::updateGeometry()
{
    Q_D(MPannableViewport);

    d->applyAutoRange();

    updatePosition(position());

    MPannableWidget::updateGeometry();
}

void MPannableViewport::updateData(const QList<const char *> &modifications)
{
    Q_D(MPannableViewport);
    const char *member;

    foreach(member, modifications) {
        if (member == MPannableWidgetModel::VerticalPanningPolicy) {
            if (verticalPanningPolicy() == PanningAlwaysOff) {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() & ~Qt::Vertical);
            } else {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() | Qt::Vertical);
            }
        }

        if (member == MPannableWidgetModel::HorizontalPanningPolicy) {
            if (horizontalPanningPolicy() == PanningAlwaysOff) {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() & ~Qt::Horizontal);
            } else {
                d->viewportLayout->setPanningDirections( d->viewportLayout->panningDirections() | Qt::Horizontal);
            }
        }
    }
}

void MPannableViewport::setPositionIndicator(MPositionIndicator *positionIndicator)
{
    Q_D(MPannableViewport);

    if (!positionIndicator) {
        return;
    }

    delete d->positionIndicator;

    d->positionIndicator = positionIndicator;
    d->positionIndicator->setZValue(ZValuePosInd);
    d->positionIndicator->setParent(this);
    d->positionIndicator->setParentItem(this);

    d->_q_positionIndicatorEnabledChanged();

    connect(d->positionIndicator,
            SIGNAL(enabledChanged()),
            SLOT(_q_positionIndicatorEnabledChanged()));
}

MPositionIndicator* MPannableViewport::positionIndicator() const
{
    Q_D(const MPannableViewport);

    return d->positionIndicator;
}

#include "moc_mpannableviewport.cpp"
<|endoftext|>


<commit_before>#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
//#include <numpy/arrayobject.h>
#include <vector>
#include <thread>
#include <iterator>
#include "repeat_fct.h"

namespace py = pybind11;

template<typename DTYPE>
class FunctionMeasureVectorCount : FunctionMeasure
{
    protected:

    std::vector<DTYPE> values;
    DTYPE th;

    public:

    FunctionMeasureVectorCount(const std::vector<DTYPE> &v, DTYPE t) : values(v), th(t)
    {
        if (values.size() == 0)
            throw std::runtime_error("Array to process must not be empty.");
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountSleep : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountSleep(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int i)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(th));
        return 0;
    }
};

#define REPEAT_INST(INST) {\
    INST INST INST INST INST\
    INST INST INST INST INST\
    }

template<typename DTYPE>
class FunctionMeasureVectorCountA : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountA(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1; // == 0 but otherwise the compiler detects the
                        // the code does not change depending on x
                        // and it caches the results.
        for(int i = 0; i < values.size(); ++i)
            REPEAT_INST(if (values[i] >= th) ++nb;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountB : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountB(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(if (*it >= th) ++nb;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountC : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountC(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(if (*it >= th) nb++;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountD : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountD(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += *it >= th ? 1 : 0;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountE : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountE(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(if (*it >= th) nb += 1;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountF : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountF(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += (*it - th) >= 0 ? 1 : 0;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountG : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountG(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += (*it - th) < 0 ? 1 : 0;)
        return (int)std::distance(values.begin(), values.end()) - nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountH : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountH(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += *it < th ? 1 : 0;)
        return (int)std::distance(values.begin(), values.end()) - nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountI : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountI(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += 1 ^ ((unsigned int)(*it) >> (sizeof(int) * CHAR_BIT - 1));)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountJ : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountJ(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1; // == 0 but otherwise the compiler detects the
                        // the code does not change depending on x
                        // and it caches the results.
        for(int i = 0; i < values.size(); ++i)
            REPEAT_INST(nb += values[i] >= th ? 1 : 0;)
        return nb;
    }
};

#if defined(_MSC_VER)
#define STRING_CONCAT(A, B) A ## B
#define CBENCHMARK_ADDFUNC(suf, C)\
    m.def(STRING_CONCAT("measure_scenario_", #suf), \
            [](const std::vector<int> &values, int th, int repeat=100, int number=1000, bool verbose=false) -> ExecutionStat { \
                ExecutionStat res; \
                FunctionMeasureVectorCount##suf<int> fct(values, th); \
                repeat_execution<FunctionMeasureVectorCount##suf<int>>(fct, repeat, number, res, verbose); \
                return res; \
            }, \
            C, \
            py::arg("values"), py::arg("th"), \
            py::arg("repeat")=10, py::arg("number")=100, \
            py::arg("verbose")=false);
#else
#define CBENCHMARK_ADDFUNC(suf, C)\
    m.def(measure_scenario_ ##suf), \
            [](const std::vector<int> &values, int th, int repeat=100, int number=1000, bool verbose=false) -> ExecutionStat { \
                ExecutionStat res; \
                FunctionMeasureVectorCount##suf<int> fct(values, th); \
                repeat_execution<FunctionMeasureVectorCount##suf<int>>(fct, repeat, number, res, verbose); \
                return res; \
            }, \
            C, \
            py::arg("values"), py::arg("th"), \
            py::arg("repeat")=10, py::arg("number")=100, \
            py::arg("verbose")=false);
#endif

PYBIND11_MODULE(cbenchmark, m) {
	m.doc() =
    #if defined(__APPLE__)
    "Measures the execution time of functions implemented in C."
    #else
    R"pbdoc(Measures the execution time of functions implemented in C, the measures are
also implemented in C.)pbdoc"
    #endif
    ;

    py::class_<ExecutionStat>(m, "ExecutionStat",
        "Holds results to compare execution time of functions.")
        .def(py::init<>())
        .def_readwrite("number", &ExecutionStat::number, "number of execution")
        .def_readwrite("repeat", &ExecutionStat::repeat, "number of calls per executions")
        .def_readwrite("average", &ExecutionStat::average, "average processing time")
        .def_readwrite("deviation", &ExecutionStat::deviation, "standard deviation")
        .def_readwrite("min_exec", &ExecutionStat::min_exec, "minimum execution time")
        .def_readwrite("max_exec", &ExecutionStat::max_exec, "maximum execution time")
        .def("__str__", [](const ExecutionStat& report) -> std::string {
            char buffer[1000];
            sprintf(buffer, "%1.3gs (+/- %1.3g) in [%1.3g, %1.3g] N=%d rep=%d",
                    report.average, report.deviation,
                    report.min_exec, report.max_exec,
                    report.number, report.repeat);
            return buffer;
            },
            "usual operator")
        .def("todict", [](const ExecutionStat& report) -> std::map<std::string, double> {
            std::map<std::string, double> res;
            res["average"] = report.average;
            res["deviation"] = report.deviation;
            res["min_exec"] = report.min_exec;
            res["max_exec"] = report.max_exec;
            res["number"] = report.number;
            res["repeat"] = report.repeat;
            return res;
        }, "Converts the structure into a dictionary.")
        ;

    CBENCHMARK_ADDFUNC(A, "Measure C++ implementation. Loop on ``if (values[i] >= th) ++nb;``");
    CBENCHMARK_ADDFUNC(B, "Measure C++ implementation. Loop on ``if (*it >= th) ++nb;``");
    CBENCHMARK_ADDFUNC(C, "Measure C++ implementation. Loop on ``if (*it >= th) nb++;``");
    CBENCHMARK_ADDFUNC(D, "Measure C++ implementation. Loop on ``nb += *it >= th ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(E, "Measure C++ implementation. Loop on ``if (*it >= th) nb += 1;``");
    CBENCHMARK_ADDFUNC(F, "Measure C++ implementation. Loop on ``nb += (*it - th) >= 0 ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(G, "Measure C++ implementation. Loop on ``nb += (*it - th) < 0 ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(H, "Measure C++ implementation. Loop on ``nb += *it < th ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(I, "Measure C++ implementation. Loop on ``nb += 1 ^ ((unsigned int)(*it) >> (sizeof(int) * CHAR_BIT - 1));``");
    CBENCHMARK_ADDFUNC(J, "Measure C++ implementation. Loop on ``nb += values[i] >= th ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(Sleep, "Measure C++ implementation. Loop on ``sleep``");
}
<commit_msg>fix for gcc<commit_after>#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
//#include <numpy/arrayobject.h>
#include <vector>
#include <thread>
#include <iterator>
#include "repeat_fct.h"

namespace py = pybind11;

template<typename DTYPE>
class FunctionMeasureVectorCount : FunctionMeasure
{
    protected:

    std::vector<DTYPE> values;
    DTYPE th;

    public:

    FunctionMeasureVectorCount(const std::vector<DTYPE> &v, DTYPE t) : values(v), th(t)
    {
        if (values.size() == 0)
            throw std::runtime_error("Array to process must not be empty.");
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountSleep : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountSleep(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int i)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(th));
        return 0;
    }
};

#define REPEAT_INST(INST) {\
    INST INST INST INST INST\
    INST INST INST INST INST\
    }

template<typename DTYPE>
class FunctionMeasureVectorCountA : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountA(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1; // == 0 but otherwise the compiler detects the
                        // the code does not change depending on x
                        // and it caches the results.
        for(int i = 0; i < values.size(); ++i)
            REPEAT_INST(if (values[i] >= th) ++nb;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountB : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountB(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(if (*it >= th) ++nb;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountC : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountC(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(if (*it >= th) nb++;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountD : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountD(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += *it >= th ? 1 : 0;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountE : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountE(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(if (*it >= th) nb += 1;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountF : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountF(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += (*it - th) >= 0 ? 1 : 0;)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountG : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountG(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += (*it - th) < 0 ? 1 : 0;)
        return (int)std::distance(values.begin(), values.end()) - nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountH : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountH(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += *it < th ? 1 : 0;)
        return (int)std::distance(values.begin(), values.end()) - nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountI : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountI(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1;
        for(auto it = values.begin(); it != values.end(); ++it)
            REPEAT_INST(nb += 1 ^ ((unsigned int)(*it) >> (sizeof(int) * CHAR_BIT - 1));)
        return nb;
    }
};

template<typename DTYPE>
class FunctionMeasureVectorCountJ : FunctionMeasureVectorCount<DTYPE>
{
    public:
    FunctionMeasureVectorCountJ(const std::vector<DTYPE> &v, DTYPE t) :
        FunctionMeasureVectorCount<DTYPE>(v, t) { }
    int run(int x)
    {
        int nb = x % 1; // == 0 but otherwise the compiler detects the
                        // the code does not change depending on x
                        // and it caches the results.
        for(int i = 0; i < values.size(); ++i)
            REPEAT_INST(nb += values[i] >= th ? 1 : 0;)
        return nb;
    }
};

#if defined(_MSC_VER)
#define STRING_CONCAT(A, B) A ## B
#define CBENCHMARK_ADDFUNC(suf, C)\
    m.def(STRING_CONCAT("measure_scenario_", #suf), \
            [](const std::vector<int> &values, int th, int repeat=100, int number=1000, bool verbose=false) -> ExecutionStat { \
                ExecutionStat res; \
                FunctionMeasureVectorCount##suf<int> fct(values, th); \
                repeat_execution<FunctionMeasureVectorCount##suf<int>>(fct, repeat, number, res, verbose); \
                return res; \
            }, \
            C, \
            py::arg("values"), py::arg("th"), \
            py::arg("repeat")=10, py::arg("number")=100, \
            py::arg("verbose")=false);
#else
#define CBENCHMARK_ADDFUNC(suf, C)\
    m.def("measure_scenario_" ##suf), \
            [](const std::vector<int> &values, int th, int repeat=100, int number=1000, bool verbose=false) -> ExecutionStat { \
                ExecutionStat res; \
                FunctionMeasureVectorCount##suf<int> fct(values, th); \
                repeat_execution<FunctionMeasureVectorCount##suf<int>>(fct, repeat, number, res, verbose); \
                return res; \
            }, \
            C, \
            py::arg("values"), py::arg("th"), \
            py::arg("repeat")=10, py::arg("number")=100, \
            py::arg("verbose")=false);
#endif

PYBIND11_MODULE(cbenchmark, m) {
	m.doc() =
    #if defined(__APPLE__)
    "Measures the execution time of functions implemented in C."
    #else
    R"pbdoc(Measures the execution time of functions implemented in C, the measures are
also implemented in C.)pbdoc"
    #endif
    ;

    py::class_<ExecutionStat>(m, "ExecutionStat",
        "Holds results to compare execution time of functions.")
        .def(py::init<>())
        .def_readwrite("number", &ExecutionStat::number, "number of execution")
        .def_readwrite("repeat", &ExecutionStat::repeat, "number of calls per executions")
        .def_readwrite("average", &ExecutionStat::average, "average processing time")
        .def_readwrite("deviation", &ExecutionStat::deviation, "standard deviation")
        .def_readwrite("min_exec", &ExecutionStat::min_exec, "minimum execution time")
        .def_readwrite("max_exec", &ExecutionStat::max_exec, "maximum execution time")
        .def("__str__", [](const ExecutionStat& report) -> std::string {
            char buffer[1000];
            sprintf(buffer, "%1.3gs (+/- %1.3g) in [%1.3g, %1.3g] N=%d rep=%d",
                    report.average, report.deviation,
                    report.min_exec, report.max_exec,
                    report.number, report.repeat);
            return buffer;
            },
            "usual operator")
        .def("todict", [](const ExecutionStat& report) -> std::map<std::string, double> {
            std::map<std::string, double> res;
            res["average"] = report.average;
            res["deviation"] = report.deviation;
            res["min_exec"] = report.min_exec;
            res["max_exec"] = report.max_exec;
            res["number"] = report.number;
            res["repeat"] = report.repeat;
            return res;
        }, "Converts the structure into a dictionary.")
        ;

    CBENCHMARK_ADDFUNC(A, "Measure C++ implementation. Loop on ``if (values[i] >= th) ++nb;``");
    CBENCHMARK_ADDFUNC(B, "Measure C++ implementation. Loop on ``if (*it >= th) ++nb;``");
    CBENCHMARK_ADDFUNC(C, "Measure C++ implementation. Loop on ``if (*it >= th) nb++;``");
    CBENCHMARK_ADDFUNC(D, "Measure C++ implementation. Loop on ``nb += *it >= th ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(E, "Measure C++ implementation. Loop on ``if (*it >= th) nb += 1;``");
    CBENCHMARK_ADDFUNC(F, "Measure C++ implementation. Loop on ``nb += (*it - th) >= 0 ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(G, "Measure C++ implementation. Loop on ``nb += (*it - th) < 0 ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(H, "Measure C++ implementation. Loop on ``nb += *it < th ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(I, "Measure C++ implementation. Loop on ``nb += 1 ^ ((unsigned int)(*it) >> (sizeof(int) * CHAR_BIT - 1));``");
    CBENCHMARK_ADDFUNC(J, "Measure C++ implementation. Loop on ``nb += values[i] >= th ? 1 : 0;``");
    CBENCHMARK_ADDFUNC(Sleep, "Measure C++ implementation. Loop on ``sleep``");
}
<|endoftext|>


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

#ifndef __FRAMEWORK_ACCELERATORS_STORAGEHOLDER_HXX_
#define __FRAMEWORK_ACCELERATORS_STORAGEHOLDER_HXX_

//===============================================
// own includes

#ifndef __FRAMEWORK_ACCELERATORS_ISTORAGELISTENER_HXX_
#include <accelerators/istoragelistener.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_THREADHELPBASE_HXX_
#include <threadhelp/threadhelpbase.hxx>
#endif

#ifndef __FRAMEWORK_GENERAL_H_
#include <general.h>
#endif

#ifndef __FRAMEWORK_STDTYPES_H_
#include <stdtypes.h>
#endif

//===============================================
// interface includes

#ifndef __COM_SUN_STAR_EMBED_XSTORAGE_HPP_
#include <com/sun/star/embed/XStorage.hpp>
#endif

#ifndef __COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

//===============================================
// other includes

//===============================================
// namespace

namespace framework
{

#ifdef css
    #error "Who defines css? I will use it as namespace alias inside header."
#else
    #define css ::com::sun::star
#endif

//===============================================
// definitions

//-----------------------------------------------
/**
    TODO document me
 */
class StorageHolder : private ThreadHelpBase // attention! Must be the first base class to guarentee right initialize lock ...
{
    //-------------------------------------------
    // types
    public:

        /** @short  TODO */
        typedef ::std::vector< css::uno::Reference< css::embed::XStorage > > TStorageList;

        typedef ::std::vector< IStorageListener* > TStorageListenerList;

        struct TStorageInfo
        {
            public:
                css::uno::Reference< css::embed::XStorage > Storage;
                sal_Int32 UseCount;
                TStorageListenerList Listener;

                TStorageInfo()
                    : UseCount(0)
                {}
        };

        /** @short  TODO */
        typedef ::std::hash_map< ::rtl::OUString                    ,
                                 TStorageInfo                       ,
                                 ::rtl::OUStringHash                ,
                                 ::std::equal_to< ::rtl::OUString > > TPath2StorageInfo;

    //-------------------------------------------
    // member
    private:

        /** @short  TODO */
        css::uno::Reference< css::lang::XMultiServiceFactory > m_xSMGR;

        /** @short  TODO */
        css::uno::Reference< css::embed::XStorage > m_xRoot;

        /** @short  TODO */
        TPath2StorageInfo m_lStorages;

    //-------------------------------------------
    // interface
    public:

        //---------------------------------------
        /** @short  TODO
         */
        StorageHolder();

        //---------------------------------------
        /** @short  TODO
         */
        StorageHolder(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR);

        //---------------------------------------
        /** @short  TODO
         */
        virtual ~StorageHolder();

        //---------------------------------------
        /** @short  TODO
         */
        virtual void forgetCachedStorages();

        //---------------------------------------
        /** @short  TODO
         */
        virtual void setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot);

        //---------------------------------------
        /** @short  TODO
         */
        virtual css::uno::Reference< css::embed::XStorage > getRootStorage() const;

        //---------------------------------------
        /** @short  TODO
                    open or get!
         */
        virtual css::uno::Reference< css::embed::XStorage > openPath(const ::rtl::OUString& sPath    ,
                                                                           sal_Int32        nOpenMode);

        //---------------------------------------
        /** @short  TODO
         */
        virtual StorageHolder::TStorageList getAllPathStorages(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void commitPath(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void closePath(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void notifyPath(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void addStorageListener(      IStorageListener* pListener,
                                        const ::rtl::OUString&  sPath    );

        //---------------------------------------
        /** @short  TODO
         */
        virtual void removeStorageListener(      IStorageListener* pListener,
                                           const ::rtl::OUString&  sPath    );

        //---------------------------------------
        /** @short  TODO
         */
        virtual ::rtl::OUString getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage);

        //---------------------------------------
        /** @short  TODO
         */
        virtual css::uno::Reference< css::embed::XStorage > getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild);

        //---------------------------------------
        /** @short  TODO
         */
        virtual css::uno::Reference< css::embed::XStorage > getParentStorage(const ::rtl::OUString& sChildPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void operator=(const StorageHolder& rCopy);

        //---------------------------------------
        /** @short  TODO
         */
        static css::uno::Reference< css::embed::XStorage > createTempStorageBasedOnFolder(const ::rtl::OUString&                                        sFolder  ,
                                                                                const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR    ,
                                                                                sal_Bool                                                bReadOnly);

        //---------------------------------------
        /** @short  opens a sub element of the specified base storage.

            @descr  First this method try to open the requested sub element
                    using the given open mode. If it failed there is second step,
                    which tries to do the same again ... but removing a might existing
                    WRITE flag from the open mode. The user can supress this fallback
                    handling by setting the parameter bAllowFallback to FALSE.

            @param  xBaseStorage
                    the storage, where the sub element should be searched.

            @param  sSubElement
                    the full name of the sub element.
                    e.g. "default.xml"

            @param  eOpenMode
                    a flag field, which set the open mode for this operation.

            @param  bAllowFallback
                    if eOpenMode contains an ELEMENT_WRITE flag this parameter
                    allow to remove it and try it with the rest of eOpenMode flags
                    again.
         */
        static css::uno::Reference< css::embed::XStorage > openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage  ,
                                                                                const ::rtl::OUString&                             sSubStorage   ,
                                                                                sal_Int32                                    eOpenMode     ,
                                                                                sal_Bool                                     bAllowFallback);

        static css::uno::Reference< css::io::XStream > openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage  ,
                                                                                const ::rtl::OUString&                             sSubStream    ,
                                                                                sal_Int32                                    eOpenMode     ,
                                                                                sal_Bool                                     bAllowFallback);

        //---------------------------------------
        // helper
        private:

            //-----------------------------------
            /** @short  TODO
             */
            static ::rtl::OUString impl_st_normPath(const ::rtl::OUString& sPath);

            //-----------------------------------
            /** @short  TODO
             */
            static OUStringList impl_st_parsePath(const ::rtl::OUString& sPath);
};

#undef css // dont let it out!

} // namespace framework

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

#ifndef __FRAMEWORK_ACCELERATORS_STORAGEHOLDER_HXX_
#define __FRAMEWORK_ACCELERATORS_STORAGEHOLDER_HXX_

//===============================================
// own includes

#ifndef __FRAMEWORK_ACCELERATORS_ISTORAGELISTENER_HXX_
#include <accelerators/istoragelistener.hxx>
#endif

#ifndef __FRAMEWORK_THREADHELP_THREADHELPBASE_HXX_
#include <threadhelp/threadhelpbase.hxx>
#endif

#ifndef __FRAMEWORK_GENERAL_H_
#include <general.h>
#endif

#ifndef __FRAMEWORK_STDTYPES_H_
#include <stdtypes.h>
#endif

//===============================================
// interface includes

#ifndef __COM_SUN_STAR_EMBED_XSTORAGE_HPP_
#include <com/sun/star/embed/XStorage.hpp>
#endif

#ifndef __COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

//===============================================
// other includes

//===============================================
// namespace

namespace framework
{

#ifdef css
    #error "Who defines css? I will use it as namespace alias inside header."
#else
    #define css ::com::sun::star
#endif

//===============================================
// definitions

//-----------------------------------------------
/**
    TODO document me
 */
class StorageHolder : private ThreadHelpBase // attention! Must be the first base class to guarentee right initialize lock ...
{
    //-------------------------------------------
    // types
    public:

        /** @short  TODO */
        typedef ::std::vector< css::uno::Reference< css::embed::XStorage > > TStorageList;

        typedef ::std::vector< IStorageListener* > TStorageListenerList;

        struct TStorageInfo
        {
            public:
                css::uno::Reference< css::embed::XStorage > Storage;
                sal_Int32 UseCount;
                TStorageListenerList Listener;

                TStorageInfo()
                    : UseCount(0)
                {}
        };

        /** @short  TODO */
        typedef ::std::hash_map< ::rtl::OUString                    ,
                                 TStorageInfo                       ,
                                 ::rtl::OUStringHash                ,
                                 ::std::equal_to< ::rtl::OUString > > TPath2StorageInfo;

    //-------------------------------------------
    // member
    private:

        /** @short  TODO */
        css::uno::Reference< css::lang::XMultiServiceFactory > m_xSMGR;

        /** @short  TODO */
        css::uno::Reference< css::embed::XStorage > m_xRoot;

        /** @short  TODO */
        TPath2StorageInfo m_lStorages;

    //-------------------------------------------
    // interface
    public:

        //---------------------------------------
        /** @short  TODO
         */
        StorageHolder();

        //---------------------------------------
        /** @short  TODO
         */
        StorageHolder(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR);

        //---------------------------------------
        /** @short  TODO
         */
        virtual ~StorageHolder();

        //---------------------------------------
        /** @short  TODO
         */
        virtual void forgetCachedStorages();

        //---------------------------------------
        /** @short  TODO
         */
        virtual void setRootStorage(const css::uno::Reference< css::embed::XStorage >& xRoot);

        //---------------------------------------
        /** @short  TODO
         */
        virtual css::uno::Reference< css::embed::XStorage > getRootStorage() const;

        //---------------------------------------
        /** @short  TODO
                    open or get!
         */
        virtual css::uno::Reference< css::embed::XStorage > openPath(const ::rtl::OUString& sPath    ,
                                                                           sal_Int32        nOpenMode);

        //---------------------------------------
        /** @short  TODO
         */
        virtual StorageHolder::TStorageList getAllPathStorages(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void commitPath(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void closePath(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void notifyPath(const ::rtl::OUString& sPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void addStorageListener(      IStorageListener* pListener,
                                        const ::rtl::OUString&  sPath    );

        //---------------------------------------
        /** @short  TODO
         */
        virtual void removeStorageListener(      IStorageListener* pListener,
                                           const ::rtl::OUString&  sPath    );

        //---------------------------------------
        /** @short  TODO
         */
        virtual ::rtl::OUString getPathOfStorage(const css::uno::Reference< css::embed::XStorage >& xStorage);

        //---------------------------------------
        /** @short  TODO
         */
        virtual css::uno::Reference< css::embed::XStorage > getParentStorage(const css::uno::Reference< css::embed::XStorage >& xChild);

        //---------------------------------------
        /** @short  TODO
         */
        virtual css::uno::Reference< css::embed::XStorage > getParentStorage(const ::rtl::OUString& sChildPath);

        //---------------------------------------
        /** @short  TODO
         */
        virtual void operator=(const StorageHolder& rCopy);

        //---------------------------------------
        /** @short  TODO
         */
        static css::uno::Reference< css::embed::XStorage > createTempStorageBasedOnFolder(const ::rtl::OUString&                                        sFolder  ,
                                                                                const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR    ,
                                                                                sal_Bool                                                bReadOnly);

        //---------------------------------------
        /** @short  opens a sub element of the specified base storage.

            @descr  First this method try to open the requested sub element
                    using the given open mode. If it failed there is second step,
                    which tries to do the same again ... but removing a might existing
                    WRITE flag from the open mode. The user can supress this fallback
                    handling by setting the parameter bAllowFallback to FALSE.

            @param  xBaseStorage
                    the storage, where the sub element should be searched.

            @param  sSubElement
                    the full name of the sub element.
                    e.g. "default.xml"

            @param  eOpenMode
                    a flag field, which set the open mode for this operation.

            @param  bAllowFallback
                    if eOpenMode contains an ELEMENT_WRITE flag this parameter
                    allow to remove it and try it with the rest of eOpenMode flags
                    again.
         */
        static css::uno::Reference< css::embed::XStorage > openSubStorageWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage  ,
                                                                                const ::rtl::OUString&                             sSubStorage   ,
                                                                                sal_Int32                                    eOpenMode     ,
                                                                                sal_Bool                                     bAllowFallback);

        static css::uno::Reference< css::io::XStream > openSubStreamWithFallback(const css::uno::Reference< css::embed::XStorage >& xBaseStorage  ,
                                                                                const ::rtl::OUString&                             sSubStream    ,
                                                                                sal_Int32                                    eOpenMode     ,
                                                                                sal_Bool                                     bAllowFallback);

        //---------------------------------------
        // helper
        private:

            //-----------------------------------
            /** @short  TODO
             */
            static ::rtl::OUString impl_st_normPath(const ::rtl::OUString& sPath);

            //-----------------------------------
            /** @short  TODO
             */
            static OUStringList impl_st_parsePath(const ::rtl::OUString& sPath);
};

#undef css // dont let it out!

} // namespace framework

#endif // __FRAMEWORK_ACCELERATORS_STORAGEHOLDER_HXX_
<|endoftext|>


<commit_before>#ifndef HELLOBYEPROTO_CPP
#define HELLOBYEPROTO_CPP

#include <cstdlib>
#include <sstream>

#include "IPv4_5TupleL2Ident.hpp"
#include "headers.hpp"
#include "helloByeProto.hpp"
#include "mbuf.hpp"
#include "samplePacket.hpp"

// using namespace Headers;
// using namespace std;

/*
 * ===================================
 * HelloByeServerHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeServerHello<Identifier, Packet>::HelloByeServerHello() {
	this->serverCookie = rand() % 10;
};

template <class Identifier, class Packet>
void HelloBye::HelloByeServerHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT HELLO:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) != 0) {
		std::cout << "HelloByeServerHello::fun() clientStr didn't match" << std::endl;
		state.transition(HelloByeServer::Terminate);
		funIface.freePkt();
		return;
	}

	// Get client cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr) - 1];
	this->clientCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "SERVER HELLO:" << this->serverCookie << std::endl;
	std::string serverHelloStr = sstream.str();
	memcpy(udp->getPayload(), serverHelloStr.c_str(), serverHelloStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...

	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->checksum = 0;

	// Set UDP checksum to 0 and hope for the best

	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;

	state.transition(HelloByeServer::Bye);
};

/*
 * ===================================
 * HelloByeServerBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeServerBye<Identifier, Packet>::HelloByeServerBye(
	const HelloByeServerHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloBye::HelloByeServerBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Not needed in this function
	(void)funIface;

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT BYE:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) != 0) {
		std::cout << "HelloByeServerBye::fun() clientStr didn't match" << std::endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr) - 1];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if (recvCookie != this->serverCookie) {
		std::cout << "HelloByeServerBye::fun() Client sent over wrong cookie" << std::endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "SERVER BYE:" << this->clientCookie << std::endl;
	std::string serverByeStr = sstream.str();
	memcpy(udp->getPayload(), serverByeStr.c_str(), serverByeStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->checksum = 0;

	// Set UDP checksum to 0 and hope for the best
	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;
	// We are done after this -> transition to Terminate
	state.transition(HelloByeServer::Terminate);
};

/*
 * ===================================
 * HelloByeClientHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeClientHello<Identifier, Packet>::HelloByeClientHello(
	uint32_t dstIp, uint16_t srcPort)
	: dstIp(dstIp), srcPort(srcPort) {
	this->clientCookie = rand() % 10;
};

template <class Identifier, class Packet>
void HelloBye::HelloByeClientHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	(void)funIface;

	memset(pkt->getData(), 0, pkt->getDataLen());

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());

	HelloByeClientConfig *config = HelloByeClientConfig::getInstance();

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->setVersion();
	ipv4->setIHL(5);
	ipv4->ttl = 64;
	ipv4->setDstIP(this->dstIp);
	ipv4->setSrcIP(config->getSrcIP());
	ipv4->setProtoUDP();
	ipv4->checksum = 0;

	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "CLIENT HELLO:" << this->clientCookie << std::endl;
	std::string clientHelloStr = sstream.str();
	memcpy(udp->getPayload(), clientHelloStr.c_str(), clientHelloStr.length());

	ether->ethertype = htons(0x0800);

	// Set UDP checksum to 0 and hope for the best
	udp->checksum = 0;
	udp->dstPort = config->getDstPort();
	udp->srcPort = this->srcPort;

	state.transition(HelloByeClient::Bye);
};

/*
 * ===================================
 * HelloByeClientBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeClientBye<Identifier, Packet>::HelloByeClientBye(
	const HelloByeClientHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie) {}

template <class Identifier, class Packet>
void HelloBye::HelloByeClientBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Not needed in this function
	(void)funIface;

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER HELLO:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) != 0) {
		std::cout << "HelloByeClientBye::fun() serverStr didn't match" << std::endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get server cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr) - 1];
	this->serverCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "CLIENT BYE:" << this->serverCookie << std::endl;
	std::string clientByeStr = sstream.str();

	// Zero out old data - just assume 20 bytes...
	memset(udp->getPayload(), 0, 20);
	memcpy(udp->getPayload(), clientByeStr.c_str(), clientByeStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->checksum = 0;

	// Set UDP checksum to 0 and hope for the best
	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;

	// We need to wait for the server reply
	state.transition(HelloByeClient::RecvBye);
};

/*
 * ===================================
 * HelloByeClientRecvBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeClientRecvBye<Identifier, Packet>::HelloByeClientRecvBye(
	const HelloByeClientBye<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloBye::HelloByeClientRecvBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER BYE:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) != 0) {
		std::cout << "HelloByeClientRecvBye::fun() serverStr didn't match" << std::endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr) - 1];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if (recvCookie != this->clientCookie) {
		std::cout << "HelloByeClientRecvBye::fun() Server sent over wrong cookie"
				  << std::endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	funIface.freePkt();

	// We are done after this -> transition to Terminate
	state.transition(HelloByeClient::Terminate);
};

	/*
	 * ===================================
	 * Prepare template instances
	 * ===================================
	 *
	 */

	/*
	 * This file is now included in the header
	 *
	template class HelloByeServerHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeServerBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeClientHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeClientBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeClientRecvBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;

	template class HelloByeServerHello<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeServerBye<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeClientHello<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeClientBye<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeClientRecvBye<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	*/

#endif /* HELLOBYEPROTO_CPP */
<commit_msg>set UDP payload length in HelloByeClientHello<commit_after>#ifndef HELLOBYEPROTO_CPP
#define HELLOBYEPROTO_CPP

#include <cstdlib>
#include <sstream>

#include "IPv4_5TupleL2Ident.hpp"
#include "headers.hpp"
#include "helloByeProto.hpp"
#include "mbuf.hpp"
#include "samplePacket.hpp"

// using namespace Headers;
// using namespace std;

/*
 * ===================================
 * HelloByeServerHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeServerHello<Identifier, Packet>::HelloByeServerHello() {
	this->serverCookie = rand() % 10;
};

template <class Identifier, class Packet>
void HelloBye::HelloByeServerHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT HELLO:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) != 0) {
		std::cout << "HelloByeServerHello::fun() clientStr didn't match" << std::endl;
		state.transition(HelloByeServer::Terminate);
		funIface.freePkt();
		return;
	}

	// Get client cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr) - 1];
	this->clientCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "SERVER HELLO:" << this->serverCookie << std::endl;
	std::string serverHelloStr = sstream.str();
	memcpy(udp->getPayload(), serverHelloStr.c_str(), serverHelloStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...

	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->checksum = 0;

	// Set UDP checksum to 0 and hope for the best

	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;

	state.transition(HelloByeServer::Bye);
};

/*
 * ===================================
 * HelloByeServerBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeServerBye<Identifier, Packet>::HelloByeServerBye(
	const HelloByeServerHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloBye::HelloByeServerBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Not needed in this function
	(void)funIface;

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT BYE:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) != 0) {
		std::cout << "HelloByeServerBye::fun() clientStr didn't match" << std::endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr) - 1];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if (recvCookie != this->serverCookie) {
		std::cout << "HelloByeServerBye::fun() Client sent over wrong cookie" << std::endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "SERVER BYE:" << this->clientCookie << std::endl;
	std::string serverByeStr = sstream.str();
	memcpy(udp->getPayload(), serverByeStr.c_str(), serverByeStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->checksum = 0;

	// Set UDP checksum to 0 and hope for the best
	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;

	// We are done after this -> transition to Terminate
	state.transition(HelloByeServer::Terminate);
};

/*
 * ===================================
 * HelloByeClientHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeClientHello<Identifier, Packet>::HelloByeClientHello(
	uint32_t dstIp, uint16_t srcPort)
	: dstIp(dstIp), srcPort(srcPort) {
	this->clientCookie = rand() % 10;
};

template <class Identifier, class Packet>
void HelloBye::HelloByeClientHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	(void)funIface;

	memset(pkt->getData(), 0, pkt->getDataLen());

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());

	HelloByeClientConfig *config = HelloByeClientConfig::getInstance();

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->setVersion();
	ipv4->setIHL(5);
	ipv4->ttl = 64;
	ipv4->setPayloadLength(20);
	ipv4->setDstIP(this->dstIp);
	ipv4->setSrcIP(config->getSrcIP());
	ipv4->setProtoUDP();
	ipv4->checksum = 0;

	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "CLIENT HELLO:" << this->clientCookie << std::endl;
	std::string clientHelloStr = sstream.str();
	memcpy(udp->getPayload(), clientHelloStr.c_str(), clientHelloStr.length());

	ether->ethertype = htons(0x0800);

	// Set UDP checksum to 0 and hope for the best
	udp->checksum = 0;
	udp->setDstPort(config->getDstPort());
	udp->setSrcPort(this->srcPort);
	udp->setPayloadLength(ipv4->getPayloadLength());

	state.transition(HelloByeClient::Bye);
};

/*
 * ===================================
 * HelloByeClientBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeClientBye<Identifier, Packet>::HelloByeClientBye(
	const HelloByeClientHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie) {}

template <class Identifier, class Packet>
void HelloBye::HelloByeClientBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Not needed in this function
	(void)funIface;

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER HELLO:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) != 0) {
		std::cout << "HelloByeClientBye::fun() serverStr didn't match" << std::endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get server cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr) - 1];
	this->serverCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	std::stringstream sstream;
	sstream << "CLIENT BYE:" << this->serverCookie << std::endl;
	std::string clientByeStr = sstream.str();

	// Zero out old data - just assume 20 bytes...
	memset(udp->getPayload(), 0, 20);
	memcpy(udp->getPayload(), clientByeStr.c_str(), clientByeStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->checksum = 0;

	// Set UDP checksum to 0 and hope for the best
	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;

	// We need to wait for the server reply
	state.transition(HelloByeClient::RecvBye);
};

/*
 * ===================================
 * HelloByeClientRecvBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloBye::HelloByeClientRecvBye<Identifier, Packet>::HelloByeClientRecvBye(
	const HelloByeClientBye<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloBye::HelloByeClientRecvBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Headers::Ethernet *ether = reinterpret_cast<Headers::Ethernet *>(pkt->getData());
	Headers::IPv4 *ipv4 = reinterpret_cast<Headers::IPv4 *>(ether->getPayload());
	Headers::Udp *udp = reinterpret_cast<Headers::Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER BYE:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) != 0) {
		std::cout << "HelloByeClientRecvBye::fun() serverStr didn't match" << std::endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar =
		reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr) - 1];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if (recvCookie != this->clientCookie) {
		std::cout << "HelloByeClientRecvBye::fun() Server sent over wrong cookie"
				  << std::endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	funIface.freePkt();

	// We are done after this -> transition to Terminate
	state.transition(HelloByeClient::Terminate);
};

	/*
	 * ===================================
	 * Prepare template instances
	 * ===================================
	 *
	 */

	/*
	 * This file is now included in the header
	 *
	template class HelloByeServerHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeServerBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeClientHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeClientBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
	template class HelloByeClientRecvBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;

	template class HelloByeServerHello<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeServerBye<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeClientHello<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeClientBye<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	template class HelloByeClientRecvBye<IPv4_5TupleL2Ident<mbuf>, mbuf>;
	*/

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


<commit_before>#include "libport/config.h"

#include <boost/lexical_cast.hpp>

#include "libport/detect_win32.h"

#if defined LIBPORT_WIN32 || defined WIN32
# include "libport/windows.hh"
#else
# include <sys/select.h>
# include <errno.h>
#endif

#include "libport/compiler.hh"
#include "libport/read-stdin.hh"

namespace libport
{
  std::string
  read_stdin()
  {
    char buf[1024];
#if not defined LIBPORT_WIN32 &&  not defined WIN32
    //select
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(0,&fd);
    struct timeval tv;
    tv.tv_sec = tv.tv_usec = 0;
    int r = select(1,&fd,0,0,&tv);
    if (r <= -1)
      throw exception::Exception(__PRETTY_FUNCTION__,
	  std::string("select error on stdin: ") + strerror(errno));
    else if (r>0)
    {
      r = read(0, buf, sizeof buf -1); //-1 for the 0 we will insert
      if (r <= 0) // EOF counts as an 'error'.
      throw exception::Exception(__PRETTY_FUNCTION__,
	  std::string("read error on stdin: ") + ((r==0)?"EOF":strerror(errno)));
      else
	return std::string(buf, r);
    }
#else
    HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
    DWORD r = WaitForSingleObject(hstdin, 0);
    if (r != WAIT_TIMEOUT)
    {
      DWORD bytesRead;
      if (ReadFile(hstdin, buf, sizeof buf -1, &bytesRead, 0))
	return std::string(buf, bytesRead);
      else
	throw exception::Exception(__PRETTY_FUNCTION__,
	    std::string("read error on stdin: ")
	      + boost::lexical_cast<std::string>(GetLastError()));
    }
#endif
    return std::string();
  }
}
<commit_msg>Import cstring to get access to strerror.<commit_after>#include "libport/config.h"

#include <boost/lexical_cast.hpp>

#include <cstring>

#include "libport/detect_win32.h"

#if defined LIBPORT_WIN32 || defined WIN32
# include "libport/windows.hh"
#else
# include <sys/select.h>
# include <errno.h>
#endif

#include "libport/compiler.hh"
#include "libport/read-stdin.hh"

namespace libport
{
  std::string
  read_stdin()
  {
    char buf[1024];
#if not defined LIBPORT_WIN32 &&  not defined WIN32
    //select
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(0,&fd);
    struct timeval tv;
    tv.tv_sec = tv.tv_usec = 0;
    int r = select(1,&fd,0,0,&tv);
    if (r <= -1)
      throw exception::Exception(__PRETTY_FUNCTION__,
	  std::string("select error on stdin: ") + strerror(errno));
    else if (r>0)
    {
      r = read(0, buf, sizeof buf -1); //-1 for the 0 we will insert
      if (r <= 0) // EOF counts as an 'error'.
      throw exception::Exception(__PRETTY_FUNCTION__,
	  std::string("read error on stdin: ") + ((r==0)?"EOF":strerror(errno)));
      else
	return std::string(buf, r);
    }
#else
    HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
    DWORD r = WaitForSingleObject(hstdin, 0);
    if (r != WAIT_TIMEOUT)
    {
      DWORD bytesRead;
      if (ReadFile(hstdin, buf, sizeof buf -1, &bytesRead, 0))
	return std::string(buf, bytesRead);
      else
	throw exception::Exception(__PRETTY_FUNCTION__,
	    std::string("read error on stdin: ")
	      + boost::lexical_cast<std::string>(GetLastError()));
    }
#endif
    return std::string();
  }
}
<|endoftext|>