<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qlandmarkabstractrequest.h"
#include "qlandmarkabstractrequest_p.h"
#include "qlandmarkmanagerengine.h"
#include "qlandmarkmanager_p.h"
#include <QDebug>
#include <QMutexLocker>

QTM_USE_NAMESPACE

QLandmarkAbstractRequestPrivate::QLandmarkAbstractRequestPrivate(QLandmarkManager *mgr)
    : type(QLandmarkAbstractRequest::InvalidRequest),
      state(QLandmarkAbstractRequest::InactiveState),
      error(QLandmarkManager::NoError),
      errorString(QString()),
      manager(mgr)
{
}

/*!
    \class QLandmarkAbstractRequest
    \brief The QLandmarkAbstractRequest class provides the interface
    from which all asynchronous request classes inherit.

    \inmodule QtLocation

    \ingroup landmarks-request

    It allows a client to asynchronously request some functionality of a
    particular QLandmarkManager. Instances of the class will emit signals when
    the state of the request changes, or when more results become available.

    Clients should not attempt to create instances of this class directly, but
    should instead use the use-case-specific classes derived from this class.

    All such request classes have a similar interface: clients set the
    parameters of the asynchronous call, then call the start() slot of the request. The manager
    will then enqueue or begin to process the request, at which point the
    request's state will transition from the \c InactiveState to \c ActiveState.
    After any state transition, the request will emit the stateChanged()
    signal. The manager may (if it supports it)
    periodically update the request with results, at
    which point the request will emit the resultsAvailable() signal. These
    results are not guaranteed to have a stable ordering. Error information is
    considered a result, so some requests will emit the resultsAvailable()
    signal even if no results are possible from the request (for example, a
    landmark remove request) when the manager updates the request with
    information about any errors which may have occurred.

    Clients can choose which signals they wish to handle from a request. If the
    client is not interested in interim results, they can choose to handle only
    the stateChanged() signal, and in the slot to which that signal is
    connected, check whether the state has changed to the \c FinishedState
    (which signifies that the manager has finished handling the request, and
    that the request will not be updated with any more results).  If the client
    is not interested in any results (including error information), they may
    choose to delete the request after calling \l start(), or simply may not
    connect the the request's signals to any slots.  (Please see the note
    below if you are working on Symbian with QtMobility 1.1.0)

    If the request is allocated via operator new, the client must delete the
    request when they are no longer using it in order to avoid leaking memory.
    That is, the client retains ownership of the request.

    The client may delete a heap-allocated request in various ways: by deleting
    it directly (but not within a slot connected to a signal emitted by the
    request), or by using the deleteLater() slot to schedule the request for
    deletion when control returns to the event loop (from within a slot
    connected to a signal emitted by the request, for example \l
    stateChanged()).

    An active request may be deleted by the client, but the client will
    not receive notifications about whether the request succeeded or not,
    nor the results of the request.

    Because clients retain ownership of any request object, and may delete a
    request object at any time, the manager engine,  implementers must be
    careful to ensue that they do not assume that a request has not been
    deleted at some time point during processing of a request, particularly
    if the engine has a multithreaded implementation.
*/

QLandmarkAbstractRequestPrivate::~QLandmarkAbstractRequestPrivate()
{
}

void QLandmarkAbstractRequestPrivate::notifyEngine(QLandmarkAbstractRequest* request)
{
        Q_ASSERT(request);
        QLandmarkAbstractRequestPrivate* d = request->d_ptr;
        if (d) {
            QMutexLocker ml(&d->mutex);
            QLandmarkManagerEngine *engine = QLandmarkManagerPrivate::getEngine(d->manager);
            ml.unlock();
            if (engine) {
                engine->requestDestroyed(request);
            }
        }
}

/*!
    \enum QLandmarkAbstractRequest::RequestType
    Defines the possible types of asynchronous requests.
    \value  InvalidRequest An invalid request
    \value  LandmarkIdFetchRequest A request to fetch a list of landmark
            identifiers.
    \value  CategoryIdFetchRequest A request to fetch a list of catgory
            identifiers.

    \value  LandmarkFetchRequest A request to fetch a list of landmarks
    \value  LandmarkFetchByIdRequest A request to fetch a list of landmarks by id.
    \value  CategoryFetchRequest A request to fetch a list of categories
    \value  CategoryFetchByIdRequest A request to fetch a list of categories by id
    \value  LandmarkSaveRequest A request to save a list of landmarks.
    \value  LandmarkRemoveRequest A request to remove a list of landmarks.
    \value  CategorySaveRequest A request to save a list of categories.
    \value  CategoryRemoveRequest A request to remove a list of categories.
    \value  ImportRequest A request import landmarks.
    \value  ExportRequest A request export landmarks.
*/

/*!
    \enum QLandmarkAbstractRequest::State
    Defines the possible states of asynchronous requests.
    \value  InactiveState Operation not yet started.
    \value  ActiveState Operation started, not yet finished.
    \value  FinishedState Operation completed.  (Can be mean either successful or
            unsuccessful completion).
*/

/*!
    Constructs a new, invalid asynchronous request with the given \a manager and \a parent.
*/
QLandmarkAbstractRequest::QLandmarkAbstractRequest(QLandmarkManager *manager, QObject *parent)
    : QObject(parent),
      d_ptr(new QLandmarkAbstractRequestPrivate(manager))
{
}

/*!
    \internal
*/
QLandmarkAbstractRequest::QLandmarkAbstractRequest(QLandmarkAbstractRequestPrivate *dd, QObject *parent)
    : QObject(parent),
     d_ptr(dd)
{
}

/*!
    Destroys the asynchronous request.  Because the request object is effectiely a handle to a
    request operation, the operation may continue or it may just be canceled, depending upon
    the enine implementation, even though the request itself has been destroyed.
    The sqlite engine continues the operation behind the scenes if the
    request is destroyed whilst active.  For the symbian engine see the note below.
*/
QLandmarkAbstractRequest::~QLandmarkAbstractRequest()
{
    QLandmarkAbstractRequestPrivate::notifyEngine(this);
    delete d_ptr;
}

/*!
    Returns the type of this asynchronous request.
*/
QLandmarkAbstractRequest::RequestType QLandmarkAbstractRequest::type() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->type;
}

/*!
    Returns the state of the request
*/
QLandmarkAbstractRequest::State QLandmarkAbstractRequest::state()
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state;
}

/*!
    Returns true if the request is in the \c QLandmarkAbstractRequest::Inactive state;
    otherwise, returns false.
    \sa state()
*/
bool QLandmarkAbstractRequest::isInactive() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state == QLandmarkAbstractRequest::InactiveState;
}

/*!
    Returns true if the request is in the \c QLandmarkAbstractRequest::Active state;
    otherwise, returns false.
    \sa state()
*/
bool QLandmarkAbstractRequest::isActive() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state == QLandmarkAbstractRequest::ActiveState;
}

/*!
    Returns true if the request is in the \c QLandmarkAbstractRequest::Finished state;
    otherwise, returns false.
    \sa state()
*/
bool QLandmarkAbstractRequest::isFinished() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state == QLandmarkAbstractRequest::FinishedState;
}

/*!
    Returns the overall error of the most recent asynchronous operation.
    \sa errorString()
*/
QLandmarkManager::Error QLandmarkAbstractRequest::error() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->error;
}

/*!
    Returns a human readable string of the last error
    that occurred.  This error string is intended to be used
    by developers only and should not be seen by end users.
    \sa error()
*/
QString QLandmarkAbstractRequest::errorString() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->errorString;
}

/*!
    Returns a pointer to the landmark manager which
    this request operates on.
*/
QLandmarkManager *QLandmarkAbstractRequest::manager() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->manager;
}

/*!
    Sets the \a manager which this request operates on.

    Note that if a NULL manager is set, the functions
    start(), cancel() and waitForFinished() will return false and
    error will be set to QLandmarkManager::InvalidManagerError.

    A manager cannot be assigned while the request is in the
    QLandmarkAbstractRequest::ActiveState.
*/
void QLandmarkAbstractRequest::setManager(QLandmarkManager *manager)
{
    QMutexLocker ml(&d_ptr->mutex);
    if (d_ptr->state == QLandmarkAbstractRequest::ActiveState && d_ptr->manager)
        return;
    d_ptr->manager = manager;
}

/*!
    Attempts to start the request.

    Returns true if the request was started, otherwise false. Trying to start a
    request that is already active returns false.
    \sa cancel().
*/
bool QLandmarkAbstractRequest::start()
{
    QMutexLocker ml(&d_ptr->mutex);
    if (!d_ptr->manager) {
        d_ptr->error = QLandmarkManager::BadArgumentError;
        d_ptr->errorString = "No manager assigned to landmark request object";
        qWarning() << d_ptr->errorString;
        return false;
    }
    QLandmarkManagerEngine *engine = d_ptr->manager->engine();
    if (!engine) {
        d_ptr->error = QLandmarkManager::InvalidManagerError;
        d_ptr->errorString = "The manager is invalid";
        return false;
    }

    if (d_ptr->state != QLandmarkAbstractRequest::ActiveState) {
        ml.unlock();
        return engine->startRequest(this);
    }
     else {
        return false;
     }
}

