<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 <QTimeLine>

#include "mpannablewidget.h"
#include "mphysics2dpanning.h"
#include "mphysics2dpanning_p.h"

MPhysics2DPanningPrivate::MPhysics2DPanningPrivate(MPhysics2DPanning *publicObject) :
    enabled(true),
    range(QRectF(0.0, 0.0, 0.0, 0.0)),
    posX(0.0),
    posY(0.0),
    velX(0.0),
    velY(0.0),
    pointerSpringX(0.0),
    pointerSpringY(0.0),
    sceneLastPos(QPointF()),
    panningAnimation(new PanningAnimation),
    pointerPressed(false),
    pointerSpringK(0.0),
    frictionC(0.0),
    slideFrictionC(0.0),
    borderSpringK(0.0),
    borderFrictionC(0.0),
    panDirection(0),
    q_ptr(publicObject)
{
}

MPhysics2DPanningPrivate::~MPhysics2DPanningPrivate()
{
    delete panningAnimation;
}

void MPhysics2DPanningPrivate::_q_integrator(const QVariant &value)
{
    Q_Q(MPhysics2DPanning);
    Q_UNUSED(value);

    qreal accX, accY;
    qreal tempPosX;
    qreal tempPosY;

    tempPosX = posX;
    tempPosY = posY;

    if (panDirection.testFlag(Qt::Horizontal)) {
        q->integrateAxis(Qt::Horizontal,
                         posX,
                         velX,
                         accX,
                         pointerSpringX,
                         pointerPressed
                         );
    } else {
        posX = 0.0f;
        velX = 0.0f;
        accX = 0.0f;
    }

    if (panDirection.testFlag(Qt::Vertical)) {
        q->integrateAxis(Qt::Vertical,
                         posY,
                         velY,
                         accY,
                         pointerSpringY,
                         pointerPressed
                         );

    } else {
        posY = 0.0f;
        velY = 0.0f;
        accY = 0.0f;
    }

    // Checking if the viewport is currently dragged beyond it's borders and the integration should
    // continue even though the speed is low.
    bool inRangeX = (panDirection.testFlag(Qt::Horizontal) == false) ||
                    (posX >= range.left() && posX <= range.right());

    bool inRangeY = (panDirection.testFlag(Qt::Vertical) == false) ||
                    (posY >= range.top()  && posY <= range.bottom());

        // Integration stop condition.
    if (inRangeX && inRangeY &&
        qAbs(accX) < 1 &&
        qAbs(accY) < 1 &&
        qAbs(velX) < 1 &&
        qAbs(velY) < 1 &&
        !pointerPressed) {
        panningAnimation->stop();

        emit q->panningStopped();
    }

    if (tempPosX != posX || tempPosY != posY) {
        emit(q->positionChanged(QPointF(posX, posY)));
    }
}

MPhysics2DPanning::MPhysics2DPanning(QObject *parent)
    : QObject(parent),
      d_ptr(new MPhysics2DPanningPrivate(this))
{
    Q_D(MPhysics2DPanning);
    connect(d->panningAnimation, SIGNAL(valueChanged(QVariant)), SLOT(_q_integrator(QVariant)));
}

MPhysics2DPanning::~MPhysics2DPanning()
{
    delete d_ptr;
}

bool MPhysics2DPanning::enabled() const
{
    return d_ptr->enabled;
}

void MPhysics2DPanning::setEnabled(bool enabled)
{
    Q_D(MPhysics2DPanning);

    d->enabled = enabled;
    if (d->enabled == false) stop();
}

Qt::Orientations MPhysics2DPanning::panDirection() const
{
    return d_ptr->panDirection;
}

void MPhysics2DPanning::setPanDirection(Qt::Orientations direction)
{
    d_ptr->panDirection = direction;
}

qreal MPhysics2DPanning::pointerSpringK() const
{
    return d_ptr->pointerSpringK;
}

void MPhysics2DPanning::setPointerSpringK(qreal value)
{
    d_ptr->pointerSpringK = value;
}

qreal MPhysics2DPanning::friction() const
{
    return d_ptr->frictionC;
}

void MPhysics2DPanning::setFriction(qreal value)
{
    d_ptr->frictionC = value;
}

qreal MPhysics2DPanning::slidingFriction() const
{
    return d_ptr->slideFrictionC;
}

void MPhysics2DPanning::setSlidingFriction(qreal value)
{
    d_ptr->slideFrictionC = value;
}

qreal MPhysics2DPanning::borderSpringK() const
{
    return d_ptr->borderSpringK;
}

void MPhysics2DPanning::setBorderSpringK(qreal value)
{
    d_ptr->borderSpringK = value;
}

qreal MPhysics2DPanning::borderFriction() const
{
    return d_ptr->borderFrictionC;
}

void MPhysics2DPanning::setBorderFriction(qreal value)
{
    d_ptr->borderFrictionC = value;
}

void MPhysics2DPanning::start()
{
    Q_D(MPhysics2DPanning);
    if (!inMotion()) {
        d->velX = 0.0f;
        d->velY = 0.0f;

        // Duration does not matter as we loop until the physics termination condition is hit
        d->panningAnimation->setDuration(1000000);
        d->panningAnimation->setLoopCount(-1);

        d->panningAnimation->setStartValue(0.0f);
        d->panningAnimation->setEndValue(1.0f);

        d->panningAnimation->start();
    }
}

void MPhysics2DPanning::stop()
{
    Q_D(MPhysics2DPanning);

    // Checking if the viewport is currently dragged beyond it's borders and the integration should
    // continue.
    bool inRangeX = (d->panDirection.testFlag(Qt::Horizontal) == false) ||
                    (d->posX >= d->range.left() && d->posX <= d->range.right());

    bool inRangeY = (d->panDirection.testFlag(Qt::Vertical) == false) ||
                    (d->posY >= d->range.top()  && d->posY <= d->range.bottom());

    if (inRangeX && inRangeY) {
        d->panningAnimation->stop();
        emit panningStopped();
    }
}

void MPhysics2DPanning::setRange(const QRectF &range)
{
    Q_D(MPhysics2DPanning);

    //update the range only if it has actually changed
    if( d->range != range ) {
        d->range = range;

        // Updates position after range setting (but this is not enough to
        // drag the position inside range in case range shrinks and puts
        // position outside it)
        emit positionChanged(QPointF(d->posX, d->posY));

        // Starts physics to return the position into range (border spring
        // activates). This does not cover the former case since physics
        // emits no positionChanged signals in case the position is still
        // inside range
        start();
    }
}

QRectF MPhysics2DPanning::range() const
{
    Q_D(const MPhysics2DPanning);
    return d->range;
}

void MPhysics2DPanning::setPosition(const QPointF &position)
{
    Q_D(MPhysics2DPanning);

    if (QPointF(d->posX, d->posY) != position) {
        d->posX = position.x();
        d->posY = position.y();

        emit positionChanged(position);

        // Starts the physics in case the position is set to border
        // and it needs to slide back into range
        start();
    }
}

QPointF MPhysics2DPanning::position() const
{
    Q_D(const MPhysics2DPanning);

    return QPointF(d->posX, d->posY);
}

QPointF MPhysics2DPanning::velocity() const
{
    Q_D(const MPhysics2DPanning);

    return QPointF(d->velX, d->velY);
}

bool MPhysics2DPanning::inMotion() const
{
    Q_D(const MPhysics2DPanning);

    return (d->panningAnimation->state() == QAbstractAnimation::Running);
}

void MPhysics2DPanning::pointerPress(const QPointF &pos)
{
    Q_D(MPhysics2DPanning);

    // Enables the pointer spring, sets it to zero length and
    // starts the integrator

    d->pointerPressed = true;
    d->sceneLastPos = pos;

    d->pointerSpringX = 0.0f;
    d->pointerSpringY = 0.0f;
}

void MPhysics2DPanning::pointerMove(const QPointF &pos)
{
    Q_D(MPhysics2DPanning);

    // Tenses the pointer spring with the amount of movement of the pointer
    QPointF delta = pos - d->sceneLastPos;

    d->sceneLastPos = pos;

    if (d->enabled) {
        d->pointerSpringX += delta.x();
        d->pointerSpringY += delta.y();
        start();
    } else {

        bool emitSignal = false;

        if (d->panDirection.testFlag(Qt::Horizontal)) {

            qreal prevPosX = d->posX;
            d->posX -= delta.x();

            if (d->posX < d->range.left()) d->posX = d->range.left();
            if (d->posX > d->range.right()) d->posX = d->range.right();

            if (prevPosX != d->posX) emitSignal = true;
        }

        if (d->panDirection.testFlag(Qt::Vertical)) {

            qreal prevPosY = d->posY;
            d->posY -= delta.y();

            if (d->posY < d->range.top()) d->posY = d->range.top();
            if (d->posY > d->range.bottom()) d->posY = d->range.bottom();

            if (prevPosY != d->posY) emitSignal = true;
        }

        if (emitSignal) emit positionChanged(QPointF(d->posX, d->posY));
    }

}

void MPhysics2DPanning::pointerRelease()
{
    Q_D(MPhysics2DPanning);

    // Disables the pointer spring
    d->pointerPressed = false;

    if (d->enabled == false) {
        //The physics engine is not working, emitting panning stopped now.
        emit panningStopped();
    }
}

void MPhysics2DPanning::integrateAxis(Qt::Orientation orientation,
                                        qreal &position,
                                        qreal &velocity,
                                        qreal &acceleration,
                                        qreal &pointerDifference,
                                        bool pointerPressed
                                        )
{
    Q_D(MPhysics2DPanning);

    qreal force;
    qreal rangeStart = (orientation == Qt::Vertical ? d->range.top() : d->range.left());
    qreal rangeEnd =   (orientation == Qt::Vertical ? d->range.bottom() : d->range.right());

    // Damping
    if (position >= rangeStart && position <= rangeEnd) {

        // Inside range
        if (d->pointerPressed) {
            force = -d->frictionC * velocity;
        } else {
            force = -d->slideFrictionC * velocity;
        }
    } else {
        // Outside range (in border)
        force = -d->borderFrictionC * velocity;
    }

    // Border springs
    if (position < rangeStart) {
        force += d->borderSpringK * (rangeStart - position);
        //Special case - when the border is crossed,
        //we don't want the view to "bounce" from the border.
        //We snap in this place to rangeStart value;
        if ((pointerPressed == false) && (position + velocity + force >= rangeStart)) {
            velocity = force = 0;
            position = rangeStart;
        }
    }

    if (position > rangeEnd) {
        force += -d->borderSpringK * (position - rangeEnd);
        //Special case - when the border is crossed
        //we don't want the view to "bounce" from the border.
        //We snap in this place to rangeEnd value;
        if ((pointerPressed == false) && (position + velocity + force <= rangeEnd)) {
            velocity = force = 0;
            position = rangeEnd;
        }
    }

    // Integration. Currently does not use time_delta or mass (assumed as 1.0)

    if (pointerPressed) {

        // Damping of acceleration with pointer spring values.
        force += d->pointerSpringK * pointerDifference;
        // Increasing the speed by the last movement of the pointer
        acceleration = force - pointerDifference;
        velocity += acceleration;

        position           -= pointerDifference;
        pointerDifference = 0;

    } else {

        acceleration = force - pointerDifference;

        velocity                 += acceleration;
        position                 += velocity;
        pointerDifference        = 0;
    }
}

#include "moc_mphysics2dpanning.cpp"
<commit_msg>Fixes: The MPannableViewport::setPosition() method should stop movement of the viewport.<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 <QTimeLine>

#include "mpannablewidget.h"
#include "mphysics2dpanning.h"
#include "mphysics2dpanning_p.h"

MPhysics2DPanningPrivate::MPhysics2DPanningPrivate(MPhysics2DPanning *publicObject) :
    enabled(true),
    range(QRectF(0.0, 0.0, 0.0, 0.0)),
    posX(0.0),
    posY(0.0),
    velX(0.0),
    velY(0.0),
    pointerSpringX(0.0),
    pointerSpringY(0.0),
    sceneLastPos(QPointF()),
    panningAnimation(new PanningAnimation),
    pointerPressed(false),
    pointerSpringK(0.0),
    frictionC(0.0),
    slideFrictionC(0.0),
    borderSpringK(0.0),
    borderFrictionC(0.0),
    panDirection(0),
    q_ptr(publicObject)
{
}

MPhysics2DPanningPrivate::~MPhysics2DPanningPrivate()
{
    delete panningAnimation;
}

void MPhysics2DPanningPrivate::_q_integrator(const QVariant &value)
{
    Q_Q(MPhysics2DPanning);
    Q_UNUSED(value);

    qreal accX, accY;
    qreal tempPosX;
    qreal tempPosY;

    tempPosX = posX;
    tempPosY = posY;

    if (panDirection.testFlag(Qt::Horizontal)) {
        q->integrateAxis(Qt::Horizontal,
                         posX,
                         velX,
                         accX,
                         pointerSpringX,
                         pointerPressed
                         );
    } else {
        posX = 0.0f;
        velX = 0.0f;
        accX = 0.0f;
    }

    if (panDirection.testFlag(Qt::Vertical)) {
        q->integrateAxis(Qt::Vertical,
                         posY,
                         velY,
                         accY,
                         pointerSpringY,
                         pointerPressed
                         );

    } else {
        posY = 0.0f;
        velY = 0.0f;
        accY = 0.0f;
    }

    // Checking if the viewport is currently dragged beyond it's borders and the integration should
    // continue even though the speed is low.
    bool inRangeX = (panDirection.testFlag(Qt::Horizontal) == false) ||
                    (posX >= range.left() && posX <= range.right());

    bool inRangeY = (panDirection.testFlag(Qt::Vertical) == false) ||
                    (posY >= range.top()  && posY <= range.bottom());

        // Integration stop condition.
    if (inRangeX && inRangeY &&
        qAbs(accX) < 1 &&
        qAbs(accY) < 1 &&
        qAbs(velX) < 1 &&
        qAbs(velY) < 1 &&
        !pointerPressed) {
        panningAnimation->stop();

        emit q->panningStopped();
    }

    if (tempPosX != posX || tempPosY != posY) {
        emit(q->positionChanged(QPointF(posX, posY)));
    }
}

MPhysics2DPanning::MPhysics2DPanning(QObject *parent)
    : QObject(parent),
      d_ptr(new MPhysics2DPanningPrivate(this))
{
    Q_D(MPhysics2DPanning);
    connect(d->panningAnimation, SIGNAL(valueChanged(QVariant)), SLOT(_q_integrator(QVariant)));
}

MPhysics2DPanning::~MPhysics2DPanning()
{
    delete d_ptr;
}

bool MPhysics2DPanning::enabled() const
{
    return d_ptr->enabled;
}

void MPhysics2DPanning::setEnabled(bool enabled)
{
    Q_D(MPhysics2DPanning);

    d->enabled = enabled;
    if (d->enabled == false) stop();
}

Qt::Orientations MPhysics2DPanning::panDirection() const
{
    return d_ptr->panDirection;
}

void MPhysics2DPanning::setPanDirection(Qt::Orientations direction)
{
    d_ptr->panDirection = direction;
}

qreal MPhysics2DPanning::pointerSpringK() const
{
    return d_ptr->pointerSpringK;
}

void MPhysics2DPanning::setPointerSpringK(qreal value)
{
    d_ptr->pointerSpringK = value;
}

qreal MPhysics2DPanning::friction() const
{
    return d_ptr->frictionC;
}

void MPhysics2DPanning::setFriction(qreal value)
{
    d_ptr->frictionC = value;
}

qreal MPhysics2DPanning::slidingFriction() const
{
    return d_ptr->slideFrictionC;
}

void MPhysics2DPanning::setSlidingFriction(qreal value)
{
    d_ptr->slideFrictionC = value;
}

qreal MPhysics2DPanning::borderSpringK() const
{
    return d_ptr->borderSpringK;
}

void MPhysics2DPanning::setBorderSpringK(qreal value)
{
    d_ptr->borderSpringK = value;
}

qreal MPhysics2DPanning::borderFriction() const
{
    return d_ptr->borderFrictionC;
}

void MPhysics2DPanning::setBorderFriction(qreal value)
{
    d_ptr->borderFrictionC = value;
}

void MPhysics2DPanning::start()
{
    Q_D(MPhysics2DPanning);
    if (!inMotion()) {
        d->velX = 0.0f;
        d->velY = 0.0f;

        // Duration does not matter as we loop until the physics termination condition is hit
        d->panningAnimation->setDuration(1000000);
        d->panningAnimation->setLoopCount(-1);

        d->panningAnimation->setStartValue(0.0f);
        d->panningAnimation->setEndValue(1.0f);

        d->panningAnimation->start();
    }
}

void MPhysics2DPanning::stop()
{
    Q_D(MPhysics2DPanning);

    // Checking if the viewport is currently dragged beyond it's borders and the integration should
    // continue.
    bool inRangeX = (d->panDirection.testFlag(Qt::Horizontal) == false) ||
                    (d->posX >= d->range.left() && d->posX <= d->range.right());

    bool inRangeY = (d->panDirection.testFlag(Qt::Vertical) == false) ||
                    (d->posY >= d->range.top()  && d->posY <= d->range.bottom());

    if (inRangeX && inRangeY) {
        d->panningAnimation->stop();
        emit panningStopped();
    }
}

void MPhysics2DPanning::setRange(const QRectF &range)
{
    Q_D(MPhysics2DPanning);

    //update the range only if it has actually changed
    if( d->range != range ) {
        d->range = range;

        // Updates position after range setting (but this is not enough to
        // drag the position inside range in case range shrinks and puts
        // position outside it)
        emit positionChanged(QPointF(d->posX, d->posY));

        // Starts physics to return the position into range (border spring
        // activates). This does not cover the former case since physics
        // emits no positionChanged signals in case the position is still
        // inside range
        start();
    }
}

QRectF MPhysics2DPanning::range() const
{
    Q_D(const MPhysics2DPanning);
    return d->range;
}

void MPhysics2DPanning::setPosition(const QPointF &position)
{
    Q_D(MPhysics2DPanning);

    if (QPointF(d->posX, d->posY) != position) {
        d->posX = position.x();
        d->posY = position.y();

        emit positionChanged(position);

        if (inMotion()) {
            // If we are in the middle of the movement, we should reduce the speed
            // but not stop because we might be outside bounds.
            d->velX = 0.0;
            d->velY = 0.0;
        } else {
            // Starts the physics in case the position is set to border
            // and it needs to slide back into range
            start();
        }
    }
}

QPointF MPhysics2DPanning::position() const
{
    Q_D(const MPhysics2DPanning);

    return QPointF(d->posX, d->posY);
}

QPointF MPhysics2DPanning::velocity() const
{
    Q_D(const MPhysics2DPanning);

    return QPointF(d->velX, d->velY);
}

bool MPhysics2DPanning::inMotion() const
{
    Q_D(const MPhysics2DPanning);

    return (d->panningAnimation->state() == QAbstractAnimation::Running);
}

void MPhysics2DPanning::pointerPress(const QPointF &pos)
{
    Q_D(MPhysics2DPanning);

    // Enables the pointer spring, sets it to zero length and
    // starts the integrator

    d->pointerPressed = true;
    d->sceneLastPos = pos;

    d->pointerSpringX = 0.0f;
    d->pointerSpringY = 0.0f;
}

void MPhysics2DPanning::pointerMove(const QPointF &pos)
{
    Q_D(MPhysics2DPanning);

    // Tenses the pointer spring with the amount of movement of the pointer
    QPointF delta = pos - d->sceneLastPos;

    d->sceneLastPos = pos;

    if (d->enabled) {
        d->pointerSpringX += delta.x();
        d->pointerSpringY += delta.y();
        start();
    } else {

        bool emitSignal = false;

        if (d->panDirection.testFlag(Qt::Horizontal)) {

            qreal prevPosX = d->posX;
            d->posX -= delta.x();

            if (d->posX < d->range.left()) d->posX = d->range.left();
            if (d->posX > d->range.right()) d->posX = d->range.right();

            if (prevPosX != d->posX) emitSignal = true;
        }

        if (d->panDirection.testFlag(Qt::Vertical)) {

            qreal prevPosY = d->posY;
            d->posY -= delta.y();

            if (d->posY < d->range.top()) d->posY = d->range.top();
            if (d->posY > d->range.bottom()) d->posY = d->range.bottom();

            if (prevPosY != d->posY) emitSignal = true;
        }

        if (emitSignal) emit positionChanged(QPointF(d->posX, d->posY));
    }

}