/*!
    Notifies the request that it should be canceled.

    Returns true if the request was successfully notified
    that it should be canceled.  The request may or may not honor
    the cancel notification.  Returns false if the notification
    could not be made or the request is not in the
    QLandmarkManager::Active state.

    \sa start()
*/
bool QLandmarkAbstractRequest::cancel()
{
    QMutexLocker ml(&d_ptr->mutex);
    if (!d_ptr->manager) {
        d_ptr->error = QLandmarkManager::BadArgumentError;
        d_ptr->errorString = "No manager assigned to landmark request object";
        qWarning() << d_ptr->errorString;
        return false;
    }
    QLandmarkManagerEngine *engine = d_ptr->manager->engine();

    if(d_ptr->state == QLandmarkAbstractRequest::ActiveState) {
        ml.unlock();
        return engine->cancelRequest(this);
    }
    else
        return false;
}

/*!
    Blocks until the request has been completed or until \a msecs milliseconds
    has elapsed.  If \a msecs is zero or negative, this function will block indefinitely.

    Returns true if the request was canceled or completed
    within the given period, otherwise returns false.  Some backends may be unable
    to support this  operation safely and will return false immediately.
    The sqlite and sparql managers currently do not support waitForFinished(),
    while the symbian manager does (with the exception of an import request,
    which will always return false on symbian when waitForFinished() is called).

    Note that any signals generated while waiting for the request to be complete
    may be queued and delivered sometime after this function has returned, when
    the calling thread's event loop is dispatched.  If your code depends on
    your slots being invoked, you may need to process events after calling
    this function.
*/
bool QLandmarkAbstractRequest::waitForFinished(int msecs)
{

    QMutexLocker ml(&d_ptr->mutex);
    if (!d_ptr->manager) {
        d_ptr->error = QLandmarkManager::BadArgumentError;
        d_ptr->errorString = "No manager assigned to landmark request object";
        qWarning() << d_ptr->errorString;
        return false;
    }
    QLandmarkManagerEngine *engine = d_ptr->manager->engine();

    switch(d_ptr->state) {
        case QLandmarkAbstractRequest::ActiveState:
            ml.unlock();
            return engine->waitForRequestFinished(this, msecs);
        case QLandmarkAbstractRequest::FinishedState:
            return true;
        default:
            return false;
    }
    return false;
}

/*!
  \fn void QLandmarkAbstractRequest::resultsAvailable()
  This signal is emitted when new results are available.  Results
  can include the operation error which may be accessed via error(),
  or derived-class specific results which are accessible through
  the derived class API.

  \sa error()
*/

/*!
    \fn void QLandmarkAbstractRequest::stateChanged(QLandmarkAbstractRequest::State newState)
    This signal is emitted when the state of the request is changed.  The new state of
    the request will be contained in \a newState.
*/

#include "moc_qlandmarkabstractrequest.cpp"

<commit_msg>doc update<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qlandmarkabstractrequest.h"
#include "qlandmarkabstractrequest_p.h"
#include "qlandmarkmanagerengine.h"
#include "qlandmarkmanager_p.h"
#include <QDebug>
#include <QMutexLocker>

QTM_USE_NAMESPACE

QLandmarkAbstractRequestPrivate::QLandmarkAbstractRequestPrivate(QLandmarkManager *mgr)
    : type(QLandmarkAbstractRequest::InvalidRequest),
      state(QLandmarkAbstractRequest::InactiveState),
      error(QLandmarkManager::NoError),
      errorString(QString()),
      manager(mgr)
{
}

/*!
    \class QLandmarkAbstractRequest
    \brief The QLandmarkAbstractRequest class provides the interface
    from which all asynchronous request classes inherit.

    \inmodule QtLocation

    \ingroup landmarks-request

    It allows a client to asynchronously request some functionality of a
    particular QLandmarkManager. Instances of the class will emit signals when
    the state of the request changes, or when more results become available.

    Clients should not attempt to create instances of this class directly, but
    should instead use the use-case-specific classes derived from this class.

    All such request classes have a similar interface: clients set the
    parameters of the asynchronous call, then call the start() slot of the request. The manager
    will then enqueue or begin to process the request, at which point the
    request's state will transition from the \c InactiveState to \c ActiveState.
    After any state transition, the request will emit the stateChanged()
    signal. The manager may (if it supports it)
    periodically update the request with results, at
    which point the request will emit the resultsAvailable() signal. These
    results are not guaranteed to have a stable ordering. Error information is
    considered a result, so some requests will emit the resultsAvailable()
    signal even if no results are possible from the request (for example, a
    landmark remove request) when the manager updates the request with
    information about any errors which may have occurred.

    Clients can choose which signals they wish to handle from a request. If the
    client is not interested in interim results, they can choose to handle only
    the stateChanged() signal, and in the slot to which that signal is
    connected, check whether the state has changed to the \c FinishedState
    (which signifies that the manager has finished handling the request, and
    that the request will not be updated with any more results).  If the client
    is not interested in any results (including error information), they may
    choose to delete the request after calling \l start(), or simply may not
    connect the the request's signals to any slots.  (Please see the note
    below if you are working on Symbian with QtMobility 1.1.0)

    If the request is allocated via operator new, the client must delete the
    request when they are no longer using it in order to avoid leaking memory.
    That is, the client retains ownership of the request.

    The client may delete a heap-allocated request in various ways: by deleting
    it directly (but not within a slot connected to a signal emitted by the
    request), or by using the deleteLater() slot to schedule the request for
    deletion when control returns to the event loop (from within a slot
    connected to a signal emitted by the request, for example \l
    stateChanged()).

    An active request may be deleted by the client, but the client will
    not receive notifications about whether the request succeeded or not,
    nor the results of the request.

    Because clients retain ownership of any request object, and may delete a
    request object at any time, the manager engine,  implementers must be
    careful to ensue that they do not assume that a request has not been
    deleted at some time point during processing of a request, particularly
    if the engine has a multithreaded implementation.
*/

QLandmarkAbstractRequestPrivate::~QLandmarkAbstractRequestPrivate()
{
}

void QLandmarkAbstractRequestPrivate::notifyEngine(QLandmarkAbstractRequest* request)
{
        Q_ASSERT(request);
        QLandmarkAbstractRequestPrivate* d = request->d_ptr;
        if (d) {
            QMutexLocker ml(&d->mutex);
            QLandmarkManagerEngine *engine = QLandmarkManagerPrivate::getEngine(d->manager);
            ml.unlock();
            if (engine) {
                engine->requestDestroyed(request);
            }
        }
}

/*!
    \enum QLandmarkAbstractRequest::RequestType
    Defines the possible types of asynchronous requests.
    \value  InvalidRequest An invalid request
    \value  LandmarkIdFetchRequest A request to fetch a list of landmark
            identifiers.
    \value  CategoryIdFetchRequest A request to fetch a list of catgory
            identifiers.

    \value  LandmarkFetchRequest A request to fetch a list of landmarks
    \value  LandmarkFetchByIdRequest A request to fetch a list of landmarks by id.
    \value  CategoryFetchRequest A request to fetch a list of categories
    \value  CategoryFetchByIdRequest A request to fetch a list of categories by id
    \value  LandmarkSaveRequest A request to save a list of landmarks.
    \value  LandmarkRemoveRequest A request to remove a list of landmarks.
    \value  CategorySaveRequest A request to save a list of categories.
    \value  CategoryRemoveRequest A request to remove a list of categories.
    \value  ImportRequest A request import landmarks.
    \value  ExportRequest A request export landmarks.
*/

/*!
    \enum QLandmarkAbstractRequest::State
    Defines the possible states of asynchronous requests.
    \value  InactiveState Operation not yet started.
    \value  ActiveState Operation started, not yet finished.
    \value  FinishedState Operation completed.  (Can be mean either successful or
            unsuccessful completion).
*/

/*!
    Constructs a new, invalid asynchronous request with the given \a manager and \a parent.
*/
QLandmarkAbstractRequest::QLandmarkAbstractRequest(QLandmarkManager *manager, QObject *parent)
    : QObject(parent),
      d_ptr(new QLandmarkAbstractRequestPrivate(manager))
{
}

/*!
    \internal
*/
QLandmarkAbstractRequest::QLandmarkAbstractRequest(QLandmarkAbstractRequestPrivate *dd, QObject *parent)
    : QObject(parent),
     d_ptr(dd)
{
}

/*!
    Destroys the asynchronous request.  Because the request object is effectiely a handle to a
    request operation, the operation may continue or it may just be canceled, depending upon
    the enine implementation, even though the request itself has been destroyed.
    The sqlite engine continues the operation behind the scenes if the
    request is destroyed whilst active.  For the symbian engine see the note below.
*/
QLandmarkAbstractRequest::~QLandmarkAbstractRequest()
{
    QLandmarkAbstractRequestPrivate::notifyEngine(this);
    delete d_ptr;
}

/*!
    Returns the type of this asynchronous request.
*/
QLandmarkAbstractRequest::RequestType QLandmarkAbstractRequest::type() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->type;
}

/*!
    Returns the state of the request
*/
QLandmarkAbstractRequest::State QLandmarkAbstractRequest::state()
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state;
}

/*!
    Returns true if the request is in the \c QLandmarkAbstractRequest::Inactive state;
    otherwise, returns false.
    \sa state()
*/
bool QLandmarkAbstractRequest::isInactive() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state == QLandmarkAbstractRequest::InactiveState;
}

/*!
    Returns true if the request is in the \c QLandmarkAbstractRequest::Active state;
    otherwise, returns false.
    \sa state()
*/
bool QLandmarkAbstractRequest::isActive() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state == QLandmarkAbstractRequest::ActiveState;
}

/*!
    Returns true if the request is in the \c QLandmarkAbstractRequest::Finished state;
    otherwise, returns false.
    \sa state()
*/
bool QLandmarkAbstractRequest::isFinished() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->state == QLandmarkAbstractRequest::FinishedState;
}

/*!
    Returns the overall error of the most recent asynchronous operation.
    \sa errorString()
*/
QLandmarkManager::Error QLandmarkAbstractRequest::error() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->error;
}

/*!
    Returns a human readable string of the last error
    that occurred.  This error string is intended to be used
    by developers only and should not be seen by end users.
    \sa error()
*/
QString QLandmarkAbstractRequest::errorString() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->errorString;
}

/*!
    Returns a pointer to the landmark manager which
    this request operates on.
*/
QLandmarkManager *QLandmarkAbstractRequest::manager() const
{
    QMutexLocker ml(&d_ptr->mutex);
    return d_ptr->manager;
}

/*!
    Sets the \a manager which this request operates on.

    Note that if a NULL manager is set, the functions
    start(), cancel() and waitForFinished() will return false and
    error will be set to QLandmarkManager::InvalidManagerError.

    A manager cannot be assigned while the request is in the
    QLandmarkAbstractRequest::ActiveState.
*/
void QLandmarkAbstractRequest::setManager(QLandmarkManager *manager)
{
    QMutexLocker ml(&d_ptr->mutex);
    if (d_ptr->state == QLandmarkAbstractRequest::ActiveState && d_ptr->manager)
        return;
    d_ptr->manager = manager;
}

/*!
    Attempts to start the request.

    Returns true if the request was started, otherwise false. Trying to start a
    request that is already active returns false.
    \sa cancel().
*/
bool QLandmarkAbstractRequest::start()
{
    QMutexLocker ml(&d_ptr->mutex);
    if (!d_ptr->manager) {
        d_ptr->error = QLandmarkManager::BadArgumentError;
        d_ptr->errorString = "No manager assigned to landmark request object";
        qWarning() << d_ptr->errorString;
        return false;
    }
    QLandmarkManagerEngine *engine = d_ptr->manager->engine();
    if (!engine) {
        d_ptr->error = QLandmarkManager::InvalidManagerError;
        d_ptr->errorString = "The manager is invalid";
        return false;
    }

    if (d_ptr->state != QLandmarkAbstractRequest::ActiveState) {
        ml.unlock();
        return engine->startRequest(this);
    }
     else {
        return false;
     }
}

/*!
    Notifies the request that it should be canceled.

    Returns true if the request was successfully notified
    that it should be canceled.  The request may or may not honor
    the cancel notification.  Returns false if the notification
    could not be made or the request is not in the
    QLandmarkManager::Active state.

    \sa start()
*/
bool QLandmarkAbstractRequest::cancel()
{
    QMutexLocker ml(&d_ptr->mutex);
    if (!d_ptr->manager) {
        d_ptr->error = QLandmarkManager::BadArgumentError;
        d_ptr->errorString = "No manager assigned to landmark request object";
        qWarning() << d_ptr->errorString;
        return false;
    }
    QLandmarkManagerEngine *engine = d_ptr->manager->engine();

    if(d_ptr->state == QLandmarkAbstractRequest::ActiveState) {
        ml.unlock();
        return engine->cancelRequest(this);
    }
    else
        return false;
}

/*!
    Blocks until the request has been completed or until \a msecs milliseconds
    has elapsed.  If \a msecs is zero or negative, this function will block indefinitely.

    Returns true if the request was canceled or completed
    within the given period, otherwise returns false.  Some backends may be unable
    to support this  operation safely and will return false immediately.
    The sqlite and sparql managers currently do not support waitForFinished(),
    while the symbian manager does.

    Note that any signals generated while waiting for the request to be complete
    may be queued and delivered sometime after this function has returned, when
    the calling thread's event loop is dispatched.  If your code depends on
    your slots being invoked, you may need to process events after calling
    this function.
*/
bool QLandmarkAbstractRequest::waitForFinished(int msecs)
{

    QMutexLocker ml(&d_ptr->mutex);
    if (!d_ptr->manager) {
        d_ptr->error = QLandmarkManager::BadArgumentError;
        d_ptr->errorString = "No manager assigned to landmark request object";
        qWarning() << d_ptr->errorString;
        return false;
    }
    QLandmarkManagerEngine *engine = d_ptr->manager->engine();

    switch(d_ptr->state) {
        case QLandmarkAbstractRequest::ActiveState:
            ml.unlock();
            return engine->waitForRequestFinished(this, msecs);
        case QLandmarkAbstractRequest::FinishedState:
            return true;
        default:
            return false;
    }
    return false;
}

/*!
  \fn void QLandmarkAbstractRequest::resultsAvailable()
  This signal is emitted when new results are available.  Results
  can include the operation error which may be accessed via error(),
  or derived-class specific results which are accessible through
  the derived class API.

  \sa error()
*/

/*!
    \fn void QLandmarkAbstractRequest::stateChanged(QLandmarkAbstractRequest::State newState)
    This signal is emitted when the state of the request is changed.  The new state of
    the request will be contained in \a newState.
*/

#include "moc_qlandmarkabstractrequest.cpp"

<|endoftext|>


<commit_before><commit_msg>Cleaned up implementation<commit_after><|endoftext|>


<commit_before><commit_msg>Rename MRegisterInfo to TargetRegisterInfo.<commit_after><|endoftext|>


<commit_before>/*
* Copyright 2008 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

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

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

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "Sockets.h"
#include "Threads.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

static const int gNumToSend = 10;

static void sigalarm_handler(int foo)
{
	printf("FAIL: test did not run successfully\n");
	exit(EXIT_FAILURE);
}

void *testReaderIP(void *param)
{
	UDPSocket *readSocket = (UDPSocket *)param;
	readSocket->nonblocking();
	int rc = 0;
	while (rc<gNumToSend) {
		char buf[MAX_UDP_LENGTH] = { 0 };
		int count = readSocket->read(buf, MAX_UDP_LENGTH);
		if (count>0) {
			CERR("read: " << buf);
			rc++;
		} else {
			sleep(2);
		}
	}
	return NULL;
}

int main(int argc, char * argv[] )
{
  int count;

  if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) {
    perror("signal");
    exit(EXIT_FAILURE);
  }

  /* If the test takes longer than 2*gNumToSend seconds, abort it */
  alarm(2* gNumToSend);

  UDPSocket readSocket("127.0.0.1", 0);
  UDPSocket socket1("127.0.0.1", 0, "localhost", readSocket.port());

  CERR("socket1: " << socket1.port() << ", readSocket: " << readSocket.port());

  Thread readerThreadIP;
  readerThreadIP.start(testReaderIP, &readSocket);

  // give the readers time to open
  sleep(1);

  for (int i=0; i<gNumToSend; i++) {
    CERR("write");
    count = socket1.write("Hello IP land");
    if (count < 0) {
      COUT("FAIL: write");
      exit(EXIT_FAILURE);
    }
    sleep(1);
  }

  readerThreadIP.join();

  printf("Done\n");
}

// vim: ts=4 sw=4
<commit_msg>SocketsTest.testReaderIP(): Zero terminate received buffer<commit_after>/*
* Copyright 2008 Free Software Foundation, Inc.
*
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

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

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

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "Sockets.h"
#include "Threads.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

static const int gNumToSend = 10;

static void sigalarm_handler(int foo)
{
	printf("FAIL: test did not run successfully\n");
	exit(EXIT_FAILURE);
}

void *testReaderIP(void *param)
{
	UDPSocket *readSocket = (UDPSocket *)param;
	readSocket->nonblocking();
	int rc = 0;
	while (rc<gNumToSend) {
		char buf[MAX_UDP_LENGTH+1] = { 0 };
		int count = readSocket->read(buf, MAX_UDP_LENGTH);
		if (count>0) {
			buf[count] = 0;
			CERR("read: " << buf);
			rc++;
		} else {
			sleep(2);
		}
	}
	return NULL;
}

int main(int argc, char * argv[] )
{
  int count;

  if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) {
    perror("signal");
    exit(EXIT_FAILURE);
  }

  /* If the test takes longer than 2*gNumToSend seconds, abort it */
  alarm(2* gNumToSend);

  UDPSocket readSocket("127.0.0.1", 0);
  UDPSocket socket1("127.0.0.1", 0, "localhost", readSocket.port());

  CERR("socket1: " << socket1.port() << ", readSocket: " << readSocket.port());

  Thread readerThreadIP;
  readerThreadIP.start(testReaderIP, &readSocket);

  // give the readers time to open
  sleep(1);

  for (int i=0; i<gNumToSend; i++) {
    CERR("write");
    count = socket1.write("Hello IP land");
    if (count < 0) {
      COUT("FAIL: write");
      exit(EXIT_FAILURE);
    }
    sleep(1);
  }

  readerThreadIP.join();

  printf("Done\n");
}