void MPhysics2DPanning::pointerRelease()
{
    Q_D(MPhysics2DPanning);

    // Disables the pointer spring
    d->pointerPressed = false;

    if (d->enabled == false) {
        //The physics engine is not working, emitting panning stopped now.
        emit panningStopped();
    }
}

void MPhysics2DPanning::integrateAxis(Qt::Orientation orientation,
                                        qreal &position,
                                        qreal &velocity,
                                        qreal &acceleration,
                                        qreal &pointerDifference,
                                        bool pointerPressed
                                        )
{
    Q_D(MPhysics2DPanning);

    qreal force;
    qreal rangeStart = (orientation == Qt::Vertical ? d->range.top() : d->range.left());
    qreal rangeEnd =   (orientation == Qt::Vertical ? d->range.bottom() : d->range.right());

    // Damping
    if (position >= rangeStart && position <= rangeEnd) {

        // Inside range
        if (d->pointerPressed) {
            force = -d->frictionC * velocity;
        } else {
            force = -d->slideFrictionC * velocity;
        }
    } else {
        // Outside range (in border)
        force = -d->borderFrictionC * velocity;
    }

    // Border springs
    if (position < rangeStart) {
        force += d->borderSpringK * (rangeStart - position);
        //Special case - when the border is crossed,
        //we don't want the view to "bounce" from the border.
        //We snap in this place to rangeStart value;
        if ((pointerPressed == false) && (position + velocity + force >= rangeStart)) {
            velocity = force = 0;
            position = rangeStart;
        }
    }

    if (position > rangeEnd) {
        force += -d->borderSpringK * (position - rangeEnd);
        //Special case - when the border is crossed
        //we don't want the view to "bounce" from the border.
        //We snap in this place to rangeEnd value;
        if ((pointerPressed == false) && (position + velocity + force <= rangeEnd)) {
            velocity = force = 0;
            position = rangeEnd;
        }
    }

    // Integration. Currently does not use time_delta or mass (assumed as 1.0)

    if (pointerPressed) {

        // Damping of acceleration with pointer spring values.
        force += d->pointerSpringK * pointerDifference;
        // Increasing the speed by the last movement of the pointer
        acceleration = force - pointerDifference;
        velocity += acceleration;

        position           -= pointerDifference;
        pointerDifference = 0;

    } else {

        acceleration = force - pointerDifference;

        velocity                 += acceleration;
        position                 += velocity;
        pointerDifference        = 0;
    }
}

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


<commit_before>#include <cppunit/Portability.h>

#if defined(CPPUNIT_HAVE_UNIX_DLL_LOADER)
#include <cppunit/plugin/DynamicLibraryManager.h>

#include <dlfcn.h>
#include <unistd.h>

namespace CppUnit
{

DynamicLibraryManager::LibraryHandle
DynamicLibraryManager::doLoadLibrary( const std::string &libraryName )
{
  return ::dlopen( libraryFileName.c_str(), DLOPEN_MODE );
}

void
DynamicLibraryManager::doReleaseLibrary()
{
  ::dlclose( m_libraryHandle);
}

DynamicLibraryManager::Symbol
DynamicLibraryManager::doFindSymbol( const std::string &symbol )
{
  return ::dlsym ( m_libraryHandle, symbol.c_str() );
}

} //  namespace CppUnit

#endif // defined(CPPUNIT_HAVE_UNIX_DLL_LOADER)
<commit_msg>fixed typo<commit_after>#include <cppunit/Portability.h>

#if defined(CPPUNIT_HAVE_UNIX_DLL_LOADER)
#include <cppunit/plugin/DynamicLibraryManager.h>

#include <dlfcn.h>
#include <unistd.h>

namespace CppUnit
{

DynamicLibraryManager::LibraryHandle
DynamicLibraryManager::doLoadLibrary( const std::string &libraryName )
{
  return ::dlopen( libraryName.c_str(), DLOPEN_MODE );
}

void
DynamicLibraryManager::doReleaseLibrary()
{
  ::dlclose( m_libraryHandle);
}

DynamicLibraryManager::Symbol
DynamicLibraryManager::doFindSymbol( const std::string &symbol )
{
  return ::dlsym ( m_libraryHandle, symbol.c_str() );
}

} //  namespace CppUnit

#endif // defined(CPPUNIT_HAVE_UNIX_DLL_LOADER)
<|endoftext|>


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

#include "build/build_config.h"

#include "chrome/browser/plugin_service.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/values.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_plugin_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/gpu_plugin.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#ifndef DISABLE_NACL
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#endif
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_MACOSX)
static void NotifyPluginsOfActivation() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    plugin->OnAppActivation();
  }
}
#endif

// static
bool PluginService::enable_chrome_plugins_ = true;
bool PluginService::enable_internal_pdf_ = false;

// static
void PluginService::InitGlobalInstance(Profile* profile) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  bool update_internal_dir = false;
  FilePath last_internal_dir =
      profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
  FilePath cur_internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
      cur_internal_dir != last_internal_dir) {
    update_internal_dir = true;
    profile->GetPrefs()->SetFilePath(
        prefs::kPluginsLastInternalDirectory, cur_internal_dir);
  }

  bool found_internal_pdf = false;
  bool force_enable_internal_pdf = false;
  FilePath pdf_path;
  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
  FilePath::StringType pdf_path_str = pdf_path.value();
  if (enable_internal_pdf_ &&
      !profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
    // We switched to the internal pdf plugin being on by default, and so we
    // need to force it to be enabled.  We only want to do it this once though,
    // i.e. we don't want to enable it again if the user disables it afterwards.
    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
    force_enable_internal_pdf = true;
  }

  // Disable plugins listed as disabled in prefs.
  if (ListValue* saved_plugins_list =
          profile->GetPrefs()->GetMutableList(prefs::kPluginsPluginsList)) {
    for (ListValue::const_iterator it = saved_plugins_list->begin();
         it != saved_plugins_list->end();
         ++it) {
      if (!(*it)->IsType(Value::TYPE_DICTIONARY)) {
        LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
        continue;  // Oops, don't know what to do with this item.
      }

      DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
      FilePath::StringType path;
      if (!plugin->GetString(L"path", &path))
        continue;

      bool enabled = true;
      plugin->GetBoolean(L"enabled", &enabled);

      if (path == pdf_path_str) {
        found_internal_pdf = true;
        if (!enabled && force_enable_internal_pdf) {
          enabled = true;
          plugin->SetBoolean(L"enabled", true);
        }
      }

      FilePath plugin_path(path);
      if (update_internal_dir && plugin_path.DirName() == last_internal_dir) {
        // If the internal plugin directory has changed and if the plugin looks
        // internal, update its path in the prefs.
        plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
        plugin->SetString(L"path", plugin_path.value());
      }

      if (!enabled)
        NPAPI::PluginList::Singleton()->DisablePlugin(plugin_path);
    }
  }

  if (!enable_internal_pdf_ && !found_internal_pdf) {
    // The internal PDF plugin is disabled by default, and the user hasn't
    // overridden the default.
    NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path);
  }

  // Have Chrome plugins write their data to the profile directory.
  GetInstance()->SetChromePluginDataDir(profile->GetPath());
}

// static
PluginService* PluginService::GetInstance() {
  return Singleton<PluginService>::get();
}

// static
void PluginService::EnableChromePlugins(bool enable) {
  enable_chrome_plugins_ = enable;
}

PluginService::PluginService()
    : main_message_loop_(MessageLoop::current()),
      resource_dispatcher_host_(NULL),
      ui_locale_(ASCIIToWide(g_browser_process->GetApplicationLocale())) {
  // Have the NPAPI plugin list search for Chrome plugins as well.
  ChromePluginLib::RegisterPluginsWithNPAPI();
  // Load the one specified on the command line as well.
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
  if (!path.empty())
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);

  // Register the internal Flash and PDF, if available.
  if (!CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableInternalFlash) &&
      PathService::Get(chrome::FILE_FLASH_PLUGIN, &path)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
  }

  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path))
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);

#ifndef DISABLE_NACL
  if (command_line->HasSwitch(switches::kInternalNaCl))
    RegisterInternalNaClPlugin();
#endif

  chrome::RegisterInternalGPUPlugin();

#if defined(OS_WIN)
  hkcu_key_.Create(
      HKEY_CURRENT_USER, kRegistryMozillaPlugins, KEY_NOTIFY);
  hklm_key_.Create(
      HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins, KEY_NOTIFY);
  if (hkcu_key_.StartWatching()) {
    hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
    hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
  }

  if (hklm_key_.StartWatching()) {
    hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
    hklm_watcher_.StartWatching(hklm_event_.get(), this);
  }
#elif defined(OS_POSIX) && !defined(OS_MACOSX)
  // Also find plugins in a user-specific plugins dir,
  // e.g. ~/.config/chromium/Plugins.
  FilePath user_data_dir;
  if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginDir(
        user_data_dir.Append("Plugins"));
  }
#endif

  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
#if defined(OS_MACOSX)
  // We need to know when the browser comes forward so we can bring modal plugin
  // windows forward too.
  registrar_.Add(this, NotificationType::APP_ACTIVATED,
                 NotificationService::AllSources());
#endif
}

PluginService::~PluginService() {
#if defined(OS_WIN)
  // Release the events since they're owned by RegKey, not WaitableEvent.
  hkcu_watcher_.StopWatching();
  hklm_watcher_.StopWatching();
  hkcu_event_->Release();
  hklm_event_->Release();
#endif
}

void PluginService::LoadChromePlugins(
    ResourceDispatcherHost* resource_dispatcher_host) {
  if (!enable_chrome_plugins_)
    return;

  resource_dispatcher_host_ = resource_dispatcher_host;
  ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
}

void PluginService::SetChromePluginDataDir(const FilePath& data_dir) {
  chrome_plugin_data_dir_ = data_dir;
}

const FilePath& PluginService::GetChromePluginDataDir() {
  return chrome_plugin_data_dir_;
}