// vim: ts=4 sw=4
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2017 Asylo authors
 *
 * 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.
 *
 */

#include "asylo/platform/arch/sgx/untrusted/sgx_client.h"

#include <cstdint>
#include <string>

#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "asylo/util/logging.h"
#include "asylo/platform/arch/sgx/sgx_error_space.h"
#include "asylo/platform/arch/sgx/untrusted/generated_bridge_u.h"
#include "asylo/platform/common/bridge_functions.h"
#include "asylo/platform/common/bridge_types.h"
#include "asylo/util/elf_reader.h"
#include "asylo/util/file_mapping.h"
#include "asylo/util/posix_error_space.h"
#include "asylo/util/status_macros.h"

namespace asylo {
namespace {

constexpr absl::string_view kCallingProcessBinaryFile = "/proc/self/exe";

constexpr int kMaxEnclaveCreateAttempts = 5;

// Creates an SGX enclave from |buffer|, updating |token| and |enclave_id| with
// the appropriate data. If enclave creation fails due to an interruption in the
// enclave creation process, retries the enclave creation up to a total of
// kMaxEnclaveCreateAttempts tries.
Status LoadFromBuffer(absl::Span<const uint8_t> buffer, bool debug,
                      sgx_launch_token_t *token, sgx_enclave_id_t *enclave_id,
                      void **enclave_base_addr) {
  int updated;
  sgx_status_t sgx_status;
  for (int i = 0; i < kMaxEnclaveCreateAttempts; ++i) {
    sgx_status = sgx_create_enclave_from_buffer(
        const_cast<uint8_t *>(buffer.data()), buffer.size(), debug, token,
        &updated, enclave_id, /*misc_attr=*/nullptr, enclave_base_addr);

    if (sgx_status == SGX_SUCCESS) {
      break;
    }

    if (sgx_status != SGX_INTERNAL_ERROR_ENCLAVE_CREATE_INTERRUPTED) {
      return Status(sgx_status, "Failed to create an enclave");
    }
  }

  return Status::OkStatus();
}

}  // namespace

// Enters the enclave and invokes the initialization entry-point. If the ecall
// fails, or the enclave does not return any output, returns a non-OK status. In
// this case, the caller cannot make any assumptions about the contents of
// |output|. Otherwise, |output| points to a buffer of length *|output_len| that
// contains output from the enclave.
static Status initialize(sgx_enclave_id_t eid, const char *name,
                         const char *input, size_t input_len, char **output,
                         size_t *output_len) {
  int result;
  sgx_status_t sgx_status = ecall_initialize(
      eid, &result, name, input, static_cast<bridge_size_t>(input_len), output,
      static_cast<bridge_size_t *>(output_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_initialize failed");
  } else if (result || *output_len == 0) {
    // Non-zero return code indicates that the enclave was not able to return
    // any output from Initialize().
    return Status(error::GoogleError::INTERNAL, "No output from enclave");
  }

  return Status::OkStatus();
}

// Enters the enclave and invokes the execution entry-point. If the ecall fails,
// or the enclave does not return any output, returns a non-OK status. In this
// case, the caller cannot make any assumptions about the contents of |output|.
// Otherwise, |output| points to a buffer of length *|output_len| that contains
// output from the enclave.
static Status run(sgx_enclave_id_t eid, const char *input, size_t input_len,
                  char **output, size_t *output_len) {
  int result;
  sgx_status_t sgx_status =
      ecall_run(eid, &result, input, static_cast<bridge_size_t>(input_len),
                output, static_cast<bridge_size_t *>(output_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_run failed");
  } else if (result || *output_len == 0) {
    // Ecall succeeded but did not return a value. The indicates that the
    // trusted code failed to propagate error information over the enclave
    // boundary (e.g. serialization failure).
    return Status(error::GoogleError::INTERNAL, "No output from enclave");
  }

  return Status::OkStatus();
}

// Enters the enclave and invokes the finalization entry-point. If the ecall
// fails, or the enclave does not return any output, returns a non-OK status. In
// this case, the caller cannot make any assumptions about the contents of
// |output|. Otherwise, |output| points to a buffer of length *|output_len| that
// contains output from the enclave.
static Status finalize(sgx_enclave_id_t eid, const char *input,
                       size_t input_len, char **output, size_t *output_len) {
  int result;
  sgx_status_t sgx_status =
      ecall_finalize(eid, &result, input, static_cast<bridge_size_t>(input_len),
                     output, static_cast<bridge_size_t *>(output_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_finalize failed");
  } else if (result || *output_len == 0) {
    // Non-zero return code indicates that the enclave was not able to return
    // any output from Finalize().
    return Status(error::GoogleError::INTERNAL, "No output from enclave");
  }

  return Status::OkStatus();
}

static int donate_thread(sgx_enclave_id_t eid, sgx_status_t *status) {
  int result;
  sgx_status_t local_status = ecall_donate_thread(eid, &result);
  if (status) *status = local_status;
  if (local_status != SGX_SUCCESS) {
    return -1;
  }
  return result;
}

// Enters the enclave and invokes the signal handle entry-point. If the ecall
// fails, returns a non-OK status.
static Status handle_signal(sgx_enclave_id_t eid, const char *input,
                            size_t input_len) {
  int result;
  sgx_status_t sgx_status = ecall_handle_signal(
      eid, &result, input, static_cast<bridge_size_t>(input_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_handle_signal failed");
  } else if (result) {
    std::string message;
    switch (result) {
      case 1:
        message = "Invalid or unregistered incoming signal";
        break;
      case 2:
        message = "Enclave unable to handle signal in current state";
        break;
      case -1:
        message = "Incoming signal is blocked inside the enclave";
        break;
      default:
        message = "Unexpected error while handling signal";
    }
    return Status(error::GoogleError::INTERNAL, message);
  }
  return Status::OkStatus();
}

StatusOr<std::unique_ptr<EnclaveClient>> SgxLoader::LoadEnclave(
    const std::string &name, void *base_address) const {
  std::unique_ptr<SgxClient> client = absl::make_unique<SgxClient>(name);
  client->base_address_ = base_address;

  FileMapping enclave_file_mapping;
  ASYLO_ASSIGN_OR_RETURN(enclave_file_mapping,
                         FileMapping::CreateFromFile(enclave_path_));

  ASYLO_RETURN_IF_ERROR(LoadFromBuffer(enclave_file_mapping.buffer(), debug_,
                                       &client->token_, &client->id_,
                                       &client->base_address_));

  return std::unique_ptr<EnclaveClient>(client.release());
}

StatusOr<std::unique_ptr<EnclaveClient>> SgxEmbeddedLoader::LoadEnclave(
    const std::string &name, void *base_address) const {
  std::unique_ptr<SgxClient> client = absl::make_unique<SgxClient>(name);
  client->base_address_ = base_address;

  FileMapping self_binary_mapping;
  ASYLO_ASSIGN_OR_RETURN(self_binary_mapping, FileMapping::CreateFromFile(
                                                  kCallingProcessBinaryFile));

  ElfReader self_binary_reader;
  ASYLO_ASSIGN_OR_RETURN(self_binary_reader, ElfReader::CreateFromSpan(
                                                 self_binary_mapping.buffer()));

  absl::Span<const uint8_t> enclave_buffer;
  ASYLO_ASSIGN_OR_RETURN(enclave_buffer,
                         self_binary_reader.GetSectionData(section_name_));

  ASYLO_RETURN_IF_ERROR(LoadFromBuffer(enclave_buffer, debug_, &client->token_,
                                       &client->id_, &client->base_address_));

  return std::unique_ptr<EnclaveClient>(client.release());
}

Status SgxClient::EnterAndInitialize(const EnclaveConfig &config) {
  std::string buf;
  if (!config.SerializeToString(&buf)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveConfig");
  }

  char *output = nullptr;
  size_t output_len = 0;
  ASYLO_RETURN_IF_ERROR(initialize(id_, get_name().c_str(), buf.data(),
                                   buf.size(), &output, &output_len));

  // Enclave entry-point was successfully invoked. |output| is guaranteed to
  // have a value.
  StatusProto status_proto;
  if (!status_proto.ParseFromArray(output, output_len)) {
    return Status(error::GoogleError::INTERNAL,
                  "Failed to deserialize StatusProto");
  }
  Status status;
  status.RestoreFrom(status_proto);

  // |output| points to an untrusted memory buffer allocated by the enclave. It
  // is the untrusted caller's responsibility to free this buffer.
  free(output);

  return status;
}

Status SgxClient::EnterAndRun(const EnclaveInput &input,
                              EnclaveOutput *output) {
  std::string buf;
  if (!input.SerializeToString(&buf)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveInput");
  }

  char *output_buf = nullptr;
  size_t output_len = 0;
  ASYLO_RETURN_IF_ERROR(
      run(id_, buf.data(), buf.size(), &output_buf, &output_len));

  // Enclave entry-point was successfully invoked. |output_buf| is guaranteed to
  // have a value.
  EnclaveOutput local_output;
  local_output.ParseFromArray(output_buf, output_len);
  Status status;
  status.RestoreFrom(local_output.status());

  // If |output| is not null, then |output_buf| points to a memory buffer
  // allocated inside the enclave using enc_untrusted_malloc(). It is the
  // caller's responsibility to free this buffer.
  free(output_buf);

  // Set the output parameter if necessary.
  if (output) {
    *output = local_output;
  }

  return status;
}

Status SgxClient::EnterAndFinalize(const EnclaveFinal &final_input) {
  std::string buf;
  if (!final_input.SerializeToString(&buf)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveFinal");
  }

  char *output = nullptr;
  size_t output_len = 0;

  ASYLO_RETURN_IF_ERROR(
      finalize(id_, buf.data(), buf.size(), &output, &output_len));

  // Enclave entry-point was successfully invoked. |output| is guaranteed to
  // have a value.
  StatusProto status_proto;
  status_proto.ParseFromArray(output, output_len);
  Status status;
  status.RestoreFrom(status_proto);

  // |output| points to an untrusted memory buffer allocated by the enclave. It
  // is the untrusted caller's responsibility to free this buffer.
  free(output);

  return status;
}

Status SgxClient::EnterAndDonateThread() {
  sgx_status_t sgx_status;
  int result = donate_thread(id_, &sgx_status);
  Status status;
  if (sgx_status != SGX_SUCCESS) {
    status = Status(sgx_status, "Failed to donate thread to enclave");
  } else if (result) {
    status = Status(static_cast<error::PosixError>(result),
                    "Failed to donate thread to enclave");
  }
  if (!status.ok()) {
    LOG(ERROR) << "EnterAndDonateThread failed " << status;
  }
  return status;
}

Status SgxClient::EnterAndHandleSignal(const EnclaveSignal &signal) {
  EnclaveSignal enclave_signal;
  int bridge_signum = ToBridgeSignal(signal.signum());
  if (bridge_signum < 0) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  absl::StrCat("Failed to convert signum (", signal.signum(),
                               ") to bridge signum"));
  }
  enclave_signal.set_signum(bridge_signum);
  std::string serialized_enclave_signal;
  if (!enclave_signal.SerializeToString(&serialized_enclave_signal)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveSignal");
  }
  return handle_signal(id_, serialized_enclave_signal.data(),
                       serialized_enclave_signal.size());
}

Status SgxClient::DestroyEnclave() {
  sgx_status_t rc = sgx_destroy_enclave(id_);
  if (rc != SGX_SUCCESS) {
    return Status(rc, "Failed to destroy an enclave");
  }
  return Status::OkStatus();
}

bool SgxClient::IsTcsActive() { return (sgx_is_tcs_active(id_) != 0); }

}  //  namespace asylo
<commit_msg>Load enclave from file when available<commit_after>/*
 *
 * Copyright 2017 Asylo authors
 *
 * 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.
 *
 */

#include "asylo/platform/arch/sgx/untrusted/sgx_client.h"

#include <cstdint>
#include <string>

#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "asylo/util/logging.h"
#include "asylo/platform/arch/sgx/sgx_error_space.h"
#include "asylo/platform/arch/sgx/untrusted/generated_bridge_u.h"
#include "asylo/platform/common/bridge_functions.h"
#include "asylo/platform/common/bridge_types.h"
#include "asylo/util/elf_reader.h"
#include "asylo/util/file_mapping.h"
#include "asylo/util/posix_error_space.h"
#include "asylo/util/status_macros.h"

namespace asylo {
namespace {

constexpr absl::string_view kCallingProcessBinaryFile = "/proc/self/exe";

constexpr int kMaxEnclaveCreateAttempts = 5;

}  // namespace

// Enters the enclave and invokes the initialization entry-point. If the ecall
// fails, or the enclave does not return any output, returns a non-OK status. In
// this case, the caller cannot make any assumptions about the contents of
// |output|. Otherwise, |output| points to a buffer of length *|output_len| that
// contains output from the enclave.
static Status initialize(sgx_enclave_id_t eid, const char *name,
                         const char *input, size_t input_len, char **output,
                         size_t *output_len) {
  int result;
  sgx_status_t sgx_status = ecall_initialize(
      eid, &result, name, input, static_cast<bridge_size_t>(input_len), output,
      static_cast<bridge_size_t *>(output_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_initialize failed");
  } else if (result || *output_len == 0) {
    // Non-zero return code indicates that the enclave was not able to return
    // any output from Initialize().
    return Status(error::GoogleError::INTERNAL, "No output from enclave");
  }

  return Status::OkStatus();
}

// Enters the enclave and invokes the execution entry-point. If the ecall fails,
// or the enclave does not return any output, returns a non-OK status. In this
// case, the caller cannot make any assumptions about the contents of |output|.
// Otherwise, |output| points to a buffer of length *|output_len| that contains
// output from the enclave.
static Status run(sgx_enclave_id_t eid, const char *input, size_t input_len,
                  char **output, size_t *output_len) {
  int result;
  sgx_status_t sgx_status =
      ecall_run(eid, &result, input, static_cast<bridge_size_t>(input_len),
                output, static_cast<bridge_size_t *>(output_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_run failed");
  } else if (result || *output_len == 0) {
    // Ecall succeeded but did not return a value. The indicates that the
    // trusted code failed to propagate error information over the enclave
    // boundary (e.g. serialization failure).
    return Status(error::GoogleError::INTERNAL, "No output from enclave");
  }

  return Status::OkStatus();
}

// Enters the enclave and invokes the finalization entry-point. If the ecall
// fails, or the enclave does not return any output, returns a non-OK status. In
// this case, the caller cannot make any assumptions about the contents of
// |output|. Otherwise, |output| points to a buffer of length *|output_len| that
// contains output from the enclave.
static Status finalize(sgx_enclave_id_t eid, const char *input,
                       size_t input_len, char **output, size_t *output_len) {
  int result;
  sgx_status_t sgx_status =
      ecall_finalize(eid, &result, input, static_cast<bridge_size_t>(input_len),
                     output, static_cast<bridge_size_t *>(output_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_finalize failed");
  } else if (result || *output_len == 0) {
    // Non-zero return code indicates that the enclave was not able to return
    // any output from Finalize().
    return Status(error::GoogleError::INTERNAL, "No output from enclave");
  }

  return Status::OkStatus();
}

static int donate_thread(sgx_enclave_id_t eid, sgx_status_t *status) {
  int result;
  sgx_status_t local_status = ecall_donate_thread(eid, &result);
  if (status) *status = local_status;
  if (local_status != SGX_SUCCESS) {
    return -1;
  }
  return result;
}

// Enters the enclave and invokes the signal handle entry-point. If the ecall
// fails, returns a non-OK status.
static Status handle_signal(sgx_enclave_id_t eid, const char *input,
                            size_t input_len) {
  int result;
  sgx_status_t sgx_status = ecall_handle_signal(
      eid, &result, input, static_cast<bridge_size_t>(input_len));
  if (sgx_status != SGX_SUCCESS) {
    // Return a Status object in the SGX error space.
    return Status(sgx_status, "Call to ecall_handle_signal failed");
  } else if (result) {
    std::string message;
    switch (result) {
      case 1:
        message = "Invalid or unregistered incoming signal";
        break;
      case 2:
        message = "Enclave unable to handle signal in current state";
        break;
      case -1:
        message = "Incoming signal is blocked inside the enclave";
        break;
      default:
        message = "Unexpected error while handling signal";
    }
    return Status(error::GoogleError::INTERNAL, message);
  }
  return Status::OkStatus();
}

StatusOr<std::unique_ptr<EnclaveClient>> SgxLoader::LoadEnclave(
    const std::string &name, void *base_address) const {
  std::unique_ptr<SgxClient> client = absl::make_unique<SgxClient>(name);
  client->base_address_ = base_address;

  int updated;
  sgx_status_t status;
  for (int i = 0; i < kMaxEnclaveCreateAttempts; ++i) {
    status = sgx_create_enclave(enclave_path_.c_str(), debug_, &client->token_,
                                &updated, &client->id_,
                                /*misc_attr=*/nullptr, &client->base_address_);

    if (status != SGX_INTERNAL_ERROR_ENCLAVE_CREATE_INTERRUPTED) {
      break;
    }
  }

  if (status != SGX_SUCCESS) {
    return Status(status, "Failed to create an enclave");
  }

  return std::unique_ptr<EnclaveClient>(client.release());
}

StatusOr<std::unique_ptr<EnclaveClient>> SgxEmbeddedLoader::LoadEnclave(
    const std::string &name, void *base_address) const {
  std::unique_ptr<SgxClient> client = absl::make_unique<SgxClient>(name);
  client->base_address_ = base_address;

  FileMapping self_binary_mapping;
  ASYLO_ASSIGN_OR_RETURN(self_binary_mapping, FileMapping::CreateFromFile(
                                                  kCallingProcessBinaryFile));

  ElfReader self_binary_reader;
  ASYLO_ASSIGN_OR_RETURN(self_binary_reader, ElfReader::CreateFromSpan(
                                                 self_binary_mapping.buffer()));

  absl::Span<const uint8_t> enclave_buffer;
  ASYLO_ASSIGN_OR_RETURN(enclave_buffer,
                         self_binary_reader.GetSectionData(section_name_));

  int updated;
  sgx_status_t status;
  for (int i = 0; i < kMaxEnclaveCreateAttempts; ++i) {
    status = sgx_create_enclave_from_buffer(
        const_cast<uint8_t *>(enclave_buffer.data()), enclave_buffer.size(),
        debug_, &client->token_, &updated, &client->id_, /*misc_attr=*/nullptr,
        &client->base_address_);

    if (status != SGX_INTERNAL_ERROR_ENCLAVE_CREATE_INTERRUPTED) {
      break;
    }
  }

  if (status != SGX_SUCCESS) {
    return Status(status, "Failed to create an enclave");
  }

  return std::unique_ptr<EnclaveClient>(client.release());
}

Status SgxClient::EnterAndInitialize(const EnclaveConfig &config) {
  std::string buf;
  if (!config.SerializeToString(&buf)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveConfig");
  }

  char *output = nullptr;
  size_t output_len = 0;
  ASYLO_RETURN_IF_ERROR(initialize(id_, get_name().c_str(), buf.data(),
                                   buf.size(), &output, &output_len));

  // Enclave entry-point was successfully invoked. |output| is guaranteed to
  // have a value.
  StatusProto status_proto;
  if (!status_proto.ParseFromArray(output, output_len)) {
    return Status(error::GoogleError::INTERNAL,
                  "Failed to deserialize StatusProto");
  }
  Status status;
  status.RestoreFrom(status_proto);

  // |output| points to an untrusted memory buffer allocated by the enclave. It
  // is the untrusted caller's responsibility to free this buffer.
  free(output);

  return status;
}

Status SgxClient::EnterAndRun(const EnclaveInput &input,
                              EnclaveOutput *output) {
  std::string buf;
  if (!input.SerializeToString(&buf)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveInput");
  }

  char *output_buf = nullptr;
  size_t output_len = 0;
  ASYLO_RETURN_IF_ERROR(
      run(id_, buf.data(), buf.size(), &output_buf, &output_len));

  // Enclave entry-point was successfully invoked. |output_buf| is guaranteed to
  // have a value.
  EnclaveOutput local_output;
  local_output.ParseFromArray(output_buf, output_len);
  Status status;
  status.RestoreFrom(local_output.status());

  // If |output| is not null, then |output_buf| points to a memory buffer
  // allocated inside the enclave using enc_untrusted_malloc(). It is the
  // caller's responsibility to free this buffer.
  free(output_buf);

  // Set the output parameter if necessary.
  if (output) {
    *output = local_output;
  }

  return status;
}

Status SgxClient::EnterAndFinalize(const EnclaveFinal &final_input) {
  std::string buf;
  if (!final_input.SerializeToString(&buf)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveFinal");
  }

  char *output = nullptr;
  size_t output_len = 0;

  ASYLO_RETURN_IF_ERROR(
      finalize(id_, buf.data(), buf.size(), &output, &output_len));

  // Enclave entry-point was successfully invoked. |output| is guaranteed to
  // have a value.
  StatusProto status_proto;
  status_proto.ParseFromArray(output, output_len);
  Status status;
  status.RestoreFrom(status_proto);

  // |output| points to an untrusted memory buffer allocated by the enclave. It
  // is the untrusted caller's responsibility to free this buffer.
  free(output);

  return status;
}

Status SgxClient::EnterAndDonateThread() {
  sgx_status_t sgx_status;
  int result = donate_thread(id_, &sgx_status);
  Status status;
  if (sgx_status != SGX_SUCCESS) {
    status = Status(sgx_status, "Failed to donate thread to enclave");
  } else if (result) {
    status = Status(static_cast<error::PosixError>(result),
                    "Failed to donate thread to enclave");
  }
  if (!status.ok()) {
    LOG(ERROR) << "EnterAndDonateThread failed " << status;
  }
  return status;
}

Status SgxClient::EnterAndHandleSignal(const EnclaveSignal &signal) {
  EnclaveSignal enclave_signal;
  int bridge_signum = ToBridgeSignal(signal.signum());
  if (bridge_signum < 0) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  absl::StrCat("Failed to convert signum (", signal.signum(),
                               ") to bridge signum"));
  }
  enclave_signal.set_signum(bridge_signum);
  std::string serialized_enclave_signal;
  if (!enclave_signal.SerializeToString(&serialized_enclave_signal)) {
    return Status(error::GoogleError::INVALID_ARGUMENT,
                  "Failed to serialize EnclaveSignal");
  }
  return handle_signal(id_, serialized_enclave_signal.data(),
                       serialized_enclave_signal.size());
}

Status SgxClient::DestroyEnclave() {
  sgx_status_t rc = sgx_destroy_enclave(id_);
  if (rc != SGX_SUCCESS) {
    return Status(rc, "Failed to destroy an enclave");
  }
  return Status::OkStatus();
}

bool SgxClient::IsTcsActive() { return (sgx_is_tcs_active(id_) != 0); }

}  //  namespace asylo
<|endoftext|>


<commit_before>/* auto_encoder_stack.cc                                           -*- C++ -*-
   Jeremy Barnes, 11 November 2009
   Copyright (c) 2009 Jeremy Barnes.  All rights reserved.

   Implementation of a stack of auto-encoders.
*/

#include "auto_encoder_stack.h"
#include "boosting/registry.h"
#include "layer_stack_impl.h"

namespace ML {

/*****************************************************************************/
/* AUTO_ENCODER_STACK                                                        */
/*****************************************************************************/

/** A stack of auto-encoders, that acts as a whole like an auto-encoder. */

Auto_Encoder_Stack::
Auto_Encoder_Stack()
{
}

Auto_Encoder_Stack::
Auto_Encoder_Stack(const std::string & name)
    : layers_(name)
{
}

Auto_Encoder_Stack::
Auto_Encoder_Stack(const Auto_Encoder_Stack & other, Deep_Copy_Tag)
    : Auto_Encoder(other),
      layers_(other.layers_, Deep_Copy_Tag())
{
}

void
Auto_Encoder_Stack::
swap(Auto_Encoder_Stack & other)
{
    layers_.swap(other.layers_);
}

void
Auto_Encoder_Stack::
clear()
{
    layers_.clear();
}

void
Auto_Encoder_Stack::
add(Auto_Encoder * layer)
{
    layers_.add(layer);
    Layer::init(name(), layers_.inputs(), layers_.outputs());
    update_parameters();
}

void
Auto_Encoder_Stack::
add(boost::shared_ptr<Auto_Encoder> layer)
{
    layers_.add(layer);
    Layer::init(name(), layers_.inputs(), layers_.outputs());
    update_parameters();
}

std::string
Auto_Encoder_Stack::
print() const
{
    return layers_.print();
}

std::string
Auto_Encoder_Stack::
class_id() const
{
    return "Auto_Encoder_Stack";
}

void
Auto_Encoder_Stack::
serialize(DB::Store_Writer & store) const
{
    store << (char)1 // version
          << layers_;
}

void
Auto_Encoder_Stack::
reconstitute(DB::Store_Reader & store)
{
    char version;
    store >> version;
    if (version != 1)
        throw Exception("Auto_Encoder_Stack::reconstitute(): invalid version");
    store >> layers_;
}

void
Auto_Encoder_Stack::
add_parameters(Parameters & params)
{
    layers_.add_parameters(params);
}

void
Auto_Encoder_Stack::
apply(const float * input, float * output) const
{
    return layers_.apply(input, output);
}

void
Auto_Encoder_Stack::
apply(const double * input, double * output) const
{
    return layers_.apply(input, output);
}

size_t
Auto_Encoder_Stack::
fprop_temporary_space_required() const
{
    return layers_.fprop_temporary_space_required();
}

void
Auto_Encoder_Stack::
fprop(const float * inputs,
      float * temp_space, size_t temp_space_size,
      float * outputs) const
{
    layers_.fprop(inputs, temp_space, temp_space_size, outputs);
}

void
Auto_Encoder_Stack::
fprop(const double * inputs,
      double * temp_space, size_t temp_space_size,
      double * outputs) const
{
    layers_.fprop(inputs, temp_space, temp_space_size, outputs);
}

void
Auto_Encoder_Stack::
bprop(const float * inputs,
      const float * outputs,
      const float * temp_space, size_t temp_space_size,
      const float * output_errors,
      float * input_errors,
      Parameters & gradient,
      double example_weight) const
{
    layers_.bprop(inputs, outputs, temp_space, temp_space_size,
                  output_errors, input_errors, gradient, example_weight);
}

void
Auto_Encoder_Stack::
bprop(const double * inputs,
      const double * outputs,
      const double * temp_space, size_t temp_space_size,
      const double * output_errors,
      double * input_errors,
      Parameters & gradient,
      double example_weight) const
{
    layers_.bprop(inputs, outputs, temp_space, temp_space_size,
                  output_errors, input_errors, gradient, example_weight);
}

void
Auto_Encoder_Stack::
iapply(const float * output, float * input) const
{
    iapply<float>(output, input);
}

void
Auto_Encoder_Stack::
iapply(const double * output, double * input) const
{
    iapply<double>(output, input);
}

template<typename F>
void
Auto_Encoder_Stack::
iapply(const F * output, F * input) const
{
    F tmp[layers_.max_internal_width()];

    for (int l = layers_.size() - 1;  l >= 0;  --l) {
        F * i = (l == 0 ? input : tmp);
        const F * o = (l == layers_.size() - 1 ? output : tmp);

        layers_[l].iapply(o, i);
    }
}

size_t
Auto_Encoder_Stack::
ifprop_temporary_space_required() const
{
    // We need: inputs of all layers except the first,
    // temporary space of all layers in between.
    //
    // +-----------+-------+-------------+--------+---...
    // |   l0 tmp  | l0 out|  l1 tmp     |  l1 out| l2 tmp
    // +-----------+-------+-------------+--------+---...

    size_t result = 0;

    for (unsigned i = 0;  i < size();  ++i) {
        if (i != 0) result += layers_[i].inputs();
        result += layers_[i].ifprop_temporary_space_required();
    }

    return result;
}

void
Auto_Encoder_Stack::
ifprop(const float * outputs,
       float * temp_space, size_t temp_space_size,
       float * inputs) const
{
    ifprop<float>(outputs, temp_space, temp_space_size, inputs);
}

void
Auto_Encoder_Stack::
ifprop(const double * outputs,
       double * temp_space, size_t temp_space_size,
       double * inputs) const
{
    ifprop<double>(outputs, temp_space, temp_space_size, inputs);
}

template<typename F>
void
Auto_Encoder_Stack::
ifprop(const F * outputs,
       F * temp_space, size_t temp_space_size,
       F * inputs) const
{
    F * temp_space_start = temp_space;
    F * temp_space_end = temp_space_start + temp_space_size;

    const F * curr_outputs = outputs;

    for (int i = size() - 1;  i >= 0;  --i) {
        int layer_temp_space_size
            = layers_[i].ifprop_temporary_space_required();

        F * curr_inputs
            = (i == 0
               ? inputs
               : temp_space + layer_temp_space_size);

        layers_[i].ifprop(curr_outputs, temp_space, layer_temp_space_size,
                           curr_inputs);

        curr_outputs = curr_inputs;

        temp_space += layer_temp_space_size;
        if (i != 0) temp_space += layers_[i].inputs();

        if (temp_space > temp_space_end
            || (i == 0 && temp_space != temp_space_end))
            throw Exception("temp space out of sync");
    }
}

void
Auto_Encoder_Stack::
ibprop(const float * outputs,
       const float * inputs,
       const float * temp_space, size_t temp_space_size,
       const float * input_errors,
       float * output_errors,
       Parameters & gradient,
       double example_weight) const
{
    ibprop<float>(outputs, inputs, temp_space, temp_space_size,
                  input_errors, output_errors, gradient, example_weight);
}

void
Auto_Encoder_Stack::
ibprop(const double * outputs,
       const double * inputs,
       const double * temp_space, size_t temp_space_size,
       const double * input_errors,
       double * output_errors,
       Parameters & gradient,
       double example_weight) const
{
    ibprop<double>(outputs, inputs, temp_space, temp_space_size,
                   input_errors, output_errors, gradient, example_weight);
}

template<typename F>
void
Auto_Encoder_Stack::
ibprop(const F * outputs,
       const F * inputs,
       const F * temp_space, size_t temp_space_size,
       const F * input_errors,
       F * output_errors,
       Parameters & gradient,
       double example_weight) const
{
    const F * temp_space_start = temp_space;
    const F * temp_space_end = temp_space_start + temp_space_size;
    const F * curr_temp_space = temp_space_end;

    const F * curr_inputs = inputs;

    // Storage for the errors kept between the layers
    F error_storage[layers_.max_internal_width()];

    for (int i = 0;  i < layers_.size(); ++i) {
        int layer_temp_space_size
            = layers_[i].ifprop_temporary_space_required();

        curr_temp_space -= layer_temp_space_size;

        const F * curr_outputs
            = (i == size() - 1
               ? outputs
               : curr_temp_space - layers_[i].outputs());

        const F * curr_input_errors
            = (i == 0 ? input_errors : error_storage);

        F * curr_output_errors
            = (i == size() - 1 ? output_errors : error_storage);

        layers_[i].ibprop(curr_outputs, curr_inputs, curr_temp_space,
                           layer_temp_space_size, curr_input_errors,
                           curr_output_errors,
                           gradient.subparams(i, layers_[i].name()),
                           example_weight);

        if (curr_temp_space < temp_space_start)
            throw Exception("Layer temp space was out of sync");

        curr_inputs = curr_outputs;
        if (i != layers_.size() - 1) curr_temp_space -= layers_[i].outputs();
    }

    if (curr_temp_space != temp_space_start)
        throw Exception("Layer_Stack::bprop(): out of sync");
}

void
Auto_Encoder_Stack::
random_fill(float limit, Thread_Context & context)
{
    layers_.random_fill(limit, context);
}

void
Auto_Encoder_Stack::
zero_fill()
{
    layers_.zero_fill();
}

size_t
Auto_Encoder_Stack::
parameter_count() const
{
    return layers_.parameter_count();
}

std::pair<float, float>
Auto_Encoder_Stack::
targets(float maximum) const
{
    return layers_.targets(maximum);
}

Auto_Encoder_Stack *
Auto_Encoder_Stack::
make_copy() const
{
    return new Auto_Encoder_Stack(*this);
}

Auto_Encoder_Stack *
Auto_Encoder_Stack::
deep_copy() const
{
    return new Auto_Encoder_Stack(*this, Deep_Copy_Tag());
}

bool
Auto_Encoder_Stack::
equal_impl(const Layer & other) const
{
    if (typeid(*this) != typeid(other)) return false;
    return layers_.equal_impl(other);
}

bool
Auto_Encoder_Stack::
operator == (const Auto_Encoder_Stack & other) const
{
    return layers_.operator == (other.layers_);
}

namespace {

Register_Factory<Layer, Auto_Encoder_Stack>
AES_REGISTER("Auto_Encoder_Stack");

} // file scope

template class Layer_Stack<Auto_Encoder>;

} // namespace ML
<commit_msg>NaN checking in auto_encoder implementation<commit_after>/* auto_encoder_stack.cc                                           -*- C++ -*-
   Jeremy Barnes, 11 November 2009
   Copyright (c) 2009 Jeremy Barnes.  All rights reserved.

   Implementation of a stack of auto-encoders.
*/

#undef NDEBUG

#include "auto_encoder_stack.h"
#include "boosting/registry.h"
#include "layer_stack_impl.h"
#include "utils/check_not_nan.h"

using namespace std;

namespace ML {

/*****************************************************************************/
/* AUTO_ENCODER_STACK                                                        */
/*****************************************************************************/

/** A stack of auto-encoders, that acts as a whole like an auto-encoder. */

Auto_Encoder_Stack::
Auto_Encoder_Stack()
{
}

Auto_Encoder_Stack::
Auto_Encoder_Stack(const std::string & name)
    : layers_(name)
{
}

Auto_Encoder_Stack::
Auto_Encoder_Stack(const Auto_Encoder_Stack & other, Deep_Copy_Tag)
    : Auto_Encoder(other),
      layers_(other.layers_, Deep_Copy_Tag())
{
}

void
Auto_Encoder_Stack::
swap(Auto_Encoder_Stack & other)
{
    layers_.swap(other.layers_);
}

void
Auto_Encoder_Stack::
clear()
{
    layers_.clear();
}

void
Auto_Encoder_Stack::
add(Auto_Encoder * layer)
{
    layers_.add(layer);
    Layer::init(name(), layers_.inputs(), layers_.outputs());
    update_parameters();
}

void
Auto_Encoder_Stack::
add(boost::shared_ptr<Auto_Encoder> layer)
{
    layers_.add(layer);
    Layer::init(name(), layers_.inputs(), layers_.outputs());
    update_parameters();
}

std::string
Auto_Encoder_Stack::
print() const
{
    return layers_.print();
}

std::string
Auto_Encoder_Stack::
class_id() const
{
    return "Auto_Encoder_Stack";
}

void
Auto_Encoder_Stack::
serialize(DB::Store_Writer & store) const
{
    store << (char)1 // version
          << layers_;
}

void
Auto_Encoder_Stack::
reconstitute(DB::Store_Reader & store)
{
    char version;
    store >> version;
    if (version != 1)
        throw Exception("Auto_Encoder_Stack::reconstitute(): invalid version");
    store >> layers_;
}

void
Auto_Encoder_Stack::
add_parameters(Parameters & params)
{
    layers_.add_parameters(params);
}

void
Auto_Encoder_Stack::
apply(const float * input, float * output) const
{
    return layers_.apply(input, output);
}

void
Auto_Encoder_Stack::
apply(const double * input, double * output) const
{
    return layers_.apply(input, output);
}

size_t
Auto_Encoder_Stack::
fprop_temporary_space_required() const
{
    return layers_.fprop_temporary_space_required();
}

void
Auto_Encoder_Stack::
fprop(const float * inputs,
      float * temp_space, size_t temp_space_size,
      float * outputs) const
{
    layers_.fprop(inputs, temp_space, temp_space_size, outputs);
}

void
Auto_Encoder_Stack::
fprop(const double * inputs,
      double * temp_space, size_t temp_space_size,
      double * outputs) const
{
    layers_.fprop(inputs, temp_space, temp_space_size, outputs);
}

void
Auto_Encoder_Stack::
bprop(const float * inputs,
      const float * outputs,
      const float * temp_space, size_t temp_space_size,
      const float * output_errors,
      float * input_errors,
      Parameters & gradient,
      double example_weight) const
{
    layers_.bprop(inputs, outputs, temp_space, temp_space_size,
                  output_errors, input_errors, gradient, example_weight);
}

void
Auto_Encoder_Stack::
bprop(const double * inputs,
      const double * outputs,
      const double * temp_space, size_t temp_space_size,
      const double * output_errors,
      double * input_errors,
      Parameters & gradient,
      double example_weight) const
{
    layers_.bprop(inputs, outputs, temp_space, temp_space_size,
                  output_errors, input_errors, gradient, example_weight);
}

void
Auto_Encoder_Stack::
iapply(const float * output, float * input) const
{
    iapply<float>(output, input);
}

void
Auto_Encoder_Stack::
iapply(const double * output, double * input) const
{
    iapply<double>(output, input);
}

template<typename F>
void
Auto_Encoder_Stack::
iapply(const F * output, F * input) const
{
    F tmp[layers_.max_internal_width()];

    for (int l = layers_.size() - 1;  l >= 0;  --l) {
        F * i = (l == 0 ? input : tmp);
        const F * o = (l == layers_.size() - 1 ? output : tmp);

        layers_[l].iapply(o, i);
    }
}

size_t
Auto_Encoder_Stack::
ifprop_temporary_space_required() const
{
    // We need: inputs of all layers except the first,
    // temporary space of all layers in between.
    //
    // +-----------+-------+-------------+--------+---...
    // |   l0 tmp  | l0 out|  l1 tmp     |  l1 out| l2 tmp
    // +-----------+-------+-------------+--------+---...

    size_t result = 0;

    for (unsigned i = 0;  i < size();  ++i) {
        if (i != 0) result += layers_[i].inputs();
        result += layers_[i].ifprop_temporary_space_required();
    }

    return result;
}

void
Auto_Encoder_Stack::
ifprop(const float * outputs,
       float * temp_space, size_t temp_space_size,
       float * inputs) const
{
    ifprop<float>(outputs, temp_space, temp_space_size, inputs);
}

void
Auto_Encoder_Stack::
ifprop(const double * outputs,
       double * temp_space, size_t temp_space_size,
       double * inputs) const
{
    ifprop<double>(outputs, temp_space, temp_space_size, inputs);
}

template<typename F>
void
Auto_Encoder_Stack::
ifprop(const F * outputs,
       F * temp_space, size_t temp_space_size,
       F * inputs) const
{
    F * temp_space_start = temp_space;
    F * temp_space_end = temp_space_start + temp_space_size;

    const F * curr_outputs = outputs;

    for (int i = size() - 1;  i >= 0;  --i) {
        int layer_temp_space_size
            = layers_[i].ifprop_temporary_space_required();

        F * curr_inputs
            = (i == 0
               ? inputs
               : temp_space + layer_temp_space_size);

        layers_[i].ifprop(curr_outputs, temp_space, layer_temp_space_size,
                           curr_inputs);

        curr_outputs = curr_inputs;

        temp_space += layer_temp_space_size;
        if (i != 0) temp_space += layers_[i].inputs();

        if (temp_space > temp_space_end
            || (i == 0 && temp_space != temp_space_end))
            throw Exception("temp space out of sync");
    }
}

void
Auto_Encoder_Stack::
ibprop(const float * outputs,
       const float * inputs,
       const float * temp_space, size_t temp_space_size,
       const float * input_errors,
       float * output_errors,
       Parameters & gradient,
       double example_weight) const
{
    ibprop<float>(outputs, inputs, temp_space, temp_space_size,
                  input_errors, output_errors, gradient, example_weight);
}

void
Auto_Encoder_Stack::
ibprop(const double * outputs,
       const double * inputs,
       const double * temp_space, size_t temp_space_size,
       const double * input_errors,
       double * output_errors,
       Parameters & gradient,
       double example_weight) const
{
    ibprop<double>(outputs, inputs, temp_space, temp_space_size,
                   input_errors, output_errors, gradient, example_weight);
}

template<typename F>
void
Auto_Encoder_Stack::
ibprop(const F * outputs,
       const F * inputs,
       const F * temp_space, size_t temp_space_size,
       const F * input_errors,
       F * output_errors,
       Parameters & gradient,
       double example_weight) const
{
    int ni = this->inputs(), no = this->outputs();

    CHECK_NOT_NAN_N(outputs, no);
    CHECK_NOT_NAN_N(inputs, ni);
    CHECK_NOT_NAN_N(input_errors, ni);

    const F * temp_space_start = temp_space;
    const F * temp_space_end = temp_space_start + temp_space_size;
    const F * curr_temp_space = temp_space_end;

    const F * curr_inputs = inputs;

    // Storage for the errors kept between the layers
    F error_storage[layers_.max_internal_width()];

    for (int i = 0;  i < layers_.size(); ++i) {
        int layer_temp_space_size
            = layers_[i].ifprop_temporary_space_required();

        curr_temp_space -= layer_temp_space_size;

        const F * curr_outputs
            = (i == size() - 1
               ? outputs
               : curr_temp_space - layers_[i].outputs());

        const F * curr_input_errors
            = (i == 0 ? input_errors : error_storage);

        F * curr_output_errors
            = (i == size() - 1 ? output_errors : error_storage);

        //cerr << "i = " << i << endl;

        layers_[i].ibprop(curr_outputs, curr_inputs, curr_temp_space,
                          layer_temp_space_size, curr_input_errors,
                          curr_output_errors,
                          gradient.subparams(i, layers_[i].name()),
                          example_weight);

        if (curr_temp_space < temp_space_start)
            throw Exception("Layer temp space was out of sync");

        curr_inputs = curr_outputs;
        if (i != layers_.size() - 1) curr_temp_space -= layers_[i].outputs();
    }

    if (curr_temp_space != temp_space_start)
        throw Exception("Layer_Stack::bprop(): out of sync");
}

void
Auto_Encoder_Stack::
random_fill(float limit, Thread_Context & context)
{
    layers_.random_fill(limit, context);
}

void
Auto_Encoder_Stack::
zero_fill()
{
    layers_.zero_fill();
}

size_t
Auto_Encoder_Stack::
parameter_count() const
{
    return layers_.parameter_count();
}

std::pair<float, float>
Auto_Encoder_Stack::
targets(float maximum) const
{
    return layers_.targets(maximum);
}

Auto_Encoder_Stack *
Auto_Encoder_Stack::
make_copy() const
{
    return new Auto_Encoder_Stack(*this);
}

Auto_Encoder_Stack *
Auto_Encoder_Stack::
deep_copy() const
{
    return new Auto_Encoder_Stack(*this, Deep_Copy_Tag());
}

bool
Auto_Encoder_Stack::
equal_impl(const Layer & other) const
{
    if (typeid(*this) != typeid(other)) return false;
    return layers_.equal_impl(other);
}

bool
Auto_Encoder_Stack::
operator == (const Auto_Encoder_Stack & other) const
{
    return layers_.operator == (other.layers_);
}

namespace {

Register_Factory<Layer, Auto_Encoder_Stack>
AES_REGISTER("Auto_Encoder_Stack");

} // file scope

template class Layer_Stack<Auto_Encoder>;

} // namespace ML
<|endoftext|>


<commit_before><commit_msg>fdo#52204 add more diacritics for Arabic<commit_after><|endoftext|>