const std::wstring& PluginService::GetUILocale() {
  return ui_locale_;
}

PluginProcessHost* PluginService::FindPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  if (plugin_path.value().empty()) {
    NOTREACHED() << "should only be called if we have a plugin to load";
    return NULL;
  }

  for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    if (plugin->info().path == plugin_path)
      return plugin;
  }

  return NULL;
}

PluginProcessHost* PluginService::FindOrStartPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  PluginProcessHost *plugin_host = FindPluginProcess(plugin_path);
  if (plugin_host)
    return plugin_host;

  WebPluginInfo info;
  if (!NPAPI::PluginList::Singleton()->GetPluginInfoByPath(
          plugin_path, &info)) {
    DCHECK(false);
    return NULL;
  }

  // This plugin isn't loaded by any plugin process, so create a new process.
  plugin_host = new PluginProcessHost();
  if (!plugin_host->Init(info, ui_locale_)) {
    DCHECK(false);  // Init is not expected to fail
    delete plugin_host;
    return NULL;
  }

  return plugin_host;
}

void PluginService::OpenChannelToPlugin(
    ResourceMessageFilter* renderer_msg_filter,
    const GURL& url,
    const std::string& mime_type,
    const std::wstring& locale,
    IPC::Message* reply_msg) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  // We don't need a policy URL here because that was already checked by a
  // previous call to GetPluginPath.
  GURL policy_url;
  FilePath plugin_path = GetPluginPath(url, policy_url, mime_type, NULL);
  PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path);
  if (plugin_host) {
    plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg);
  } else {
    PluginProcessHost::ReplyToRenderer(
        renderer_msg_filter, IPC::ChannelHandle(), WebPluginInfo(), reply_msg);
  }
}

FilePath PluginService::GetPluginPath(const GURL& url,
                                      const GURL& policy_url,
                                      const std::string& mime_type,
                                      std::string* actual_mime_type) {
  bool allow_wildcard = true;
  WebPluginInfo info;
  if (NPAPI::PluginList::Singleton()->GetPluginInfo(
          url, mime_type, allow_wildcard, &info, actual_mime_type) &&
      PluginAllowedForURL(info.path, policy_url)) {
    return info.path;
  }

  return FilePath();
}

static void PurgePluginListCache(bool reload_pages) {
  for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
       !it.IsAtEnd(); it.Advance()) {
    it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
  }
}

void PluginService::OnWaitableEventSignaled(
    base::WaitableEvent* waitable_event) {
#if defined(OS_WIN)
  if (waitable_event == hkcu_event_.get()) {
    hkcu_key_.StartWatching();
  } else {
    hklm_key_.StartWatching();
  }

  NPAPI::PluginList::Singleton()->RefreshPlugins();
  PurgePluginListCache(true);
#endif  // defined(OS_WIN)
}

static void ForceShutdownPlugin(const FilePath& plugin_path) {
  PluginProcessHost* plugin =
      PluginService::GetInstance()->FindPluginProcess(plugin_path);
  if (plugin)
    plugin->ForceShutdown();
}

void PluginService::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_LOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_[plugin.path] = extension->url();
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                               NewRunnableFunction(&ForceShutdownPlugin,
                                                   plugin.path));
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->RemoveExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_.erase(plugin.path);
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

#if defined(OS_MACOSX)
    case NotificationType::APP_ACTIVATED: {
      ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                             NewRunnableFunction(&NotifyPluginsOfActivation));
      break;
    }
#endif

    default:
      DCHECK(false);
  }
}

bool PluginService::PluginAllowedForURL(const FilePath& plugin_path,
                                        const GURL& url) {
  if (url.is_empty())
    return true;  // Caller wants all plugins.

  PrivatePluginMap::iterator it = private_plugins_.find(plugin_path);
  if (it == private_plugins_.end())
    return true;  // This plugin is not private, so it's allowed everywhere.

  // We do a dumb compare of scheme and host, rather than using the domain
  // service, since we only care about this for extensions.
  const GURL& required_url = it->second;
  return (url.scheme() == required_url.scheme() &&
          url.host() == required_url.host());
}
<commit_msg>Do case-insensitive checks for the plugin paths in case a user has different shortcuts to the Chrome binary. Review URL: http://codereview.chromium.org/2155004<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/plugin_service.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/values.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_plugin_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/gpu_plugin.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#ifndef DISABLE_NACL
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#endif
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_MACOSX)
static void NotifyPluginsOfActivation() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    plugin->OnAppActivation();
  }
}
#endif

// static
bool PluginService::enable_chrome_plugins_ = true;
bool PluginService::enable_internal_pdf_ = false;

// static
void PluginService::InitGlobalInstance(Profile* profile) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  bool update_internal_dir = false;
  FilePath last_internal_dir =
      profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
  FilePath cur_internal_dir;
  if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
      cur_internal_dir != last_internal_dir) {
    update_internal_dir = true;
    profile->GetPrefs()->SetFilePath(
        prefs::kPluginsLastInternalDirectory, cur_internal_dir);
  }

  bool found_internal_pdf = false;
  bool force_enable_internal_pdf = false;
  FilePath pdf_path;
  PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
  FilePath::StringType pdf_path_str = pdf_path.value();
  if (enable_internal_pdf_ &&
      !profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
    // We switched to the internal pdf plugin being on by default, and so we
    // need to force it to be enabled.  We only want to do it this once though,
    // i.e. we don't want to enable it again if the user disables it afterwards.
    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
    force_enable_internal_pdf = true;
  }

  // Disable plugins listed as disabled in prefs.
  if (ListValue* saved_plugins_list =
          profile->GetPrefs()->GetMutableList(prefs::kPluginsPluginsList)) {
    for (ListValue::const_iterator it = saved_plugins_list->begin();
         it != saved_plugins_list->end();
         ++it) {
      if (!(*it)->IsType(Value::TYPE_DICTIONARY)) {
        LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
        continue;  // Oops, don't know what to do with this item.
      }

      DictionaryValue* plugin = static_cast<DictionaryValue*>(*it);
      FilePath::StringType path;
      if (!plugin->GetString(L"path", &path))
        continue;

      bool enabled = true;
      plugin->GetBoolean(L"enabled", &enabled);

      if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) {
        found_internal_pdf = true;
        if (!enabled && force_enable_internal_pdf) {
          enabled = true;
          plugin->SetBoolean(L"enabled", true);
        }
      }

      FilePath plugin_path(path);
      if (update_internal_dir &&
          FilePath::CompareIgnoreCase(plugin_path.DirName().value(),
              last_internal_dir.value()) == 0) {
        // If the internal plugin directory has changed and if the plugin looks
        // internal, update its path in the prefs.
        plugin_path = cur_internal_dir.Append(plugin_path.BaseName());
        plugin->SetString(L"path", plugin_path.value());
      }

      if (!enabled)
        NPAPI::PluginList::Singleton()->DisablePlugin(plugin_path);
    }
  }

  if (!enable_internal_pdf_ && !found_internal_pdf) {
    // The internal PDF plugin is disabled by default, and the user hasn't
    // overridden the default.
    NPAPI::PluginList::Singleton()->DisablePlugin(pdf_path);
  }

  // Have Chrome plugins write their data to the profile directory.
  GetInstance()->SetChromePluginDataDir(profile->GetPath());
}

// static
PluginService* PluginService::GetInstance() {
  return Singleton<PluginService>::get();
}

// static
void PluginService::EnableChromePlugins(bool enable) {
  enable_chrome_plugins_ = enable;
}

PluginService::PluginService()
    : main_message_loop_(MessageLoop::current()),
      resource_dispatcher_host_(NULL),
      ui_locale_(ASCIIToWide(g_browser_process->GetApplicationLocale())) {
  // Have the NPAPI plugin list search for Chrome plugins as well.
  ChromePluginLib::RegisterPluginsWithNPAPI();
  // Load the one specified on the command line as well.
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
  if (!path.empty())
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);

  // Register the internal Flash and PDF, if available.
  if (!CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableInternalFlash) &&
      PathService::Get(chrome::FILE_FLASH_PLUGIN, &path)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
  }

  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path))
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);

#ifndef DISABLE_NACL
  if (command_line->HasSwitch(switches::kInternalNaCl))
    RegisterInternalNaClPlugin();
#endif

  chrome::RegisterInternalGPUPlugin();

#if defined(OS_WIN)
  hkcu_key_.Create(
      HKEY_CURRENT_USER, kRegistryMozillaPlugins, KEY_NOTIFY);
  hklm_key_.Create(
      HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins, KEY_NOTIFY);
  if (hkcu_key_.StartWatching()) {
    hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
    hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
  }

  if (hklm_key_.StartWatching()) {
    hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
    hklm_watcher_.StartWatching(hklm_event_.get(), this);
  }
#elif defined(OS_POSIX) && !defined(OS_MACOSX)
  // Also find plugins in a user-specific plugins dir,
  // e.g. ~/.config/chromium/Plugins.
  FilePath user_data_dir;
  if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginDir(
        user_data_dir.Append("Plugins"));
  }
#endif

  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
#if defined(OS_MACOSX)
  // We need to know when the browser comes forward so we can bring modal plugin
  // windows forward too.
  registrar_.Add(this, NotificationType::APP_ACTIVATED,
                 NotificationService::AllSources());
#endif
}

PluginService::~PluginService() {
#if defined(OS_WIN)
  // Release the events since they're owned by RegKey, not WaitableEvent.
  hkcu_watcher_.StopWatching();
  hklm_watcher_.StopWatching();
  hkcu_event_->Release();
  hklm_event_->Release();
#endif
}

void PluginService::LoadChromePlugins(
    ResourceDispatcherHost* resource_dispatcher_host) {
  if (!enable_chrome_plugins_)
    return;

  resource_dispatcher_host_ = resource_dispatcher_host;
  ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
}

void PluginService::SetChromePluginDataDir(const FilePath& data_dir) {
  chrome_plugin_data_dir_ = data_dir;
}

const FilePath& PluginService::GetChromePluginDataDir() {
  return chrome_plugin_data_dir_;
}

const std::wstring& PluginService::GetUILocale() {
  return ui_locale_;
}

PluginProcessHost* PluginService::FindPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  if (plugin_path.value().empty()) {
    NOTREACHED() << "should only be called if we have a plugin to load";
    return NULL;
  }

  for (ChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    if (plugin->info().path == plugin_path)
      return plugin;
  }

  return NULL;
}

PluginProcessHost* PluginService::FindOrStartPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  PluginProcessHost *plugin_host = FindPluginProcess(plugin_path);
  if (plugin_host)
    return plugin_host;

  WebPluginInfo info;
  if (!NPAPI::PluginList::Singleton()->GetPluginInfoByPath(
          plugin_path, &info)) {
    DCHECK(false);
    return NULL;
  }

  // This plugin isn't loaded by any plugin process, so create a new process.
  plugin_host = new PluginProcessHost();
  if (!plugin_host->Init(info, ui_locale_)) {
    DCHECK(false);  // Init is not expected to fail
    delete plugin_host;
    return NULL;
  }

  return plugin_host;
}

void PluginService::OpenChannelToPlugin(
    ResourceMessageFilter* renderer_msg_filter,
    const GURL& url,
    const std::string& mime_type,
    const std::wstring& locale,
    IPC::Message* reply_msg) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  // We don't need a policy URL here because that was already checked by a
  // previous call to GetPluginPath.
  GURL policy_url;
  FilePath plugin_path = GetPluginPath(url, policy_url, mime_type, NULL);
  PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path);
  if (plugin_host) {
    plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg);
  } else {
    PluginProcessHost::ReplyToRenderer(
        renderer_msg_filter, IPC::ChannelHandle(), WebPluginInfo(), reply_msg);
  }
}

FilePath PluginService::GetPluginPath(const GURL& url,
                                      const GURL& policy_url,
                                      const std::string& mime_type,
                                      std::string* actual_mime_type) {
  bool allow_wildcard = true;
  WebPluginInfo info;
  if (NPAPI::PluginList::Singleton()->GetPluginInfo(
          url, mime_type, allow_wildcard, &info, actual_mime_type) &&
      PluginAllowedForURL(info.path, policy_url)) {
    return info.path;
  }

  return FilePath();
}

static void PurgePluginListCache(bool reload_pages) {
  for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
       !it.IsAtEnd(); it.Advance()) {
    it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
  }
}

void PluginService::OnWaitableEventSignaled(
    base::WaitableEvent* waitable_event) {
#if defined(OS_WIN)
  if (waitable_event == hkcu_event_.get()) {
    hkcu_key_.StartWatching();
  } else {
    hklm_key_.StartWatching();
  }

  NPAPI::PluginList::Singleton()->RefreshPlugins();
  PurgePluginListCache(true);
#endif  // defined(OS_WIN)
}

static void ForceShutdownPlugin(const FilePath& plugin_path) {
  PluginProcessHost* plugin =
      PluginService::GetInstance()->FindPluginProcess(plugin_path);
  if (plugin)
    plugin->ForceShutdown();
}

void PluginService::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_LOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_[plugin.path] = extension->url();
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                               NewRunnableFunction(&ForceShutdownPlugin,
                                                   plugin.path));
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->RemoveExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_.erase(plugin.path);
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

#if defined(OS_MACOSX)
    case NotificationType::APP_ACTIVATED: {
      ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                             NewRunnableFunction(&NotifyPluginsOfActivation));
      break;
    }
#endif

    default:
      DCHECK(false);
  }
}

bool PluginService::PluginAllowedForURL(const FilePath& plugin_path,
                                        const GURL& url) {
  if (url.is_empty())
    return true;  // Caller wants all plugins.

  PrivatePluginMap::iterator it = private_plugins_.find(plugin_path);
  if (it == private_plugins_.end())
    return true;  // This plugin is not private, so it's allowed everywhere.

  // We do a dumb compare of scheme and host, rather than using the domain
  // service, since we only care about this for extensions.
  const GURL& required_url = it->second;
  return (url.scheme() == required_url.scheme() &&
          url.host() == required_url.host());
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HTTP_REQUEST_LINE_HPP
#define HTTP_REQUEST_LINE_HPP

#include <cctype>
#include <regex>
#include "common.hpp"
#include "methods.hpp"
#include "version.hpp"

namespace http {

/**
 * @brief This class represents the {Request-Line}
 * of an HTTP request message
 */
class Request_Line {
public:
  //-----------------------------------
  // Constructor to create a default
  // request-line which is as follows:
  //
  // <GET / HTTP/1.1>
  //-----------------------------------
  explicit Request_Line() = default;

  //-----------------------------------
  // Constructor to construct a request-line
  // from the incoming character stream of
  // data which is a <std::string> object
  //
  // @tparam (std::string) request - The character stream of
  //                                 data
  //-----------------------------------
  template <typename Request>
  explicit Request_Line(Request&& request);

  // Copy / move constructors
  Request_Line(Request_Line&) = default;
  Request_Line(Request_Line&&) = default;
  ~Request_Line() noexcept = default;
  Request_Line& operator = (Request_Line&) = default;
  Request_Line& operator = (Request_Line&&) = default;

  //-----------------------------------
  // Get the method of the message
  //
  // @return - The method of the message
  //-----------------------------------
  const Method& get_method() const noexcept;

  //-----------------------------------
  // Set the method of the message
  //
  // @param method - The method of the message
  //-----------------------------------
  void set_method(const Method& method);

  //-----------------------------------
  // Get the URI of the message
  //
  // @return - The URI of the message
  //-----------------------------------
  const URI& get_uri() const noexcept;

  //-----------------------------------
  // Set the URI of the message
  //
  // @param uri - The URI of the message
  //-----------------------------------
  void set_uri(const URI& uri);

  //-----------------------------------
  // Get the version of the message
  //
  // @return - The version of the message
  //-----------------------------------
  const Version& get_version() const noexcept;

  //-----------------------------------
  // Set the version of the message
  //
  // @param version - The version of the message
  //-----------------------------------
  void set_version(const Version& version) noexcept;

  //-----------------------------------
  // Get a string representation of this
  // class
  //
  // @return - A string representation
  //-----------------------------------
  std::string to_string() const;

  //-----------------------------------
  // Operator to transform this class
  // into string form
  //-----------------------------------
  operator std::string () const;
  //-----------------------------------
private:
  //-----------------------------------
  // Class data members
  //-----------------------------------
  Method  method_  { GET };
  URI     uri_     {"/"};
  Version version_ {1U, 1U};
}; //< class Request_Line

  class Request_line_error : public std::runtime_error {
    using runtime_error::runtime_error;
  };

/**--v----------- Implementation Details -----------v--**/

template <typename Request>
inline Request_Line::Request_Line(Request&& request) {
  if (request.empty() or request.size() < 15 /*<-(15) minimum request length */) {
    throw Request_line_error("Invalid request line: " + request_line);
  }

  // Extract HTTP method
  std::string request_line;
  std::size_t index;

  if ((index = request.find("\r\n")) not_eq std::string::npos) {
    request_line = {request.substr(0, index)};
  } else if ((index = request.find('\n')) not_eq std::string::npos) {
    request_line = {request.substr(0, index)};
  } else {
    throw Request_line_error("Invalid line-ending");
  }

  // Should identify strings according to RFC 2616 sect.5.1
  // https://tools.ietf.org/html/rfc2616#section-5.1
  std::regex re_request_line {
    "\\s*(GET|POST|PUT|DELETE|OPTIONS|HEAD|TRACE|CONNECT) " // Method
      "(\\S+) " // URI
      "HTTP/(\\d+)\\.(\\d+)" // Version Major.Minor
      };

  std::smatch m;
  auto matched = std::regex_match(request_line,m, re_request_line);

  if (not matched)
    throw Request_line_error("Invalid request line: " + request_line);

  method_ = method::code(m[1]);
  //uri_ = URI {m[2]};
  new (&uri_) URI(m[2]);
  unsigned maj = static_cast<unsigned>(std::stoul(m[3]));
  unsigned min = static_cast<unsigned>(std::stoul(m[4]));
  version_ = Version{maj, min};

  // Trim the request for further processing
  request = request.substr(index + 2);
}

inline const Method& Request_Line::get_method() const noexcept {
  return method_;
}

inline void Request_Line::set_method(const Method& method) {
  method_ = method;
}

inline const URI& Request_Line::get_uri() const noexcept {
  return uri_;
}

inline void Request_Line::set_uri(const URI& uri) {
  //uri_ = uri;
  new (&uri_) URI(uri);
}

inline const Version& Request_Line::get_version() const noexcept {
  return version_;
}

inline void Request_Line::set_version(const Version& version) noexcept {
  version_ = version;
}

inline std::string Request_Line::to_string() const {
  return method::str(method_)+" "+uri_.to_string()+" "
    +version_.to_string();
}

inline Request_Line::operator std::string () const {
  std::ostringstream req_line;
  //-----------------------------
  req_line << method_  << " "
           << uri_     << " "
           << version_ << "\r\n";
 //------------------------------
  return req_line.str();
}

inline std::ostream& operator << (std::ostream& output_device, const Request_Line& req_line) {
  return output_device << req_line.to_string();
}

/**--^----------- Implementation Details -----------^--**/

} //< namespace http

#endif //< HTTP_REQUEST_LINE_HPP
<commit_msg>Changed Request_Line constructor API DOC<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HTTP_REQUEST_LINE_HPP
#define HTTP_REQUEST_LINE_HPP

#include <cctype>
#include <regex>
#include "common.hpp"
#include "methods.hpp"
#include "version.hpp"

namespace http {

/**
 * @brief This class represents the {Request-Line}
 * of an HTTP request message
 */
class Request_Line {
public:
  /**
   * @brief Default constructor
   */
  explicit Request_Line() = default;

  //-----------------------------------
  // Constructor to construct a request-line
  // from the incoming character stream of
  // data which is a <std::string> object
  //
  // @tparam (std::string) request - The character stream of
  //                                 data
  //-----------------------------------
  template <typename Request>
  explicit Request_Line(Request&& request);

  // Copy / move constructors
  Request_Line(Request_Line&) = default;
  Request_Line(Request_Line&&) = default;
  ~Request_Line() noexcept = default;
  Request_Line& operator = (Request_Line&) = default;
  Request_Line& operator = (Request_Line&&) = default;

  //-----------------------------------
  // Get the method of the message
  //
  // @return - The method of the message
  //-----------------------------------
  const Method& get_method() const noexcept;

  //-----------------------------------
  // Set the method of the message
  //
  // @param method - The method of the message
  //-----------------------------------
  void set_method(const Method& method);

  //-----------------------------------
  // Get the URI of the message
  //
  // @return - The URI of the message
  //-----------------------------------
  const URI& get_uri() const noexcept;

  //-----------------------------------
  // Set the URI of the message
  //
  // @param uri - The URI of the message
  //-----------------------------------
  void set_uri(const URI& uri);

  //-----------------------------------
  // Get the version of the message
  //
  // @return - The version of the message
  //-----------------------------------
  const Version& get_version() const noexcept;

  //-----------------------------------
  // Set the version of the message
  //
  // @param version - The version of the message
  //-----------------------------------
  void set_version(const Version& version) noexcept;

  //-----------------------------------
  // Get a string representation of this
  // class
  //
  // @return - A string representation
  //-----------------------------------
  std::string to_string() const;

  //-----------------------------------
  // Operator to transform this class
  // into string form
  //-----------------------------------
  operator std::string () const;
  //-----------------------------------
private:
  //-----------------------------------
  // Class data members
  //-----------------------------------
  Method  method_  { GET };
  URI     uri_     {"/"};
  Version version_ {1U, 1U};
}; //< class Request_Line

  class Request_line_error : public std::runtime_error {
    using runtime_error::runtime_error;
  };

/**--v----------- Implementation Details -----------v--**/

template <typename Request>
inline Request_Line::Request_Line(Request&& request) {
  if (request.empty() or request.size() < 15 /*<-(15) minimum request length */) {
    throw Request_line_error("Invalid request line: " + request_line);
  }

  // Extract HTTP method
  std::string request_line;
  std::size_t index;

  if ((index = request.find("\r\n")) not_eq std::string::npos) {
    request_line = {request.substr(0, index)};
  } else if ((index = request.find('\n')) not_eq std::string::npos) {
    request_line = {request.substr(0, index)};
  } else {
    throw Request_line_error("Invalid line-ending");
  }

  // Should identify strings according to RFC 2616 sect.5.1
  // https://tools.ietf.org/html/rfc2616#section-5.1
  std::regex re_request_line {
    "\\s*(GET|POST|PUT|DELETE|OPTIONS|HEAD|TRACE|CONNECT) " // Method
      "(\\S+) " // URI
      "HTTP/(\\d+)\\.(\\d+)" // Version Major.Minor
      };

  std::smatch m;
  auto matched = std::regex_match(request_line,m, re_request_line);

  if (not matched)
    throw Request_line_error("Invalid request line: " + request_line);

  method_ = method::code(m[1]);
  //uri_ = URI {m[2]};
  new (&uri_) URI(m[2]);
  unsigned maj = static_cast<unsigned>(std::stoul(m[3]));
  unsigned min = static_cast<unsigned>(std::stoul(m[4]));
  version_ = Version{maj, min};

  // Trim the request for further processing
  request = request.substr(index + 2);
}

inline const Method& Request_Line::get_method() const noexcept {
  return method_;
}

inline void Request_Line::set_method(const Method& method) {
  method_ = method;
}

inline const URI& Request_Line::get_uri() const noexcept {
  return uri_;
}

inline void Request_Line::set_uri(const URI& uri) {
  //uri_ = uri;
  new (&uri_) URI(uri);
}

inline const Version& Request_Line::get_version() const noexcept {
  return version_;
}

inline void Request_Line::set_version(const Version& version) noexcept {
  version_ = version;
}

inline std::string Request_Line::to_string() const {
  return method::str(method_)+" "+uri_.to_string()+" "
    +version_.to_string();
}

inline Request_Line::operator std::string () const {
  std::ostringstream req_line;
  //-----------------------------
  req_line << method_  << " "
           << uri_     << " "
           << version_ << "\r\n";
 //------------------------------
  return req_line.str();
}

inline std::ostream& operator << (std::ostream& output_device, const Request_Line& req_line) {
  return output_device << req_line.to_string();
}

/**--^----------- Implementation Details -----------^--**/

} //< namespace http

#endif //< HTTP_REQUEST_LINE_HPP
<|endoftext|>


<commit_before>#ifndef CELL_TYPES_INCLUDED //se l'header non è stato incluso
#define CELL_TYPES_INCLUDED

struct celldata{ //the final data struct
  float Ex, Ey; //double precision is wayyyy too much
  float P;
};

struct cellpos{ //the position in the simulation of the cell
  float x, y;
};

struct cell{
  cellpos* pos;
  celldata* data;
};

#endif //ending the if
<commit_msg>commenting<commit_after>#ifndef CELL_TYPES_INCLUDED //se l'header non è stato incluso
#define CELL_TYPES_INCLUDED

struct celldata{ //the final data struct
  float Ex, Ey; //double precision is wayyyy too much
  float P;
};

struct cellpos{ //the position in the simulation of the cell
  float x, y;
};

struct cell{ //it will be used for cicles too
  cellpos* pos;
  celldata* data;
};

#endif //ending the if
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <algorithm>    //For std::find_if
#include <iosfwd>     //For stream support

#include "cpp_utils/assert.hpp"

#include "tmp.hpp"
#include "evaluator.hpp"
#include "traits_lite.hpp"          //forward declaration of the traits
#include "compat.hpp"               //To make it work with g++

// CRTP classes
#include "crtp/inplace_assignable.hpp"
#include "crtp/comparable.hpp"
#include "crtp/value_testable.hpp"
#include "crtp/dim_testable.hpp"
#include "crtp/expression_able.hpp"

namespace etl {

namespace matrix_detail {

template<typename M, std::size_t I, typename Enable = void>
struct matrix_subsize : std::integral_constant<std::size_t, M::template dim<I+1>() * matrix_subsize<M, I+1>::value> {};

template<typename M, std::size_t I>
struct matrix_subsize<M, I, std::enable_if_t<I == M::n_dimensions - 1>> : std::integral_constant<std::size_t, 1> {};

template<typename M, std::size_t I, typename Enable = void>
struct matrix_leadingsize : std::integral_constant<std::size_t, M::template dim<I-1>() * matrix_leadingsize<M, I-1>::value> {};

template<typename M>
struct matrix_leadingsize<M, 0> : std::integral_constant<std::size_t, 1> {};

template<typename M, std::size_t I, typename S1>
inline constexpr std::size_t rm_compute_index(S1 first) noexcept {
    return first;
}

template<typename M, std::size_t I, typename S1, typename... S, cpp_enable_if((sizeof...(S) > 0))>
inline constexpr std::size_t rm_compute_index(S1 first, S... args) noexcept {
    return matrix_subsize<M, I>::value * first + rm_compute_index<M, I+1>(args...);
}

template<typename M, std::size_t I, typename S1>
inline constexpr std::size_t cm_compute_index(S1 first) noexcept {
    return matrix_leadingsize<M, I>::value * first;
}

template<typename M, std::size_t I, typename S1, typename... S, cpp_enable_if((sizeof...(S) > 0))>
inline constexpr std::size_t cm_compute_index(S1 first, S... args) noexcept {
    return matrix_leadingsize<M, I>::value * first + cm_compute_index<M, I+1>(args...);
}

template<typename M, std::size_t I, typename... S, cpp_enable_if(M::storage_order == order::RowMajor)>
inline constexpr std::size_t compute_index(S... args) noexcept {
    return rm_compute_index<M, I>(args...);
}

template<typename M, std::size_t I, typename... S, cpp_enable_if(M::storage_order == order::ColumnMajor)>
inline constexpr std::size_t compute_index(S... args) noexcept {
    return cm_compute_index<M, I>(args...);
}

template <typename N>
struct is_vector : std::false_type { };

template <typename N, typename A>
struct is_vector<std::vector<N, A>> : std::true_type { };

template <typename N>
struct is_vector<std::vector<N>> : std::true_type { };

} //end of namespace matrix_detail

template<typename T, typename ST, order SO, std::size_t... Dims>
struct fast_matrix_impl final :
        inplace_assignable<fast_matrix_impl<T, ST, SO, Dims...>>
        , comparable<fast_matrix_impl<T, ST, SO, Dims...>>
        , expression_able<fast_matrix_impl<T, ST, SO, Dims...>>
        , value_testable<fast_matrix_impl<T, ST, SO, Dims...>>
        , dim_testable<fast_matrix_impl<T, ST, SO, Dims...>>
        {
    static_assert(sizeof...(Dims) > 0, "At least one dimension must be specified");

public:
    static constexpr const std::size_t n_dimensions = sizeof...(Dims);
    static constexpr const std::size_t etl_size = mul_all<Dims...>::value;
    static constexpr const order storage_order = SO;
    static constexpr const bool array_impl = !matrix_detail::is_vector<ST>::value;

    using        value_type = T;
    using      storage_impl = ST;
    using          iterator = typename storage_impl::iterator;
    using    const_iterator = typename storage_impl::const_iterator;
    using         this_type = fast_matrix_impl<T, ST, SO, Dims...>;
    using       memory_type = value_type*;
    using const_memory_type = const value_type*;
    using          vec_type = intrinsic_type<T>;

private:
    storage_impl _data;

    template<typename... S>
    static constexpr std::size_t index(S... args){
        return matrix_detail::compute_index<this_type, 0>(args...);
    }

    template<typename... S>
    value_type& access(S... args){
        return _data[index(args...)];
    }

    template<typename... S>
    const value_type& access(S... args) const {
        return _data[index(args...)];
    }

public:

    ///{{{ Construction

    template<typename S = ST, cpp::enable_if_c<matrix_detail::is_vector<S>> = cpp::detail::dummy>
    void init(){
        _data.resize(etl_size);
    }

    template<typename S = ST, cpp::disable_if_c<matrix_detail::is_vector<S>> = cpp::detail::dummy>
    void init() noexcept {
        //Nothing to init
    }

    fast_matrix_impl() noexcept(array_impl) {
        init();
    }

    template<typename VT, cpp::enable_if_one_c<std::is_convertible<VT, value_type>, std::is_assignable<T&, VT>> = cpp::detail::dummy>
    explicit fast_matrix_impl(const VT& value){
        init();
        std::fill(_data.begin(), _data.end(), value);
    }

    fast_matrix_impl(std::initializer_list<value_type> l){
        init();

        cpp_assert(l.size() == size(), "Cannot copy from an initializer of different size");

        std::copy(l.begin(), l.end(), begin());
    }

    fast_matrix_impl(const fast_matrix_impl& rhs) noexcept(array_impl) {
        init();
        std::copy(rhs.begin(), rhs.end(), begin());
    }

    template<typename SST = ST, cpp_enable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl(fast_matrix_impl&& rhs) noexcept {
        _data = std::move(rhs._data);
    }

    template<typename SST = ST, cpp_disable_if(matrix_detail::is_vector<SST>::value)>
    explicit fast_matrix_impl(fast_matrix_impl&& rhs) noexcept {
        std::copy(rhs.begin(), rhs.end(), begin());
    }

    template<typename E, cpp_enable_if(std::is_convertible<value_t<E>, value_type>::value, is_copy_expr<E>::value)>
    explicit fast_matrix_impl(E&& e){
        init();
        validate_assign(*this, e);
        assign_evaluate(std::forward<E>(e), *this);
    }

    template<typename Container, cpp_enable_if(
            std::is_convertible<typename Container::value_type, value_type>::value,
            cpp::not_c<is_copy_expr<Container>>::value
        )>
    explicit fast_matrix_impl(const Container& vec){
        init();
        validate_assign(*this, vec);
        std::copy(vec.begin(), vec.end(), begin());
    }

    template<typename Generator>
    explicit fast_matrix_impl(generator_expr<Generator>&& e){
        init();
        validate_assign(*this, e);
        assign_evaluate(e, *this);
    }

    //}}}

    //{{{ Assignment

    //Copy assignment operator

    template<typename SST = ST, cpp_enable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(const fast_matrix_impl& rhs) noexcept {
        if(this != &rhs){
            _data = rhs._data;
        }
        return *this;
    }

    template<typename SST = ST, cpp_disable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(const fast_matrix_impl& rhs) noexcept {
        if(this != &rhs){
            std::copy(rhs.begin(), rhs.end(), begin());
        }
        return *this;
    }

    template<std::size_t... SDims>
    fast_matrix_impl& operator=(const fast_matrix_impl<T, ST, SO, SDims...>& rhs) noexcept {
        validate_assign(*this, rhs);
        _data = rhs._data;
        return *this;
    }

    //Allow copy from other containers

    template<typename Container, cpp::enable_if_c<std::is_convertible<typename Container::value_type, value_type>> = cpp::detail::dummy>
    fast_matrix_impl& operator=(const Container& vec) noexcept {
        validate_assign(*this, vec);
        std::copy(vec.begin(), vec.end(), begin());
        return *this;
    }

    //Construct from expression

    template<typename E, cpp_enable_if(std::is_convertible<typename E::value_type, value_type>::value && is_copy_expr<E>::value)>
    fast_matrix_impl& operator=(E&& e){
        validate_assign(*this, e);
        assign_evaluate(std::forward<E>(e), *this);
        return *this;
    }

    template<typename Generator>
    fast_matrix_impl& operator=(generator_expr<Generator>&& e){
        validate_assign(*this, e);
        assign_evaluate(e, *this);
        return *this;
    }

    //Set the same value to each element of the matrix
    template<typename VT, cpp::enable_if_one_c<std::is_convertible<VT, value_type>, std::is_assignable<T&, VT>> = cpp::detail::dummy>
    fast_matrix_impl& operator=(const VT& value) noexcept {
        std::fill(_data.begin(), _data.end(), value);

        return *this;
    }

    //Prohibit move

    template<typename SST = ST, cpp_enable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(fast_matrix_impl&& rhs){
        if(this != &rhs){
            _data = std::move(rhs._data);
        }
        return *this;
    }

    template<typename SST = ST, cpp_disable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(fast_matrix_impl&& rhs) = delete;

    //}}}

    //{{{ Swap operations

    void swap(fast_matrix_impl& other){
        using std::swap;
        swap(_data, other._data);
    }

    //}}}

    //{{{ Accessors

    static constexpr std::size_t size() noexcept {
        return etl_size;
    }

    static constexpr std::size_t rows() noexcept {
        return dim<0>();
    }

    static constexpr std::size_t columns() noexcept {
        static_assert(n_dimensions > 1, "columns() can only be used on 2D+ matrices");

        return dim<1>();
    }

    static constexpr std::size_t dimensions() noexcept {
        return n_dimensions;
    }

    template<std::size_t D>
    static constexpr std::size_t dim() noexcept {
        return nth_size<D, 0, Dims...>::value;
    }

    std::size_t dim(std::size_t d) const noexcept {
        return dyn_nth_size<Dims...>(d);
    }

    template<bool B = (n_dimensions > 1), cpp::enable_if_u<B> = cpp::detail::dummy>
    auto operator()(std::size_t i) noexcept {
        return sub(*this, i);
    }

    template<bool B = (n_dimensions > 1), cpp::enable_if_u<B> = cpp::detail::dummy>
    auto operator()(std::size_t i) const noexcept {
        return sub(*this, i);
    }

    template<typename... S>
    std::enable_if_t<sizeof...(S) == sizeof...(Dims), value_type&> operator()(S... args) noexcept {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return access(static_cast<std::size_t>(args)...);
    }

    template<typename... S>
    std::enable_if_t<sizeof...(S) == sizeof...(Dims), const value_type&> operator()(S... args) const noexcept {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return access(static_cast<std::size_t>(args)...);
    }

    const value_type& operator[](std::size_t i) const noexcept {
        cpp_assert(i < size(), "Out of bounds");

        return _data[i];
    }

    value_type& operator[](std::size_t i) noexcept {
        cpp_assert(i < size(), "Out of bounds");

        return _data[i];
    }

    vec_type load(std::size_t i) const noexcept {
        return vec::loadu(memory_start() + i);
    }

    iterator begin() noexcept(noexcept(_data.begin())) {
        return _data.begin();
    }

    iterator end() noexcept(noexcept(_data.end())) {
        return _data.end();
    }

    const_iterator begin() const noexcept(noexcept(_data.cbegin())) {
        return _data.cbegin();
    }

    const_iterator end() const noexcept(noexcept(_data.end())) {
        return _data.cend();
    }

    const_iterator cbegin() const noexcept(noexcept(_data.cbegin())) {
        return _data.cbegin();
    }

    const_iterator cend() const noexcept(noexcept(_data.end())) {
        return _data.cend();
    }

    //}}}

    //{{{ Direct memory access

    memory_type memory_start() noexcept {
        return &_data[0];
    }

    const_memory_type memory_start() const noexcept {
        return &_data[0];
    }

    memory_type memory_end() noexcept {
        return &_data[size()];
    }

    const_memory_type memory_end() const noexcept {
        return &_data[size()];
    }

    //}}}
};

template<typename T, typename ST, order SO, std::size_t... Dims>
void swap(fast_matrix_impl<T, ST, SO, Dims...>& lhs, fast_matrix_impl<T, ST, SO, Dims...>& rhs){
    lhs.swap(rhs);
}

template<typename T, typename ST, order SO, std::size_t... Dims>
std::ostream& operator<<(std::ostream& os, const fast_matrix_impl<T, ST, SO, Dims...>& /*matrix*/){
    if(sizeof...(Dims) == 1){
        return os << "V[" << concat_sizes(Dims...) << "]";
    } else {
        return os << "M[" << concat_sizes(Dims...) << "]";
    }
}

} //end of namespace etl
<commit_msg>Fixes<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <algorithm>    //For std::find_if
#include <iosfwd>     //For stream support

#include "cpp_utils/assert.hpp"

#include "tmp.hpp"
#include "evaluator.hpp"
#include "traits_lite.hpp"          //forward declaration of the traits
#include "compat.hpp"               //To make it work with g++

// CRTP classes
#include "crtp/inplace_assignable.hpp"
#include "crtp/comparable.hpp"
#include "crtp/value_testable.hpp"
#include "crtp/dim_testable.hpp"
#include "crtp/expression_able.hpp"

namespace etl {

namespace matrix_detail {

template<typename M, std::size_t I, typename Enable = void>
struct matrix_subsize : std::integral_constant<std::size_t, M::template dim<I+1>() * matrix_subsize<M, I+1>::value> {};

template<typename M, std::size_t I>
struct matrix_subsize<M, I, std::enable_if_t<I == M::n_dimensions - 1>> : std::integral_constant<std::size_t, 1> {};

template<typename M, std::size_t I, typename Enable = void>
struct matrix_leadingsize : std::integral_constant<std::size_t, M::template dim<I-1>() * matrix_leadingsize<M, I-1>::value> {};

template<typename M>
struct matrix_leadingsize<M, 0> : std::integral_constant<std::size_t, 1> {};

template<typename M, std::size_t I, typename S1>
inline constexpr std::size_t rm_compute_index(S1 first) noexcept {
    return first;
}

template<typename M, std::size_t I, typename S1, typename... S, cpp_enable_if((sizeof...(S) > 0))>
inline constexpr std::size_t rm_compute_index(S1 first, S... args) noexcept {
    return matrix_subsize<M, I>::value * first + rm_compute_index<M, I+1>(args...);
}

template<typename M, std::size_t I, typename S1>
inline constexpr std::size_t cm_compute_index(S1 first) noexcept {
    return matrix_leadingsize<M, I>::value * first;
}

template<typename M, std::size_t I, typename S1, typename... S, cpp_enable_if((sizeof...(S) > 0))>
inline constexpr std::size_t cm_compute_index(S1 first, S... args) noexcept {
    return matrix_leadingsize<M, I>::value * first + cm_compute_index<M, I+1>(args...);
}

template<typename M, std::size_t I, typename... S, cpp_enable_if(M::storage_order == order::RowMajor)>
inline constexpr std::size_t compute_index(S... args) noexcept {
    return rm_compute_index<M, I>(args...);
}

template<typename M, std::size_t I, typename... S, cpp_enable_if(M::storage_order == order::ColumnMajor)>
inline constexpr std::size_t compute_index(S... args) noexcept {
    return cm_compute_index<M, I>(args...);
}

template <typename N>
struct is_vector : std::false_type { };

template <typename N, typename A>
struct is_vector<std::vector<N, A>> : std::true_type { };

template <typename N>
struct is_vector<std::vector<N>> : std::true_type { };

} //end of namespace matrix_detail

template<typename T, typename ST, order SO, std::size_t... Dims>
struct fast_matrix_impl final :
        inplace_assignable<fast_matrix_impl<T, ST, SO, Dims...>>
        , comparable<fast_matrix_impl<T, ST, SO, Dims...>>
        , expression_able<fast_matrix_impl<T, ST, SO, Dims...>>
        , value_testable<fast_matrix_impl<T, ST, SO, Dims...>>
        , dim_testable<fast_matrix_impl<T, ST, SO, Dims...>>
        {
    static_assert(sizeof...(Dims) > 0, "At least one dimension must be specified");

public:
    static constexpr const std::size_t n_dimensions = sizeof...(Dims);
    static constexpr const std::size_t etl_size = mul_all<Dims...>::value;
    static constexpr const order storage_order = SO;
    static constexpr const bool array_impl = !matrix_detail::is_vector<ST>::value;

    using        value_type = T;
    using      storage_impl = ST;
    using          iterator = typename storage_impl::iterator;
    using    const_iterator = typename storage_impl::const_iterator;
    using         this_type = fast_matrix_impl<T, ST, SO, Dims...>;
    using       memory_type = value_type*;
    using const_memory_type = const value_type*;
    using          vec_type = intrinsic_type<T>;

private:
    storage_impl _data;

    template<typename... S>
    static constexpr std::size_t index(S... args){
        return matrix_detail::compute_index<this_type, 0>(args...);
    }

    template<typename... S>
    value_type& access(S... args){
        return _data[index(args...)];
    }

    template<typename... S>
    const value_type& access(S... args) const {
        return _data[index(args...)];
    }

public:

    ///{{{ Construction

    template<typename S = ST, cpp::enable_if_c<matrix_detail::is_vector<S>> = cpp::detail::dummy>
    void init(){
        _data.resize(etl_size);
    }

    template<typename S = ST, cpp::disable_if_c<matrix_detail::is_vector<S>> = cpp::detail::dummy>
    void init() noexcept {
        //Nothing to init
    }

    fast_matrix_impl() noexcept(array_impl) {
        init();
    }

    template<typename VT, cpp::enable_if_one_c<std::is_convertible<VT, value_type>, std::is_assignable<T&, VT>> = cpp::detail::dummy>
    explicit fast_matrix_impl(const VT& value){
        init();
        std::fill(_data.begin(), _data.end(), value);
    }

    fast_matrix_impl(std::initializer_list<value_type> l){
        init();

        cpp_assert(l.size() == size(), "Cannot copy from an initializer of different size");

        std::copy(l.begin(), l.end(), begin());
    }

    fast_matrix_impl(const fast_matrix_impl& rhs) noexcept(array_impl) {
        init();
        std::copy(rhs.begin(), rhs.end(), begin());
    }

    template<typename SST = ST, cpp_enable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl(fast_matrix_impl&& rhs) noexcept {
        _data = std::move(rhs._data);
    }

    template<typename SST = ST, cpp_disable_if(matrix_detail::is_vector<SST>::value)>
    explicit fast_matrix_impl(fast_matrix_impl&& rhs) noexcept {
        std::copy(rhs.begin(), rhs.end(), begin());
    }

    template<typename E, cpp_enable_if(std::is_convertible<value_t<E>, value_type>::value, is_copy_expr<E>::value)>
    explicit fast_matrix_impl(E&& e){
        init();
        validate_assign(*this, e);
        assign_evaluate(std::forward<E>(e), *this);
    }

    template<typename Container, cpp_enable_if(
            std::is_convertible<typename Container::value_type, value_type>::value,
            cpp::not_c<is_copy_expr<Container>>::value
        )>
    explicit fast_matrix_impl(const Container& vec){
        init();
        validate_assign(*this, vec);
        std::copy(vec.begin(), vec.end(), begin());
    }

    template<typename Generator>
    explicit fast_matrix_impl(generator_expr<Generator>&& e){
        init();
        validate_assign(*this, e);
        assign_evaluate(e, *this);
    }

    //}}}

    //{{{ Assignment

    //Copy assignment operator

    template<typename SST = ST, cpp_enable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(const fast_matrix_impl& rhs) noexcept {
        if(this != &rhs){
            _data = rhs._data;
        }
        return *this;
    }

    template<typename SST = ST, cpp_disable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(const fast_matrix_impl& rhs) noexcept {
        if(this != &rhs){
            std::copy(rhs.begin(), rhs.end(), begin());
        }
        return *this;
    }

    template<std::size_t... SDims>
    fast_matrix_impl& operator=(const fast_matrix_impl<T, ST, SO, SDims...>& rhs) noexcept {
        validate_assign(*this, rhs);
        std::copy(rhs.begin(), rhs.end(), begin());
        return *this;
    }

    //Allow copy from other containers

    template<typename Container, cpp::enable_if_c<std::is_convertible<typename Container::value_type, value_type>> = cpp::detail::dummy>
    fast_matrix_impl& operator=(const Container& vec) noexcept {
        validate_assign(*this, vec);
        std::copy(vec.begin(), vec.end(), begin());
        return *this;
    }

    //Construct from expression

    template<typename E, cpp_enable_if(std::is_convertible<typename E::value_type, value_type>::value && is_copy_expr<E>::value)>
    fast_matrix_impl& operator=(E&& e){
        validate_assign(*this, e);
        assign_evaluate(std::forward<E>(e), *this);
        return *this;
    }

    template<typename Generator>
    fast_matrix_impl& operator=(generator_expr<Generator>&& e){
        validate_assign(*this, e);
        assign_evaluate(e, *this);
        return *this;
    }

    //Set the same value to each element of the matrix
    template<typename VT, cpp::enable_if_one_c<std::is_convertible<VT, value_type>, std::is_assignable<T&, VT>> = cpp::detail::dummy>
    fast_matrix_impl& operator=(const VT& value) noexcept {
        std::fill(_data.begin(), _data.end(), value);

        return *this;
    }

    //Prohibit move

    template<typename SST = ST, cpp_enable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(fast_matrix_impl&& rhs){
        if(this != &rhs){
            _data = std::move(rhs._data);
        }
        return *this;
    }

    template<typename SST = ST, cpp_disable_if(matrix_detail::is_vector<SST>::value)>
    fast_matrix_impl& operator=(fast_matrix_impl&& rhs) = delete;

    //}}}

    //{{{ Swap operations

    void swap(fast_matrix_impl& other){
        using std::swap;
        swap(_data, other._data);
    }

    //}}}

    //{{{ Accessors

    static constexpr std::size_t size() noexcept {
        return etl_size;
    }

    static constexpr std::size_t rows() noexcept {
        return dim<0>();
    }

    static constexpr std::size_t columns() noexcept {
        static_assert(n_dimensions > 1, "columns() can only be used on 2D+ matrices");

        return dim<1>();
    }

    static constexpr std::size_t dimensions() noexcept {
        return n_dimensions;
    }

    template<std::size_t D>
    static constexpr std::size_t dim() noexcept {
        return nth_size<D, 0, Dims...>::value;
    }

    std::size_t dim(std::size_t d) const noexcept {
        return dyn_nth_size<Dims...>(d);
    }

    template<bool B = (n_dimensions > 1), cpp::enable_if_u<B> = cpp::detail::dummy>
    auto operator()(std::size_t i) noexcept {
        return sub(*this, i);
    }

    template<bool B = (n_dimensions > 1), cpp::enable_if_u<B> = cpp::detail::dummy>
    auto operator()(std::size_t i) const noexcept {
        return sub(*this, i);
    }

    template<typename... S>
    std::enable_if_t<sizeof...(S) == sizeof...(Dims), value_type&> operator()(S... args) noexcept {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return access(static_cast<std::size_t>(args)...);
    }

    template<typename... S>
    std::enable_if_t<sizeof...(S) == sizeof...(Dims), const value_type&> operator()(S... args) const noexcept {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return access(static_cast<std::size_t>(args)...);
    }

    const value_type& operator[](std::size_t i) const noexcept {
        cpp_assert(i < size(), "Out of bounds");

        return _data[i];
    }

    value_type& operator[](std::size_t i) noexcept {
        cpp_assert(i < size(), "Out of bounds");

        return _data[i];
    }

    vec_type load(std::size_t i) const noexcept {
        return vec::loadu(memory_start() + i);
    }

    iterator begin() noexcept(noexcept(_data.begin())) {
        return _data.begin();
    }

    iterator end() noexcept(noexcept(_data.end())) {
        return _data.end();
    }

    const_iterator begin() const noexcept(noexcept(_data.cbegin())) {
        return _data.cbegin();
    }

    const_iterator end() const noexcept(noexcept(_data.end())) {
        return _data.cend();
    }

    const_iterator cbegin() const noexcept(noexcept(_data.cbegin())) {
        return _data.cbegin();
    }

    const_iterator cend() const noexcept(noexcept(_data.end())) {
        return _data.cend();
    }

    //}}}

    //{{{ Direct memory access

    memory_type memory_start() noexcept {
        return &_data[0];
    }

    const_memory_type memory_start() const noexcept {
        return &_data[0];
    }

    memory_type memory_end() noexcept {
        return &_data[size()];
    }

    const_memory_type memory_end() const noexcept {
        return &_data[size()];
    }

    //}}}
};

template<typename T, typename ST, order SO, std::size_t... Dims>
void swap(fast_matrix_impl<T, ST, SO, Dims...>& lhs, fast_matrix_impl<T, ST, SO, Dims...>& rhs){
    lhs.swap(rhs);
}

template<typename T, typename ST, order SO, std::size_t... Dims>
std::ostream& operator<<(std::ostream& os, const fast_matrix_impl<T, ST, SO, Dims...>& /*matrix*/){
    if(sizeof...(Dims) == 1){
        return os << "V[" << concat_sizes(Dims...) << "]";
    } else {
        return os << "M[" << concat_sizes(Dims...) << "]";
    }
}

} //end of namespace etl
<|endoftext|>