<commit_before>/* dtkComposerTransmitterReceiver.tpp ---
 *
 * Author: tkloczko
 * Copyright (C) 2011 - Thibaud Kloczko, Inria.
 * Created: Tue Feb 14 12:56:04 2012 (+0100)
 * Version: $Id$
 * Last-Updated: Wed Jun 13 15:07:57 2012 (+0200)
 *           By: tkloczko
 *     Update #: 300
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#ifndef DTKCOMPOSERTRANSMITTERRECEIVER_TPP
#define DTKCOMPOSERTRANSMITTERRECEIVER_TPP

#include "dtkComposerTransmitterEmitter.h"
#include "dtkComposerTransmitterVariant.h"

#include <dtkCore/dtkGlobal.h>

#include <QtCore>

// /////////////////////////////////////////////////////////////////
// dtkComposerTransmitterReceiver implementation
// /////////////////////////////////////////////////////////////////

//! Constructs an empty receiver.
/*!
 *
 */
template <typename T> dtkComposerTransmitterReceiver<T>::dtkComposerTransmitterReceiver(dtkComposerNode *parent) : dtkComposerTransmitter(parent)
{
    T t;

    d->variant = qVariantFromValue(t);

    active_emitter = NULL;
    active_variant = NULL;
};

//! Destroys the receiver.
/*!
 *
 */
template <typename T> dtkComposerTransmitterReceiver<T>::~dtkComposerTransmitterReceiver(void)
{

};

//! Returns the data as a modifiable reference.
/*!
 *
 */
template <typename T> T& dtkComposerTransmitterReceiver<T>::data(void)
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        m_data = qvariant_cast<T>(active_variant->data());

    return m_data;
};

//! Returns the data as a modifiable reference.
/*!
 *
 */
template <typename T> const T& dtkComposerTransmitterReceiver<T>::data(void) const
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        m_data = qvariant_cast<const T>(active_variant->data());

    return m_data;
};

//!
/*!
 *
 */
template <typename T> QVector<T> dtkComposerTransmitterReceiver<T>::allData(void)
{
    QVector<T> list;

    int count = this->emitters.count();

    for(int i = 0; i < count; i++)
        if (this->emitters.at(i)->active()) {
            list << this->emitters.at(i)->data();
        }

    count = this->variants.count();

    for(int i = 0; i < count; i++) {
        if (this->variants.at(i)->active()) {
            list << qvariant_cast<T>(this->variants.at(i)->data());
        }
    }

    return list;
};

//! Returns.
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiver<T>::isEmpty(void) const
{
    if (emitters.isEmpty() && variants.isEmpty())
        return true;

    return false;
};

//! Returns the kind of the transmitter.
/*!
 *
 */
template <typename T> dtkComposerTransmitter::Kind dtkComposerTransmitterReceiver<T>::kind(void) const
{
    return dtkComposerTransmitter::Receiver;
};

template <typename T> QString dtkComposerTransmitterReceiver<T>::kindName(void) const
{
    return "Receiver";
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiver<T>::connect(dtkComposerTransmitter *transmitter)
{
    qDebug() << this->typeName() << transmitter->typeName();

    if (transmitter->kind() == Emitter) {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitter<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitter<T> *>(transmitter);

            if (!emitters.contains(emitter)) {
                emitters << emitter;
                active_emitter = emitter;
                active_variant = NULL;
                emitter->appendReceiver(this);
                return true;
            }
        }

    } else if (transmitter->kind() == Variant) {

        dtkComposerTransmitterVariant *v = dynamic_cast<dtkComposerTransmitterVariant *>(transmitter);

        if (v->types().isEmpty() && !variants.contains(v)) {
            variants << v;
            active_variant = v;
            active_emitter = NULL;
            v->appendReceiver(this);
            return true;
        } else {
            foreach(QVariant::Type t, v->types()) {
                if (t == this->type() && !variants.contains(v)) {
                    variants << v;
                    active_variant = v;
                    active_emitter = NULL;
                    v->appendReceiver(this);
                    return true;
                }
            }
        }
    }

    return false;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiver<T>::disconnect(dtkComposerTransmitter *transmitter)
{
    transmitter->removeReceiver(this);

    bool ok = false;

    if (transmitter->kind() == Variant) {

        dtkComposerTransmitterVariant *v = static_cast<dtkComposerTransmitterVariant *>(transmitter);

        ok = variants.removeOne(v);

        if (v == active_variant) {

            active_variant = NULL;

            foreach(dtkComposerTransmitterVariant *var, variants) {
                if (var->active())
                    active_variant = var;
            }

            if (!active_variant) {
                foreach(dtkComposerTransmitterEmitter<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }
            }
        }

    } else {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitter<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitter<T> *>(transmitter);

            ok = emitters.removeOne(emitter);

            if (emitter == active_emitter) {

                active_emitter = NULL;

                foreach(dtkComposerTransmitterEmitter<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }

                if (!active_emitter) {
                    foreach(dtkComposerTransmitterVariant *var, variants) {
                        if (var->active())
                            active_variant = var;
                    }
                }
            }
        }
    }

    return ok;
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiver<T>::clear(void)
{
    if (active_emitter)
        active_emitter->clear();

    if (active_variant)
        active_variant->clear();
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiver<T>::setActiveEmitter(dtkComposerTransmitter *emitter)
{
    active_emitter = NULL;
    active_variant = NULL;

    foreach(dtkComposerTransmitterEmitter<T> *e, emitters) {
        if (emitter == static_cast<dtkComposerTransmitter *>(e)) {
            active_emitter = e;
            return;
        }
    }

    foreach(dtkComposerTransmitterVariant *v, variants) {
        if (emitter == static_cast<dtkComposerTransmitter *>(v)) {
            active_variant = v;
            return;
        }
    }
}

//!
/*!
 *  All links from every receiver found to \a transmitter are stored
 *  in a multi-hash table.
 *
 *  By default, an empty multi-hash is returned.
 */
template <typename T> dtkComposerTransmitter::LinkMap dtkComposerTransmitterReceiver<T>::rightLinks(dtkComposerTransmitter *transmitter, dtkComposerTransmitterLinkList list)
{
    DTK_UNUSED(transmitter);

    LinkMap link_map;
    foreach(dtkComposerTransmitterLink *l, list)
        link_map.insert(this, l);

    return link_map;
};

// /////////////////////////////////////////////////////////////////
// dtkComposerTransmitterReceiverVector implementation
// /////////////////////////////////////////////////////////////////

template <typename T> inline dtkComposerTransmitterReceiverVector<T>::dtkComposerTransmitterReceiverVector(dtkComposerNode *parent) : dtkComposerTransmitterReceiver<T>(parent)
{

};

template <typename T> inline dtkComposerTransmitterReceiverVector<T>::~dtkComposerTransmitterReceiverVector(void)
{

};

template <typename T> inline dtkContainerVector<T>& dtkComposerTransmitterReceiverVector<T>::data(void)
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        return *reinterpret_cast<dtkContainerVector<T> *>(&(active_variant->container()));

    return m_vector;
};

template <typename T> inline const dtkContainerVector<T>& dtkComposerTransmitterReceiverVector<T>::data(void) const
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        return *reinterpret_cast<const dtkContainerVector<T> *>(&(active_variant->container()));

    return m_vector;
};

//!
/*!
 *
 */
template <typename T> dtkAbstractContainerWrapper& dtkComposerTransmitterReceiverVector<T>::container(void)
{
    if (active_emitter)
        return active_emitter->container();

    if (active_variant)
        return active_variant->container();

    return d->container;
};

//!
/*!
 *
 */
template <typename T> const dtkAbstractContainerWrapper& dtkComposerTransmitterReceiverVector<T>::container(void) const
{
    if (active_emitter)
        return active_emitter->container();

    if (active_variant)
        return active_variant->container();

    return d->container;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiverVector<T>::connect(dtkComposerTransmitter *transmitter)
{
    if (transmitter->kind() == dtkComposerTransmitter::EmitterVector) {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitterVector<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitterVector<T> *>(transmitter);

            if (!emitters.contains(emitter)) {

                emitters << emitter;
                active_emitter = emitter;
                active_variant = NULL;
                emitter->appendReceiver(this);
                return true;
            }
        }

    } else if (transmitter->kind() == dtkComposerTransmitter::VariantContainer) {

        dtkComposerTransmitterVariantContainer *v = dynamic_cast<dtkComposerTransmitterVariantContainer *>(transmitter);

        if(v->types().isEmpty() && !variants.contains(v)) {
            variants << v;
            active_variant = v;
            active_emitter = NULL;
            v->appendReceiver(this);
            return true;
        } else {
            foreach(QVariant::Type t, v->types()) {
                if (t == this->type() && !variants.contains(v)) {
                    variants << v;
                    active_variant = v;
                    active_emitter = NULL;
                    v->appendReceiver(this);
                    return true;
                }
            }
        }
    }

    return false;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiverVector<T>::disconnect(dtkComposerTransmitter *transmitter)
{
    transmitter->removeReceiver(this);

    bool ok = false;

    if (transmitter->kind() == dtkComposerTransmitter::VariantContainer) {

        dtkComposerTransmitterVariantContainer *v = static_cast<dtkComposerTransmitterVariantContainer *>(transmitter);

        ok = variants.removeOne(v);

        if (v == active_variant) {

            active_variant = NULL;

            foreach(dtkComposerTransmitterVariantContainer *var, variants) {
                if (var->active())
                    active_variant = var;
            }

            if (!active_variant) {
                foreach(dtkComposerTransmitterEmitterVector<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }
            }
        }

    } else {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitterVector<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitterVector<T> *>(transmitter);

            ok = emitters.removeOne(emitter);

            if (emitter == active_emitter) {

                active_emitter = NULL;

                foreach(dtkComposerTransmitterEmitterVector<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }

                if (!active_emitter) {
                    foreach(dtkComposerTransmitterVariantContainer *var, variants) {
                        if (var->active())
                            active_variant = var;
                    }
                }
            }
        }
    }

    return ok;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiverVector<T>::isEmpty(void)
{
    if (emitters.isEmpty() && variants.isEmpty())
        return true;

    return false;
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiverVector<T>::clear(void)
{
    if (active_emitter)
        active_emitter->clear();

    if (active_variant)
        active_variant->clear();
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiverVector<T>::setActiveEmitter(dtkComposerTransmitter *emitter)
{
    active_emitter = NULL;
    active_variant = NULL;

    foreach(dtkComposerTransmitterEmitterVector<T> *e, emitters) {
        if (emitter == static_cast<dtkComposerTransmitter *>(e)) {
            active_emitter = e;
            return;
        }
    }

    foreach(dtkComposerTransmitterVariantContainer *v, variants) {
        if (emitter == static_cast<dtkComposerTransmitter *>(v)) {
            active_variant = v;
            return;
        }
    }
}

#endif
<commit_msg>Fix bug correction...<commit_after>/* dtkComposerTransmitterReceiver.tpp ---
 *
 * Author: tkloczko
 * Copyright (C) 2011 - Thibaud Kloczko, Inria.
 * Created: Tue Feb 14 12:56:04 2012 (+0100)
 * Version: $Id$
 * Last-Updated: Wed Jun 13 15:10:02 2012 (+0200)
 *           By: tkloczko
 *     Update #: 301
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#ifndef DTKCOMPOSERTRANSMITTERRECEIVER_TPP
#define DTKCOMPOSERTRANSMITTERRECEIVER_TPP

#include "dtkComposerTransmitterEmitter.h"
#include "dtkComposerTransmitterVariant.h"

#include <dtkCore/dtkGlobal.h>

#include <QtCore>

// /////////////////////////////////////////////////////////////////
// dtkComposerTransmitterReceiver implementation
// /////////////////////////////////////////////////////////////////

//! Constructs an empty receiver.
/*!
 *
 */
template <typename T> dtkComposerTransmitterReceiver<T>::dtkComposerTransmitterReceiver(dtkComposerNode *parent) : dtkComposerTransmitter(parent)
{
    T t;

    d->variant = qVariantFromValue(t);

    active_emitter = NULL;
    active_variant = NULL;
};

//! Destroys the receiver.
/*!
 *
 */
template <typename T> dtkComposerTransmitterReceiver<T>::~dtkComposerTransmitterReceiver(void)
{

};

//! Returns the data as a modifiable reference.
/*!
 *
 */
template <typename T> T& dtkComposerTransmitterReceiver<T>::data(void)
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        m_data = qvariant_cast<T>(active_variant->data());

    return m_data;
};

//! Returns the data as a modifiable reference.
/*!
 *
 */
template <typename T> const T& dtkComposerTransmitterReceiver<T>::data(void) const
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        m_data = qvariant_cast<const T>(active_variant->data());

    return m_data;
};

//!
/*!
 *
 */
template <typename T> QVector<T> dtkComposerTransmitterReceiver<T>::allData(void)
{
    QVector<T> list;

    int count = this->emitters.count();

    for(int i = 0; i < count; i++)
        if (this->emitters.at(i)->active()) {
            list << this->emitters.at(i)->data();
        }

    count = this->variants.count();

    for(int i = 0; i < count; i++) {
        if (this->variants.at(i)->active()) {
            list << qvariant_cast<T>(this->variants.at(i)->data());
        }
    }

    return list;
};

//! Returns.
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiver<T>::isEmpty(void) const
{
    if (emitters.isEmpty() && variants.isEmpty())
        return true;

    return false;
};

//! Returns the kind of the transmitter.
/*!
 *
 */
template <typename T> dtkComposerTransmitter::Kind dtkComposerTransmitterReceiver<T>::kind(void) const
{
    return dtkComposerTransmitter::Receiver;
};

template <typename T> QString dtkComposerTransmitterReceiver<T>::kindName(void) const
{
    return "Receiver";
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiver<T>::connect(dtkComposerTransmitter *transmitter)
{
    qDebug() << this->typeName() << transmitter->typeName();

    if (transmitter->kind() == Emitter) {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitter<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitter<T> *>(transmitter);

            if (!emitters.contains(emitter)) {
                emitters << emitter;
                active_emitter = emitter;
                active_variant = NULL;
                emitter->appendReceiver(this);
                return true;
            }
        }

    } else if (transmitter->kind() == Variant) {

        dtkComposerTransmitterVariant *v = dynamic_cast<dtkComposerTransmitterVariant *>(transmitter);

        if (v->types().isEmpty() && !variants.contains(v)) {
            variants << v;
            active_variant = v;
            active_emitter = NULL;
            v->appendReceiver(this);
            return true;
        } else {
            foreach(QVariant::Type t, v->types()) {
                if (t == this->type() && !variants.contains(v)) {
                    variants << v;
                    active_variant = v;
                    active_emitter = NULL;
                    v->appendReceiver(this);
                    return true;
                }
            }
        }
    }

    return false;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiver<T>::disconnect(dtkComposerTransmitter *transmitter)
{
    transmitter->removeReceiver(this);

    bool ok = false;

    if (transmitter->kind() == Variant) {

        dtkComposerTransmitterVariant *v = static_cast<dtkComposerTransmitterVariant *>(transmitter);

        ok = variants.removeOne(v);

        if (v == active_variant) {

            active_variant = NULL;

            foreach(dtkComposerTransmitterVariant *var, variants) {
                if (var->active())
                    active_variant = var;
            }

            if (!active_variant) {
                foreach(dtkComposerTransmitterEmitter<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }
            }
        }

    } else {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitter<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitter<T> *>(transmitter);

            ok = emitters.removeOne(emitter);

            if (emitter == active_emitter) {

                active_emitter = NULL;

                foreach(dtkComposerTransmitterEmitter<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }

                if (!active_emitter) {
                    foreach(dtkComposerTransmitterVariant *var, variants) {
                        if (var->active())
                            active_variant = var;
                    }
                }
            }
        }
    }

    return ok;
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiver<T>::clear(void)
{
    if (active_emitter)
        active_emitter->clear();

    if (active_variant)
        active_variant->clear();
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiver<T>::setActiveEmitter(dtkComposerTransmitter *emitter)
{
    active_emitter = NULL;
    active_variant = NULL;

    foreach(dtkComposerTransmitterEmitter<T> *e, emitters) {
        if (emitter == static_cast<dtkComposerTransmitter *>(e)) {
            active_emitter = e;
            return;
        }
    }

    foreach(dtkComposerTransmitterVariant *v, variants) {
        if (emitter == static_cast<dtkComposerTransmitter *>(v)) {
            active_variant = v;
            return;
        }
    }
}

//!
/*!
 *  All links from every receiver found to \a transmitter are stored
 *  in a multi-hash table.
 *
 *  By default, an empty multi-hash is returned.
 */
template <typename T> dtkComposerTransmitter::LinkMap dtkComposerTransmitterReceiver<T>::rightLinks(dtkComposerTransmitter *transmitter, dtkComposerTransmitterLinkList list)
{
    DTK_UNUSED(transmitter);

    LinkMap link_map;
    foreach(dtkComposerTransmitterLink *l, list)
        link_map.insert(this, l);

    return link_map;
};

// /////////////////////////////////////////////////////////////////
// dtkComposerTransmitterReceiverVector implementation
// /////////////////////////////////////////////////////////////////

template <typename T> inline dtkComposerTransmitterReceiverVector<T>::dtkComposerTransmitterReceiverVector(dtkComposerNode *parent) : dtkComposerTransmitterReceiver<T>(parent)
{

};

template <typename T> inline dtkComposerTransmitterReceiverVector<T>::~dtkComposerTransmitterReceiverVector(void)
{

};

template <typename T> inline dtkContainerVector<T>& dtkComposerTransmitterReceiverVector<T>::data(void)
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        return *reinterpret_cast<dtkContainerVector<T> *>(&(active_variant->container()));

    return m_vector;
};

template <typename T> inline const dtkContainerVector<T>& dtkComposerTransmitterReceiverVector<T>::data(void) const
{
    if (active_emitter)
        return active_emitter->data();

    if (active_variant)
        return *reinterpret_cast<const dtkContainerVector<T> *>(&(active_variant->container()));

    return m_vector;
};

//!
/*!
 *
 */
template <typename T> dtkAbstractContainerWrapper& dtkComposerTransmitterReceiverVector<T>::container(void)
{
    if (active_emitter)
        return active_emitter->container();

    if (active_variant)
        return active_variant->container();

    return d->container;
};

//!
/*!
 *
 */
template <typename T> const dtkAbstractContainerWrapper& dtkComposerTransmitterReceiverVector<T>::container(void) const
{
    if (active_emitter)
        return active_emitter->container();

    if (active_variant)
        return active_variant->container();

    return d->container;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiverVector<T>::connect(dtkComposerTransmitter *transmitter)
{
    if (transmitter->kind() == dtkComposerTransmitter::EmitterVector) {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitterVector<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitterVector<T> *>(transmitter);

            if (!emitters.contains(emitter)) {

                emitters << emitter;
                active_emitter = emitter;
                active_variant = NULL;
                emitter->appendReceiver(this);
                return true;
            }
        }

    } else if (transmitter->kind() == dtkComposerTransmitter::VariantContainer) {

        dtkComposerTransmitterVariantContainer *v = dynamic_cast<dtkComposerTransmitterVariantContainer *>(transmitter);

        if(v->types().isEmpty() && !variants.contains(v)) {
            variants << v;
            active_variant = v;
            active_emitter = NULL;
            v->appendReceiver(this);
            return true;
        } else {
            foreach(QVariant::Type t, v->types()) {
                if (t == this->type() && !variants.contains(v)) {
                    variants << v;
                    active_variant = v;
                    active_emitter = NULL;
                    v->appendReceiver(this);
                    return true;
                }
            }
        }
    }

    return false;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiverVector<T>::disconnect(dtkComposerTransmitter *transmitter)
{
    transmitter->removeReceiver(this);

    bool ok = false;

    if (transmitter->kind() == dtkComposerTransmitter::VariantContainer) {

        dtkComposerTransmitterVariantContainer *v = static_cast<dtkComposerTransmitterVariantContainer *>(transmitter);

        ok = variants.removeOne(v);

        if (v == active_variant) {

            active_variant = NULL;

            foreach(dtkComposerTransmitterVariantContainer *var, variants) {
                if (var->active())
                    active_variant = var;
            }

            if (!active_variant) {
                foreach(dtkComposerTransmitterEmitterVector<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }
            }
        }

    } else {

        if (this->typeName() == transmitter->typeName()) {

            dtkComposerTransmitterEmitterVector<T> *emitter = reinterpret_cast<dtkComposerTransmitterEmitterVector<T> *>(transmitter);

            ok = emitters.removeOne(emitter);

            if (emitter == active_emitter) {

                active_emitter = NULL;

                foreach(dtkComposerTransmitterEmitterVector<T> *em, emitters) {
                    if (em->active())
                        active_emitter = em;
                }

                if (!active_emitter) {
                    foreach(dtkComposerTransmitterVariantContainer *var, variants) {
                        if (var->active())
                            active_variant = var;
                    }
                }
            }
        }
    }

    return ok;
};

//!
/*!
 *
 */
template <typename T> bool dtkComposerTransmitterReceiverVector<T>::isEmpty(void) const
{
    if (emitters.isEmpty() && variants.isEmpty())
        return true;

    return false;
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiverVector<T>::clear(void)
{
    if (active_emitter)
        active_emitter->clear();

    if (active_variant)
        active_variant->clear();
};

//!
/*!
 *
 */
template <typename T> void dtkComposerTransmitterReceiverVector<T>::setActiveEmitter(dtkComposerTransmitter *emitter)
{
    active_emitter = NULL;
    active_variant = NULL;

    foreach(dtkComposerTransmitterEmitterVector<T> *e, emitters) {
        if (emitter == static_cast<dtkComposerTransmitter *>(e)) {
            active_emitter = e;
            return;
        }
    }

    foreach(dtkComposerTransmitterVariantContainer *v, variants) {
        if (emitter == static_cast<dtkComposerTransmitter *>(v)) {
            active_variant = v;
            return;
        }
    }
}

#endif
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// Copyright (c) 2016 by contributors. All Rights Reserved.
//
// 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.
//------------------------------------------------------------------------------

/*
Author: Chao Ma (mctt90@gmail.com)
This file is the implementation of LinearScore class.
*/

#include "src/score/linear_score_ftrl.h"
#include "src/base/math.h"

namespace xLearn {

// y = wTx (incluing bias term)
real_t LinearScoreFtrl::CalcScore(const SparseRow* row,
                              Model& model,
                              real_t norm) {
  real_t* w = model.GetParameter_w();
  real_t score = 0.0;
  for (SparseRow::const_iterator iter = row->begin();
       iter != row->end(); ++iter) {
    index_t idx = iter->feat_id * 3;
    score += w[idx] * iter->feat_val;
  }
  // bias
  score += model.GetParameter_b()[0];
  return score;
}

// Calculate gradient and update current model
void LinearScoreFtrl::CalcGrad(const SparseRow* row,
                           Model& model,
                           real_t pg,
                           real_t norm) {
  real_t alpha = 1.0;
  real_t beta = 1.0;
  real_t lambda1 = 1.0;
  real_t lambda2 = 1.0;
  real_t* w = model.GetParameter_w();
  for (SparseRow::const_iterator iter = row->begin();
       iter != row->end(); ++iter) {
    real_t gradient = pg * iter->feat_val;
    index_t idx_w = iter->feat_id * 3; // index of w_i
    index_t idx_n = idx_w + 1; // index of cumulate for gradient * gradient
    index_t idx_z = idx_w + 2; // index of cumulater for gradient
    real_t old_n = w[idx_n]; // old n_i
    w[idx_n] += (gradient * gradient); // new n_i
    real_t sigma = 1.0f * (std::sqrt(w[idx_n]) - sqrt(old_n))
                    / alpha;
    w[idx_z] += gradient - sigma * w[idx_w];
    // above had calculate n_i and z_i
    // below update gradient by n_i and z_i
    if (std::abs(w[idx_z]) <= lambda1) {
      w[idx_w] = 0.0;
    } else {
      real_t smooth_lr = 1.0f
                         / (lambda2 + (beta + std::sqrt(w[idx_n])) / alpha);
      if (w[idx_z] < 0) {
        w[idx_z] += lambda1;
      } else {
        w[idx_z] -= lambda1;
      }
      w[idx_w] = -1.0f * smooth_lr * w[idx_z];
    }
  }
  // bias
  w = model.GetParameter_b();
  real_t &wb = w[0];
  real_t &wbn = w[1];
  real_t &wbz = w[2];
  real_t g = pg;
  wbn += g*g;
  wbz += g;
  if (std::abs(wbz) <= lambda1) {
    wb = 0.0f;
  } else {
    real_t smooth_lr = 1.0f
                       / (lambda2 + (beta + std::sqrt(wbn)) / alpha);
    if (wbz < 0) {
      wbz += lambda1;
    } else {
      wbz -= lambda1;
    }
    wb = -1.0f * smooth_lr * wbz;
  }
}

} // namespace xLearn
<commit_msg>fix: linear_score_ftrl calcGrad<commit_after>//------------------------------------------------------------------------------
// Copyright (c) 2016 by contributors. All Rights Reserved.
//
// 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.
//------------------------------------------------------------------------------

/*
Author: Chao Ma (mctt90@gmail.com)
This file is the implementation of LinearScore class.
*/

#include "src/score/linear_score_ftrl.h"
#include "src/base/math.h"

namespace xLearn {

// y = wTx (incluing bias term)
real_t LinearScoreFtrl::CalcScore(const SparseRow* row,
                              Model& model,
                              real_t norm) {
  real_t* w = model.GetParameter_w();
  real_t score = 0.0;
  for (SparseRow::const_iterator iter = row->begin();
       iter != row->end(); ++iter) {
    index_t idx = iter->feat_id * 3;
    score += w[idx] * iter->feat_val;
  }
  // bias
  score += model.GetParameter_b()[0];
  return score;
}

// Calculate gradient and update current model
void LinearScoreFtrl::CalcGrad(const SparseRow* row,
                           Model& model,
                           real_t pg,
                           real_t norm) {
  real_t alpha = 1.0;
  real_t beta = 1.0;
  real_t lambda1 = 1.0;
  real_t lambda2 = 1.0;
  real_t* w = model.GetParameter_w();
  for (SparseRow::const_iterator iter = row->begin();
       iter != row->end(); ++iter) {
    real_t gradient = pg * iter->feat_val;
    index_t idx_w = iter->feat_id * 3; // index of w_i
    index_t idx_n = idx_w + 1; // index of cumulate for gradient * gradient
    index_t idx_z = idx_w + 2; // index of cumulater for gradient
    real_t old_n = w[idx_n]; // old n_i
    w[idx_n] += (gradient * gradient); // new n_i
    real_t sigma = 1.0f * (std::sqrt(w[idx_n]) - sqrt(old_n))
                    / alpha;
    w[idx_z] += gradient - sigma * w[idx_w];
    // above had calculate n_i and z_i
    // below update gradient by n_i and z_i
    if (std::abs(w[idx_z]) <= lambda1) {
      w[idx_w] = 0.0;
    } else {
      real_t smooth_lr = 1.0f
                         / (lambda2 + (beta + std::sqrt(w[idx_n])) / alpha);
      if (w[idx_z] < 0.0) {
        w[idx_z] += lambda1;
      } else if (w[idx_z] > 0.0) {
        w[idx_z] -= lambda1;
      }
      w[idx_w] = -1.0f * smooth_lr * w[idx_z];
    }
  }
  // bias
  w = model.GetParameter_b();
  real_t &wb = w[0];
  real_t &wbn = w[1];
  real_t &wbz = w[2];
  real_t g = pg;
  wbn += g*g;
  wbz += g;
  if (std::abs(wbz) <= lambda1) {
    wb = 0.0f;
  } else {
    real_t smooth_lr = 1.0f
                       / (lambda2 + (beta + std::sqrt(wbn)) / alpha);
    if (wbz < 0.0) {
      wbz += lambda1;
    } else if(wbz > 0.0) {
      wbz -= lambda1;
    }
    wb = -1.0f * smooth_lr * wbz;
  }
}

} // namespace xLearn
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC. All Rights Reserved.
/*
   Copyright (C) 2005 Steven L. Scott

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

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

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

#include <cmath>
#include <sstream>
#include "cpputil/math_utils.hpp"
#include "cpputil/report_error.hpp"
#include "distributions.hpp"

/* functions for the triangular distribution over the interval (x0,
   x1) with breakpoint xm */

namespace BOOM {
  double rtriangle(double x0, double x1, double xm) {
    return rtriangle_mt(GlobalRng::rng, x0, x1, xm);
  }

  double rtriangle_mt(RNG& rng, double x0, double x1, double xm) {
    /* simulates from the noncentral triangle distribution on the
       interval (x0, x1) with a break at xm.  If xm < x0 || xm > x1 then
       xm is taken to be the midpoint of the interval.
    */

    double y, m0, m1, a0, u;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in rtriangle_mt: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "x0 must be less than x1";
      report_error(err.str());
    } else if (x0 == x1)
      return x0;

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;

    y = 2.0 / (x1 - x0);
    m0 = y / (xm - x0);
    m1 = y / (xm - x1);

    a0 = 0.5 * y * (xm - x0);
    u = runif_mt(rng, 0, 1);

    double ans = 0;
    if (!std::isfinite(a0)) {
      report_error("an unknown error occurred in rtriangle_mt");
    }

    if (u < a0) {
      ans = x0 + sqrt(2 * u / m0); /* area of left right triangle */
    } else {
      ans = x1 - sqrt(-2.0 * (1 - u) / m1); /* area of right right triangle */
    }
    return ans;
  }
  /*======================================================================*/
  double dtriangle(double x, double x0, double x1, double xm, bool logscale) {
    double m0, m1, y, ans;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in dtriangle: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "logscale = " << logscale << std::endl
          << "x0 must be less than x1";

      report_error(err.str());
    }
    if (x0 == x1) return x0;

    if (x < x0 || x > x1) return (logscale ? negative_infinity() : 0);

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;
    y = 2.0 / (x1 - x0);
    m0 = y / (xm - x0);
    m1 = y / (xm - x1);
    ans = (x < xm ? m0 * (x - x0) : m1 * (x - x1));
    return (logscale ? log(ans) : ans);
  }
  /*======================================================================*/
  double ptriangle(double x, double x0, double x1, double xm, bool lower_tail) {
    double y;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in ptriangle: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "x0 must be less than x1";
      report_error(err.str());
    } else if (x0 == x1)
      return x0;

    if (x < x0) return lower_tail ? 0.0 : 1.0;
    if (x > x1) return lower_tail ? 1.0 : 0.0;

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;
    y = 2.0 / (x1 - x0);

    double ans = 0;
    if (x <= xm) {
      x -= x0;
      double m0 = y / (xm - x0);
      double a0 = 0.5 * m0 * x * x;
      ans = lower_tail ? a0 : 1 - a0;
    } else if (x > xm) {
      double m1 = y / (xm - x1);
      double b = 0.5 * m1 * (x - x1) * (x1 - x);
      ans = lower_tail ? b : 1 - b;
    } else
      report_error("an unknown error occurred in ptrigangle");

    return ans;
  }
  /*======================================================================*/
  double qtriangle(double p, double x0, double x1, double xm) {
    double y, m0, m1, a0;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in qtriangle: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "x0 must be less than x1";
      report_error(err.str());
    } else if (x0 == x1)
      return x0;

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;

    y = 2.0 / (x1 - x0);
    m0 = y / (xm - x0);
    m1 = y / (xm - x1);

    a0 = 0.5 * y * (xm - x0);

    double ans = 0;
    if (!std::isfinite(p)) {
      report_error("Non finite value for p in qtriangle.");
    } else if (!std::isfinite(a0)) {
      report_error("Nonfinite value for a0 in qtriangle.");
    } else if (p < a0) {
      ans = x0 + sqrt(2 * p / m0); /* area of left right triangle */
    } else {
      ans = x1 - sqrt(-2.0 * (1 - p) / m1); /* area of right right triangle */
    }
    return ans;
  }

}  // namespace BOOM
<commit_msg>Should be the final codacy code quality issue.<commit_after>// Copyright 2018 Google LLC. All Rights Reserved.
/*
   Copyright (C) 2005 Steven L. Scott

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

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

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

#include <cmath>
#include <sstream>
#include "cpputil/math_utils.hpp"
#include "cpputil/report_error.hpp"
#include "distributions.hpp"

/* functions for the triangular distribution over the interval (x0,
   x1) with breakpoint xm */

namespace BOOM {
  double rtriangle(double x0, double x1, double xm) {
    return rtriangle_mt(GlobalRng::rng, x0, x1, xm);
  }

  double rtriangle_mt(RNG& rng, double x0, double x1, double xm) {
    /* simulates from the noncentral triangle distribution on the
       interval (x0, x1) with a break at xm.  If xm < x0 || xm > x1 then
       xm is taken to be the midpoint of the interval.
    */

    double y, m0, m1, a0, u;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in rtriangle_mt: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "x0 must be less than x1";
      report_error(err.str());
    } else if (x0 == x1)
      return x0;

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;

    y = 2.0 / (x1 - x0);
    m0 = y / (xm - x0);
    m1 = y / (xm - x1);

    a0 = 0.5 * y * (xm - x0);
    u = runif_mt(rng, 0, 1);

    double ans = 0;
    if (!std::isfinite(a0)) {
      report_error("an unknown error occurred in rtriangle_mt");
    }

    if (u < a0) {
      ans = x0 + sqrt(2 * u / m0); /* area of left right triangle */
    } else {
      ans = x1 - sqrt(-2.0 * (1 - u) / m1); /* area of right right triangle */
    }
    return ans;
  }
  /*======================================================================*/
  double dtriangle(double x, double x0, double x1, double xm, bool logscale) {
    double m0, m1, y, ans;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in dtriangle: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "logscale = " << logscale << std::endl
          << "x0 must be less than x1";

      report_error(err.str());
    }
    if (x0 == x1) return x0;

    if (x < x0 || x > x1) return (logscale ? negative_infinity() : 0);

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;
    y = 2.0 / (x1 - x0);
    m0 = y / (xm - x0);
    m1 = y / (xm - x1);
    ans = (x < xm ? m0 * (x - x0) : m1 * (x - x1));
    return (logscale ? log(ans) : ans);
  }
  /*======================================================================*/
  double ptriangle(double x, double x0, double x1, double xm, bool lower_tail) {
    double y;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in ptriangle: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "x0 must be less than x1";
      report_error(err.str());
    } else if (x0 == x1)
      return x0;

    if (x < x0) return lower_tail ? 0.0 : 1.0;
    if (x > x1) return lower_tail ? 1.0 : 0.0;

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;
    y = 2.0 / (x1 - x0);

    double ans = 0;
    if (!std::isfinite(x) || !std::isfinite(xm)) {
      report_error("Non-finite inputs to ptriangle.");
    } else if (x <= xm) {
      x -= x0;
      double m0 = y / (xm - x0);
      double a0 = 0.5 * m0 * x * x;
      ans = lower_tail ? a0 : 1 - a0;
    } else {
      double m1 = y / (xm - x1);
      double b = 0.5 * m1 * (x - x1) * (x1 - x);
      ans = lower_tail ? b : 1 - b;
    }
    return ans;
  }
  /*======================================================================*/
  double qtriangle(double p, double x0, double x1, double xm) {
    double y, m0, m1, a0;

    if (x1 < x0) {
      std::ostringstream err;
      err << "error in qtriangle: called with" << std::endl
          << "x0 = " << x0 << std::endl
          << "x1 = " << x1 << std::endl
          << "xm = " << xm << std::endl
          << "x0 must be less than x1";
      report_error(err.str());
    } else if (x0 == x1)
      return x0;

    if (xm < x0 || xm > x1) xm = (x0 + x1) / 2.0;

    y = 2.0 / (x1 - x0);
    m0 = y / (xm - x0);
    m1 = y / (xm - x1);

    a0 = 0.5 * y * (xm - x0);

    double ans = 0;
    if (!std::isfinite(p)) {
      report_error("Non finite value for p in qtriangle.");
    } else if (!std::isfinite(a0)) {
      report_error("Nonfinite value for a0 in qtriangle.");
    } else if (p < a0) {
      ans = x0 + sqrt(2 * p / m0); /* area of left right triangle */
    } else {
      ans = x1 - sqrt(-2.0 * (1 - p) / m1); /* area of right right triangle */
    }
    return ans;
  }

}  // namespace BOOM
<|endoftext|>


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

/* Author: Ioan Sucan */

#include "ompl/geometric/planners/kpiece/KPIECE1.h"
#include "ompl/base/GoalSampleableRegion.h"
#include <limits>
#include <cassert>

void ompl::geometric::KPIECE1::setup(void)
{
    Planner::setup();
    checkProjectionEvaluator(this, projectionEvaluator_);
    checkMotionLength(this, maxDistance_);

    if (badScoreFactor_ < std::numeric_limits<double>::epsilon() || badScoreFactor_ > 1.0)
        throw Exception("Bad cell score factor must be in the range (0,1]");
    if (goodScoreFactor_ < std::numeric_limits<double>::epsilon() || goodScoreFactor_ > 1.0)
        throw Exception("Good cell score factor must be in the range (0,1]");
    if (minValidPathFraction_ < std::numeric_limits<double>::epsilon() || minValidPathFraction_ > 1.0)
        throw Exception("The minimum valid path fraction must be in the range (0,1]");
    if (selectBorderFraction_ < std::numeric_limits<double>::epsilon() || selectBorderFraction_ > 1.0)
        throw Exception("The fraction of time spent selecting border cells must be in the range (0,1]");

    tree_.grid.setDimension(projectionEvaluator_->getDimension());
}

void ompl::geometric::KPIECE1::clear(void)
{
    Planner::clear();
    sampler_.reset();
    freeMemory();
    tree_.grid.clear();
    tree_.size = 0;
    tree_.iteration = 1;
}

void ompl::geometric::KPIECE1::freeMemory(void)
{
    freeGridMotions(tree_.grid);
}

void ompl::geometric::KPIECE1::freeGridMotions(Grid &grid)
{
    for (Grid::iterator it = grid.begin(); it != grid.end() ; ++it)
        freeCellData(it->second->data);
}

void ompl::geometric::KPIECE1::freeCellData(CellData *cdata)
{
    for (unsigned int i = 0 ; i < cdata->motions.size() ; ++i)
        freeMotion(cdata->motions[i]);
    delete cdata;
}

void ompl::geometric::KPIECE1::freeMotion(Motion *motion)
{
    if (motion->state)
        si_->freeState(motion->state);
    delete motion;
}

bool ompl::geometric::KPIECE1::solve(const base::PlannerTerminationCondition &ptc)
{
    checkValidity();
    base::Goal                   *goal = pdef_->getGoal().get();
    base::GoalRegion           *goal_r = dynamic_cast<base::GoalRegion*>(goal);
    base::GoalSampleableRegion *goal_s = dynamic_cast<base::GoalSampleableRegion*>(goal);

    if (!goal)
    {
        msg_.error("Goal undefined");
        return false;
    }

    while (const base::State *st = pis_.nextStart())
    {
        Motion *motion = new Motion(si_);
        si_->copyState(motion->state, st);
        addMotion(motion, 1.0);
    }

    if (tree_.grid.size() == 0)
    {
        msg_.error("There are no valid initial states!");
        return false;
    }

    if (!sampler_)
        sampler_ = si_->allocManifoldStateSampler();

    msg_.inform("Starting with %u states", tree_.size);

    Motion *solution  = NULL;
    Motion *approxsol = NULL;
    double  approxdif = std::numeric_limits<double>::infinity();
    base::State *xstate = si_->allocState();
    Grid::Coord  xcoord;

    double improveValue = maxDistance_;

    while (ptc() == false)
    {
        tree_.iteration++;

        /* Decide on a state to expand from */
        Motion     *existing = NULL;
        Grid::Cell *ecell = NULL;
        selectMotion(existing, ecell);
        assert(existing);

        /* sample random state (with goal biasing) */
        if (rng_.uniform01() < goalBias_)
        {
            if (goal_s && goal_s->canSample())
                goal_s->sampleGoal(xstate);
            else
            {
                if (approxsol && goal_r)
                {
                    si_->copyState(xstate, approxsol->state);
                    msg_.debug("Start Running HCIK (%f)...", improveValue);
                    if (hcik_.tryToImprove(*goal_r, xstate, improveValue))
                        improveValue /= 2.0;
                    else
                        sampler_->sampleUniformNear(xstate, existing->state, maxDistance_);
                    msg_.debug("End Running HCIK");
                }
                else
                    sampler_->sampleUniformNear(xstate, existing->state, maxDistance_);
            }
        }
        else
            sampler_->sampleUniformNear(xstate, existing->state, maxDistance_);

        std::pair<base::State*, double> fail(xstate, 0.0);
        bool keep = si_->checkMotion(existing->state, xstate, fail);
        if (!keep && fail.second > minValidPathFraction_)
            keep = true;

        if (keep)
        {
            /* create a motion */
            Motion *motion = new Motion(si_);
            si_->copyState(motion->state, xstate);
            motion->parent = existing;

            double dist = 0.0;
            bool solved = goal->isSatisfied(motion->state, &dist);
            addMotion(motion, dist);

            if (solved)
            {
                approxdif = dist;
                solution = motion;
                break;
            }
            if (dist < approxdif)
            {
                approxdif = dist;
                approxsol = motion;
            }
            ecell->data->score *= goodScoreFactor_;
        }
        else
            ecell->data->score *= badScoreFactor_;

        tree_.grid.update(ecell);
    }

    bool approximate = false;
    if (solution == NULL)
    {
        solution = approxsol;
        approximate = true;
    }

    if (solution != NULL)
    {
        /* construct the solution path */
        std::vector<Motion*> mpath;
        while (solution != NULL)
        {
            mpath.push_back(solution);
            solution = solution->parent;
        }

        /* set the solution path */
        PathGeometric *path = new PathGeometric(si_);
           for (int i = mpath.size() - 1 ; i >= 0 ; --i)
            path->states.push_back(si_->cloneState(mpath[i]->state));
        goal->setDifference(approxdif);
        goal->setSolutionPath(base::PathPtr(path), approximate);

        if (approximate)
            msg_.warn("Found approximate solution");
    }

    si_->freeState(xstate);

    msg_.inform("Created %u states in %u cells (%u internal + %u external)", tree_.size, tree_.grid.size(),
                 tree_.grid.countInternal(), tree_.grid.countExternal());

    return goal->isAchieved();
}

bool ompl::geometric::KPIECE1::selectMotion(Motion* &smotion, Grid::Cell* &scell)
{
    scell = rng_.uniform01() < std::max(selectBorderFraction_, tree_.grid.fracExternal()) ?
        tree_.grid.topExternal() : tree_.grid.topInternal();

    // We are running on finite precision, so our update scheme will end up
    // with 0 values for the score. This is where we fix the problem
    if (scell->data->score < std::numeric_limits<double>::epsilon())
    {
        std::vector<CellData*> content;
        content.reserve(tree_.grid.size());
        tree_.grid.getContent(content);
        for (std::vector<CellData*>::iterator it = content.begin() ; it != content.end() ; ++it)
            (*it)->score += 1.0 + log((double)((*it)->iteration));
        tree_.grid.updateAll();
    }

    if (scell && !scell->data->motions.empty())
    {
        scell->data->selections++;
        smotion = scell->data->motions[rng_.halfNormalInt(0, scell->data->motions.size() - 1)];
        return true;
    }
    else
        return false;
}

unsigned int ompl::geometric::KPIECE1::addMotion(Motion *motion, double dist)
{
    Grid::Coord coord;
    projectionEvaluator_->computeCoordinates(motion->state, coord);
    Grid::Cell* cell = tree_.grid.getCell(coord);
    unsigned int created = 0;
    if (cell)
    {
        cell->data->motions.push_back(motion);
        cell->data->coverage += 1.0;
        tree_.grid.update(cell);
    }
    else
    {
        cell = tree_.grid.createCell(coord);
        cell->data = new CellData();
        cell->data->motions.push_back(motion);
        cell->data->coverage = 1.0;
        cell->data->iteration = tree_.iteration;
        cell->data->selections = 1;
        cell->data->score = (1.0 + log((double)(tree_.iteration))) / (1e-3 + dist);
        tree_.grid.add(cell);
        created = 1;
    }
    tree_.size++;
    return created;
}

void ompl::geometric::KPIECE1::getPlannerData(base::PlannerData &data) const
{
    Planner::getPlannerData(data);

    std::vector<CellData*> cdata;
    tree_.grid.getContent(cdata);
    for (unsigned int i = 0 ; i < cdata.size() ; ++i)
        for (unsigned int j = 0 ; j < cdata[i]->motions.size() ; ++j)
            data.recordEdge(cdata[i]->motions[j]->parent ? cdata[i]->motions[j]->parent->state : NULL, cdata[i]->motions[j]->state);
}
<commit_msg>limit the range for hill climbing search<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2008, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ioan Sucan */

#include "ompl/geometric/planners/kpiece/KPIECE1.h"
#include "ompl/base/GoalSampleableRegion.h"
#include <limits>
#include <cassert>

void ompl::geometric::KPIECE1::setup(void)
{
    Planner::setup();
    checkProjectionEvaluator(this, projectionEvaluator_);
    checkMotionLength(this, maxDistance_);

    if (badScoreFactor_ < std::numeric_limits<double>::epsilon() || badScoreFactor_ > 1.0)
        throw Exception("Bad cell score factor must be in the range (0,1]");
    if (goodScoreFactor_ < std::numeric_limits<double>::epsilon() || goodScoreFactor_ > 1.0)
        throw Exception("Good cell score factor must be in the range (0,1]");
    if (minValidPathFraction_ < std::numeric_limits<double>::epsilon() || minValidPathFraction_ > 1.0)
        throw Exception("The minimum valid path fraction must be in the range (0,1]");
    if (selectBorderFraction_ < std::numeric_limits<double>::epsilon() || selectBorderFraction_ > 1.0)
        throw Exception("The fraction of time spent selecting border cells must be in the range (0,1]");

    tree_.grid.setDimension(projectionEvaluator_->getDimension());
}

void ompl::geometric::KPIECE1::clear(void)
{
    Planner::clear();
    sampler_.reset();
    freeMemory();
    tree_.grid.clear();
    tree_.size = 0;
    tree_.iteration = 1;
}

void ompl::geometric::KPIECE1::freeMemory(void)
{
    freeGridMotions(tree_.grid);
}

void ompl::geometric::KPIECE1::freeGridMotions(Grid &grid)
{
    for (Grid::iterator it = grid.begin(); it != grid.end() ; ++it)
        freeCellData(it->second->data);
}

void ompl::geometric::KPIECE1::freeCellData(CellData *cdata)
{
    for (unsigned int i = 0 ; i < cdata->motions.size() ; ++i)
        freeMotion(cdata->motions[i]);
    delete cdata;
}

void ompl::geometric::KPIECE1::freeMotion(Motion *motion)
{
    if (motion->state)
        si_->freeState(motion->state);
    delete motion;
}

bool ompl::geometric::KPIECE1::solve(const base::PlannerTerminationCondition &ptc)
{
    checkValidity();
    base::Goal                   *goal = pdef_->getGoal().get();
    base::GoalRegion           *goal_r = dynamic_cast<base::GoalRegion*>(goal);
    base::GoalSampleableRegion *goal_s = dynamic_cast<base::GoalSampleableRegion*>(goal);

    if (!goal)
    {
        msg_.error("Goal undefined");
        return false;
    }

    while (const base::State *st = pis_.nextStart())
    {
        Motion *motion = new Motion(si_);
        si_->copyState(motion->state, st);
        addMotion(motion, 1.0);
    }

    if (tree_.grid.size() == 0)
    {
        msg_.error("There are no valid initial states!");
        return false;
    }

    if (!sampler_)
        sampler_ = si_->allocManifoldStateSampler();

    msg_.inform("Starting with %u states", tree_.size);

    Motion *solution  = NULL;
    Motion *approxsol = NULL;
    double  approxdif = std::numeric_limits<double>::infinity();
    base::State *xstate = si_->allocState();
    Grid::Coord  xcoord;

    double improveValue = maxDistance_;

    while (ptc() == false)
    {
        tree_.iteration++;

        /* Decide on a state to expand from */
        Motion     *existing = NULL;
        Grid::Cell *ecell = NULL;
        selectMotion(existing, ecell);
        assert(existing);

        /* sample random state (with goal biasing) */
        if (rng_.uniform01() < goalBias_)
        {
            if (goal_s && goal_s->canSample())
                goal_s->sampleGoal(xstate);
            else
            {
                if (approxsol && goal_r)
                {
                    si_->copyState(xstate, approxsol->state);
                    msg_.debug("Start Running HCIK (%f)...", improveValue);
                    if (hcik_.tryToImprove(*goal_r, xstate, improveValue))
                    {
                        if (improveValue > maxDistance_ / 100.0)
                            improveValue /= 2.0;
                    }
                    else
                        sampler_->sampleUniformNear(xstate, existing->state, maxDistance_);
                    msg_.debug("End Running HCIK");
                }
                else
                    sampler_->sampleUniformNear(xstate, existing->state, maxDistance_);
            }
        }
        else
            sampler_->sampleUniformNear(xstate, existing->state, maxDistance_);

        std::pair<base::State*, double> fail(xstate, 0.0);
        bool keep = si_->checkMotion(existing->state, xstate, fail);
        if (!keep && fail.second > minValidPathFraction_)
            keep = true;

        if (keep)
        {
            /* create a motion */
            Motion *motion = new Motion(si_);
            si_->copyState(motion->state, xstate);
            motion->parent = existing;

            double dist = 0.0;
            bool solved = goal->isSatisfied(motion->state, &dist);
            addMotion(motion, dist);

            if (solved)
            {
                approxdif = dist;
                solution = motion;
                break;
            }
            if (dist < approxdif)
            {
                approxdif = dist;
                approxsol = motion;
            }
            ecell->data->score *= goodScoreFactor_;
        }
        else
            ecell->data->score *= badScoreFactor_;

        tree_.grid.update(ecell);
    }

    bool approximate = false;
    if (solution == NULL)
    {
        solution = approxsol;
        approximate = true;
    }

    if (solution != NULL)
    {
        /* construct the solution path */
        std::vector<Motion*> mpath;
        while (solution != NULL)
        {
            mpath.push_back(solution);
            solution = solution->parent;
        }

        /* set the solution path */
        PathGeometric *path = new PathGeometric(si_);
           for (int i = mpath.size() - 1 ; i >= 0 ; --i)
            path->states.push_back(si_->cloneState(mpath[i]->state));
        goal->setDifference(approxdif);
        goal->setSolutionPath(base::PathPtr(path), approximate);

        if (approximate)
            msg_.warn("Found approximate solution");
    }

    si_->freeState(xstate);

    msg_.inform("Created %u states in %u cells (%u internal + %u external)", tree_.size, tree_.grid.size(),
                 tree_.grid.countInternal(), tree_.grid.countExternal());

    return goal->isAchieved();
}

bool ompl::geometric::KPIECE1::selectMotion(Motion* &smotion, Grid::Cell* &scell)
{
    scell = rng_.uniform01() < std::max(selectBorderFraction_, tree_.grid.fracExternal()) ?
        tree_.grid.topExternal() : tree_.grid.topInternal();

    // We are running on finite precision, so our update scheme will end up
    // with 0 values for the score. This is where we fix the problem
    if (scell->data->score < std::numeric_limits<double>::epsilon())
    {
        std::vector<CellData*> content;
        content.reserve(tree_.grid.size());
        tree_.grid.getContent(content);
        for (std::vector<CellData*>::iterator it = content.begin() ; it != content.end() ; ++it)
            (*it)->score += 1.0 + log((double)((*it)->iteration));
        tree_.grid.updateAll();
    }

    if (scell && !scell->data->motions.empty())
    {
        scell->data->selections++;
        smotion = scell->data->motions[rng_.halfNormalInt(0, scell->data->motions.size() - 1)];
        return true;
    }
    else
        return false;
}

unsigned int ompl::geometric::KPIECE1::addMotion(Motion *motion, double dist)
{
    Grid::Coord coord;
    projectionEvaluator_->computeCoordinates(motion->state, coord);
    Grid::Cell* cell = tree_.grid.getCell(coord);
    unsigned int created = 0;
    if (cell)
    {
        cell->data->motions.push_back(motion);
        cell->data->coverage += 1.0;
        tree_.grid.update(cell);
    }
    else
    {
        cell = tree_.grid.createCell(coord);
        cell->data = new CellData();
        cell->data->motions.push_back(motion);
        cell->data->coverage = 1.0;
        cell->data->iteration = tree_.iteration;
        cell->data->selections = 1;
        cell->data->score = (1.0 + log((double)(tree_.iteration))) / (1e-3 + dist);
        tree_.grid.add(cell);
        created = 1;
    }
    tree_.size++;
    return created;
}

void ompl::geometric::KPIECE1::getPlannerData(base::PlannerData &data) const
{
    Planner::getPlannerData(data);

    std::vector<CellData*> cdata;
    tree_.grid.getContent(cdata);
    for (unsigned int i = 0 ; i < cdata.size() ; ++i)
        for (unsigned int j = 0 ; j < cdata[i]->motions.size() ; ++j)
            data.recordEdge(cdata[i]->motions[j]->parent ? cdata[i]->motions[j]->parent->state : NULL, cdata[i]->motions[j]->state);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wdocsh.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 08:17:54 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SWWDOCSH_HXX
#define _SWWDOCSH_HXX
#ifndef INCLUDED_SWDLLAPI_H
#include "swdllapi.h"
#endif
#ifndef _SWDOCSH_HXX
#include "docsh.hxx"
#endif
#ifndef SW_SWDLL_HXX
#include <swdll.hxx>
#endif

class SW_DLLPUBLIC SwWebDocShell: public SwDocShell
{
    USHORT      nSourcePara;    // aktive Zeile in der SourceView
public:

    using SotObject::GetInterface;

    // aber selbst implementieren
    SFX_DECL_INTERFACE(SW_WEBDOCSHELL)
    SFX_DECL_OBJECTFACTORY();
    TYPEINFO();

    SwWebDocShell(SfxObjectCreateMode eMode = SFX_CREATE_MODE_EMBEDDED);
    ~SwWebDocShell();

    virtual void        FillClass( SvGlobalName * pClassName,
                                   sal_uInt32 * pClipFormat,
                                   String * pAppName,
                                   String * pLongUserName,
                                   String * pUserName,
                                   sal_Int32 nFileFormat ) const;
    USHORT      GetSourcePara()const
                            {return nSourcePara;}
    void        SetSourcePara(USHORT nSet) {nSourcePara = nSet;}
};

#endif

<commit_msg>INTEGRATION: CWS swusing (1.10.38); FILE MERGED 2007/10/12 09:57:52 tl 1.10.38.2: #i82476# make 'using' declarations private 2007/10/10 14:14:49 tl 1.10.38.1: #i82476# make newly added 'using' declarations private<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wdocsh.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: vg $ $Date: 2007-10-22 15:09:39 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SWWDOCSH_HXX
#define _SWWDOCSH_HXX
#ifndef INCLUDED_SWDLLAPI_H
#include "swdllapi.h"
#endif
#ifndef _SWDOCSH_HXX
#include "docsh.hxx"
#endif
#ifndef SW_SWDLL_HXX
#include <swdll.hxx>
#endif

class SW_DLLPUBLIC SwWebDocShell: public SwDocShell
{
    USHORT      nSourcePara;    // aktive Zeile in der SourceView

public:

    using SotObject::GetInterface;

    // aber selbst implementieren
    SFX_DECL_INTERFACE(SW_WEBDOCSHELL)
    SFX_DECL_OBJECTFACTORY();
    TYPEINFO();

    SwWebDocShell(SfxObjectCreateMode eMode = SFX_CREATE_MODE_EMBEDDED);
    ~SwWebDocShell();

    virtual void        FillClass( SvGlobalName * pClassName,
                                   sal_uInt32 * pClipFormat,
                                   String * pAppName,
                                   String * pLongUserName,
                                   String * pUserName,
                                   sal_Int32 nFileFormat ) const;
    USHORT      GetSourcePara()const
                            {return nSourcePara;}
    void        SetSourcePara(USHORT nSet) {nSourcePara = nSet;}
};

#endif

<|endoftext|>


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

#ifndef ROCPRIM_BLOCK_BLOCK_SHUFFLE_HPP_
#define ROCPRIM_BLOCK_BLOCK_SHUFFLE_HPP_

#include <type_traits>

#include "../config.hpp"
#include "../detail/various.hpp"

#include "../intrinsics.hpp"
#include "../functional.hpp"

#include "detail/block_reduce_warp_reduce.hpp"
#include "detail/block_reduce_raking_reduce.hpp"

/// \addtogroup blockmodule
/// @{

BEGIN_ROCPRIM_NAMESPACE

template<
    class T,
    unsigned int BlockSizeX,
    unsigned int BlockSizeY = 1,
    unsigned int BlockSizeZ = 1>
class block_shuffle
{
    static constexpr unsigned int BlockSize = BlockSizeX * BlockSizeY * BlockSizeZ;

    struct storage_type_
    {
        T prev[BlockSize];
        T next[BlockSize];
    };

    storage_type_* storage;

public:

    /// \brief Struct used to allocate a temporary memory that is required for thread
    /// communication during operations provided by related parallel primitive.
    ///
    /// Depending on the implemention the operations exposed by parallel primitive may
    /// require a temporary storage for thread communication. The storage should be allocated
    /// using keywords <tt>__shared__</tt>. It can be aliased to
    /// an externally allocated memory, or be a part of a union type with other storage types
    /// to increase shared memory reusability.
    #ifndef DOXYGEN_SHOULD_SKIP_THIS // hides storage_type implementation for Doxygen
        using storage_type = detail::raw_storage<storage_type_>;
    #else
        using storage_type = storage_type_; // only for Doxygen
    #endif

    ROCPRIM_DEVICE inline
    block_shuffle()
    {
        ROCPRIM_SHARED_MEMORY storage_type_ shared_storage;
        storage = &shared_storage;
    }

    /// \brief Each threadi obtains the \p input provided
    /// by threadi+<tt>distance</tt>.
    /// The offset \p distance may be negative.
    ///
    /// \par
    /// - \smemreuse
    ///
    ROCPRIM_DEVICE inline
    void offset(
      T input,
      T& output,
      int distance =1)
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->prev[flat_id] = input;
        ::rocprim::syncthreads();

        const int offset_tid = static_cast<int>(flat_id) + distance;
        if ((offset_tid >= 0) && (offset_tid < (int)BlockSize))
        {
            output = storage->prev[static_cast<size_t>(offset_tid)];
        }
    }

    /// \brief Each threadi obtains the \p input provided by
    /// threadi+<tt>distance</tt>.
    ///
    /// \par
    /// - \smemreuse
    ///
    ROCPRIM_DEVICE inline
    void rotate(
        T   input,                  ///< [in] The calling thread's input item
        T&  output,                 ///< [out] The \p input item from thread thread(i+<tt>distance></tt>)%<tt><BlockSize></tt> (may be aliased to \p input).  This value is not updated for threadBlockSize-1
        unsigned int distance = 1)  ///< [in] Offset distance (0 < \p distance < <tt>BlockSize</tt>)
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->prev[flat_id] = input;
        ::rocprim::syncthreads();

        unsigned int offset = threadIdx.x + distance;
        if (offset >= BlockSize)
            offset -= BlockSize;

        output = storage->prev[offset];
    }

    /// \brief The thread block rotates its [blocked arrangement](index.html#sec5sec3) of \p input items, shifting it up by one item
    ///
    /// \par
    /// - \blocked
    /// - \granularity
    /// - \smemreuse
    ///
    template <unsigned int ItemsPerThread>
    ROCPRIM_DEVICE inline
    void up(
        T (&input)[ItemsPerThread],   ///< [in] The calling thread's input items
        T (&prev)[ItemsPerThread])    ///< [out] The corresponding predecessor items (may be aliased to \p input).  The item \p prev[0] is not updated for thread0.
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->prev[flat_id] = input[ItemsPerThread -1];
        ::rocprim::syncthreads();
        #pragma unroll
        for (unsigned int i = ItemsPerThread - 1; i > 0; --i)
        {
            prev[i] = input[i - 1];
        }
        if (flat_id > 0)
        {
            prev[0] = storage->prev[flat_id - 1];
        }
    }

    /**
     * \brief The thread block rotates its [blocked arrangement](index.html#sec5sec3) of \p input items, shifting it up by one item.  All threads receive the \p input provided by thread<tt>BlockSize-1</tt>.
     *
     * \par
     * - \blocked
     * - \granularity
     * - \smemreuse
     */
    template <int ItemsPerThread>
    ROCPRIM_DEVICE inline void up(
        T (&input)[ItemsPerThread],   ///< [in] The calling thread's input items
        T (&prev)[ItemsPerThread],    ///< [out] The corresponding predecessor items (may be aliased to \p input).  The item \p prev[0] is not updated for thread0.
        T &block_suffix)                ///< [out] The item \p input[ItemsPerThread-1] from thread<tt>BlockSize-1</tt>, provided to all threads
    {
        up(input, prev);
        block_suffix = storage->prev[BlockSize - 1];
    }

    /// \brief The thread block rotates its [blocked arrangement](index.html#sec5sec3) of \p input items, shifting it down by one item
    ///
    /// \par
    /// - \blocked
    /// - \granularity
    /// - \smemreuse
    ///
    template <unsigned int ItemsPerThread>
    ROCPRIM_DEVICE inline void down(
        T (&input)[ItemsPerThread],   ///< [in] The calling thread's input items
        T (&next)[ItemsPerThread])    ///< [out] The corresponding predecessor items (may be aliased to \p input).  The value \p next[0] is not updated for threadBlockSize-1.
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->next[flat_id] = input[0];
        ::rocprim::syncthreads();

        #pragma unroll
        for (unsigned int i = 0; i < (ItemsPerThread - 1); ++i)
        {
          next[i] = input[i + 1];
        }

        if (flat_id <(BlockSize -1))
        {
          next[ItemsPerThread -1] = storage->next[flat_id + 1];
        }
    }

    /// \brief The thread block rotates its [blocked arrangement](index.html#sec5sec3)
    /// of input items, shifting it down by one item.
    /// All threads receive \p input[0] provided by thread<tt>0</tt>.
    ///
    /// \par
    /// - \blocked
    /// - \granularity
    /// - \smemreuse
    ///
    template <unsigned int ItemsPerThread>
    ROCPRIM_DEVICE inline void Down(
        T (&input)[ItemsPerThread],   ///< [in] The calling thread's input items
        T (&next)[ItemsPerThread],    ///< [out] The corresponding predecessor items (may be aliased to \p input).  The value \p next[0] is not updated for threadBlockSize-1.
        T &block_suffix)                ///< [out] The item \p input[0] from thread<tt>0</tt>, provided to all threads
    {
        Up(input, next);
        block_suffix = storage->next[0];
    }
};

END_ROCPRIM_NAMESPACE

/// @}
// end of group blockmodule

#endif // ROCPRIM_BLOCK_BLOCK_SHUFFLE_HPP_
<commit_msg>Updated documentation for block shuffle<commit_after>/******************************************************************************
 * Copyright (c) 2011, Duane Merrill.  All rights reserved.
 * Copyright (c) 2011-2018, NVIDIA CORPORATION.  All rights reserved.
 * Modifications Copyright (c) 2021, Advanced Micro Devices, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the NVIDIA CORPORATION nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

#ifndef ROCPRIM_BLOCK_BLOCK_SHUFFLE_HPP_
#define ROCPRIM_BLOCK_BLOCK_SHUFFLE_HPP_

#include <type_traits>

#include "../config.hpp"
#include "../detail/various.hpp"

#include "../intrinsics.hpp"
#include "../functional.hpp"

#include "detail/block_reduce_warp_reduce.hpp"
#include "detail/block_reduce_raking_reduce.hpp"

/// \addtogroup blockmodule
/// @{

BEGIN_ROCPRIM_NAMESPACE

/// \brief The block_shuffle class is a block level parallel primitive which provides methods
/// for shuffling data partitioned across a block
///
/// \tparam T - the input/output type.
/// \tparam Algorithm - selected scan algorithm, block_scan_algorithm::default_algorithm by default.
/// \tparam BlockSizeY - the number of threads in a block's y dimension, defaults to 1.
/// \tparam BlockSizeZ - the number of threads in a block's z dimension, defaults to 1.
///
/// \par Overview
/// It is commonplace for blocks of threads to rearrange data items between
//  threads.  The BlockShuffle abstraction allows threads to efficiently shift items
//  either (a) up to their successor or (b) down to their predecessor.
/// \endparblock
template<
    class T,
    unsigned int BlockSizeX,
    unsigned int BlockSizeY = 1,
    unsigned int BlockSizeZ = 1>
class block_shuffle
{
    static constexpr unsigned int BlockSize = BlockSizeX * BlockSizeY * BlockSizeZ;

    struct storage_type_
    {
        T prev[BlockSize];
        T next[BlockSize];
    };

    storage_type_* storage;

public:

    /// \brief Struct used to allocate a temporary memory that is required for thread
    /// communication during operations provided by related parallel primitive.
    ///
    /// Depending on the implemention the operations exposed by parallel primitive may
    /// require a temporary storage for thread communication. The storage should be allocated
    /// using keywords <tt>__shared__</tt>. It can be aliased to
    /// an externally allocated memory, or be a part of a union type with other storage types
    /// to increase shared memory reusability.
    #ifndef DOXYGEN_SHOULD_SKIP_THIS // hides storage_type implementation for Doxygen
        using storage_type = detail::raw_storage<storage_type_>;
    #else
        using storage_type = storage_type_; // only for Doxygen
    #endif

    ROCPRIM_DEVICE inline
    block_shuffle()
    {
        ROCPRIM_SHARED_MEMORY storage_type_ shared_storage;
        storage = &shared_storage;
    }

    /// \brief Shuffles data across threads in a block, offseted by the distance value.
    ///
    /// \par A thread with  threadId i receives data from a thread with threadIdx (i-distance), whre distance may be a negative value.
    /// allocated by the method itself.
    /// \par Any shuffle operation with invalid input or output threadIds are not carried out, i.e. threadId < 0 || threadId >= BlockSize.
    ///
    /// \param [in] input - input data to be shuffled to another thread.
    /// \param [out] output - reference to a output value, that receives data from another thread
    /// \param [in] distance - The input threadId + distance = output threadId.
    ROCPRIM_DEVICE inline
    void offset(
      T input,
      T& output,
      int distance =1)
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->prev[flat_id] = input;
        ::rocprim::syncthreads();

        const int offset_tid = static_cast<int>(flat_id) + distance;
        if ((offset_tid >= 0) && (offset_tid < (int)BlockSize))
        {
            output = storage->prev[static_cast<size_t>(offset_tid)];
        }
    }

    /// \brief Shuffles data across threads in a block, offseted by the distance value.
    ///
    /// \par A thread with  threadId i receives data from a thread with threadIdx (i-distance)%BlockSize, whre distance may be a negative value.
    /// allocated by the method itself.
    /// \par Data is rotated around the block, using (input_threadId + distance) modulous BlockSize to ensure valid threadIds.
    ///
    /// \param [in] input - input data to be shuffled to another thread.
    /// \param [out] output - reference to a output value, that receives data from another thread
    /// \param [in] distance - The input threadId + distance = output threadId.
    ROCPRIM_DEVICE inline
    void rotate(
        T   input,                  ///< [in] The calling thread's input item
        T&  output,                 ///< [out] The \p input item from thread thread(i+<tt>distance></tt>)%<tt><BlockSize></tt> (may be aliased to \p input).  This value is not updated for threadBlockSize-1
        unsigned int distance = 1)  ///< [in] Offset distance (0 < \p distance < <tt>BlockSize</tt>)
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->prev[flat_id] = input;
        ::rocprim::syncthreads();

        unsigned int offset = threadIdx.x + distance;
        if (offset >= BlockSize)
            offset -= BlockSize;

        output = storage->prev[offset];
    }

    /// \brief The thread block rotates a blocked arrange of \input items, shifting it up by one item
    ///
    /// \param [in]  input -  The calling thread's input items
    /// \param [out] prev  -  The corresponding predecessor items (may be aliased to \p input).  The item \p prev[0] is not updated for thread0.
    template <unsigned int ItemsPerThread>
    ROCPRIM_DEVICE inline
    void up(
        T (&input)[ItemsPerThread],
        T (&prev)[ItemsPerThread])
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->prev[flat_id] = input[ItemsPerThread -1];
        ::rocprim::syncthreads();
        #pragma unroll
        for (unsigned int i = ItemsPerThread - 1; i > 0; --i)
        {
            prev[i] = input[i - 1];
        }
        if (flat_id > 0)
        {
            prev[0] = storage->prev[flat_id - 1];
        }
    }

    /// \brief The thread block rotates a blocked arrange of \input items, shifting it up by one item
    ///
    /// \param [in]  input - The calling thread's input items
    /// \param [out] prev  - The corresponding predecessor items (may be aliased to \p input).  The item \p prev[0] is not updated for thread0.
    /// \param [out] block_suffix - The item \p input[ItemsPerThread-1] from thread<tt>BlockSize-1</tt>, provided to all threads
    template <int ItemsPerThread>
    ROCPRIM_DEVICE inline void up(
        T (&input)[ItemsPerThread],
        T (&prev)[ItemsPerThread],
        T &block_suffix)
    {
        up(input, prev);
        block_suffix = storage->prev[BlockSize - 1];
    }

    /// \brief The thread block rotates a blocked arrange of \input items, shifting it down by one item
    ///
    /// \param [in]  input -  The calling thread's input items
    /// \param [out] next  -  The corresponding successor items (may be aliased to \p input).  The item \p prev[0] is not updated for threadBlockSize - 1.
    template <unsigned int ItemsPerThread>
    ROCPRIM_DEVICE inline void down(
        T (&input)[ItemsPerThread],
        T (&next)[ItemsPerThread])
    {
        const size_t flat_id = ::rocprim::flat_block_thread_id<BlockSizeX, BlockSizeY, BlockSizeZ>();
        storage->next[flat_id] = input[0];
        ::rocprim::syncthreads();

        #pragma unroll
        for (unsigned int i = 0; i < (ItemsPerThread - 1); ++i)
        {
          next[i] = input[i + 1];
        }

        if (flat_id <(BlockSize -1))
        {
          next[ItemsPerThread -1] = storage->next[flat_id + 1];
        }
    }

    /// \brief The thread block rotates a blocked arrange of \input items, shifting it down by one item
    ///
    /// \param [in]  input -  The calling thread's input items
    /// \param [out] next  -  The corresponding successor items (may be aliased to \p input).  The item \p prev[0] is not updated for threadBlockSize - 1.
    /// \param [out] block_prefix -  The item \p input[0] from thread<tt>0</tt>, provided to all threads
    template <unsigned int ItemsPerThread>
    ROCPRIM_DEVICE inline void Down(
        T (&input)[ItemsPerThread],
        T (&next)[ItemsPerThread],
        T &block_prefix)
    {
        Down(input, next);
        block_prefix = storage->next[0];
    }
};

END_ROCPRIM_NAMESPACE

/// @}
// end of group blockmodule

#endif // ROCPRIM_BLOCK_BLOCK_SHUFFLE_HPP_
<|endoftext|>


<commit_before>#include "p0run/interpreter.hpp"
#include "p0run/string.hpp"
#include "p0run/table.hpp"
#include "p0compile/compiler.hpp"
#include "p0compile/compiler_error.hpp"
#include <boost/test/unit_test.hpp>
using namespace p0::run;

namespace
{
	bool expect_no_error(p0::compiler_error const &error)
	{
		std::cerr << error.what() << '\n';
		BOOST_CHECK(nullptr == "no error expected");
		return true;
	}

	template <class CheckResult>
	void run_valid_source(
			std::string const &source,
			std::vector<value> const &arguments,
			CheckResult const &check_result)
	{
		p0::source_range const source_range(
			source.data(),
			source.data() + source.size());

		p0::compiler compiler(source_range, expect_no_error);
		auto const program = compiler.compile();

		p0::run::interpreter interpreter(program, nullptr);
		auto const &main_function = program.functions().front();
		auto const result = interpreter.call(main_function, arguments);
		check_result(result, program);
	}
}

BOOST_AUTO_TEST_CASE(empty_function_compile_test)
{
	std::string const source = "";
	std::vector<p0::run::value> const arguments;
	run_valid_source(source, arguments,
		[](p0::run::value const &result, p0::intermediate::unit const &program)
	{
		auto const &main_function = program.functions().front();
		BOOST_CHECK(result == value(main_function));
	});
}

BOOST_AUTO_TEST_CASE(return_integer_compile_test)
{
	std::string const source = "return 123";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(result == value(static_cast<integer>(123)));
	});
}

BOOST_AUTO_TEST_CASE(return_null_compile_test)
{
	std::string const source = "return null";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(is_null(result));
	});
}

BOOST_AUTO_TEST_CASE(return_string_compile_test)
{
	std::string const source = "return \"hello, world!\"";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_REQUIRE(result.type == value_type::object);
		BOOST_REQUIRE(dynamic_cast<string const *>(result.obj));
		BOOST_CHECK(dynamic_cast<string const &>(*result.obj).content() == "hello, world!");
	});
}

BOOST_AUTO_TEST_CASE(return_empty_table_compile_test)
{
	std::string const source = "return []";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_REQUIRE(result.type == value_type::object);
		BOOST_REQUIRE(dynamic_cast<table const *>(result.obj));
	});
}

BOOST_AUTO_TEST_CASE(return_trivial_table_compile_test)
{
	std::string const source = "var t = [] t[123] = 456 return t";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_REQUIRE(result.type == value_type::object);
		BOOST_REQUIRE(dynamic_cast<table const *>(result.obj));
		auto const element = dynamic_cast<table const &>(*result.obj).get_element(
					value(static_cast<integer>(123)));
		BOOST_REQUIRE(element);
		BOOST_CHECK(*element == value(static_cast<integer>(456)));
	});
}

BOOST_AUTO_TEST_CASE(bind_local_variable_test)
{
	std::string const source =
			"var a = 7\n"
			"var f = function () { return a + 2 }\n"
			"return f()";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(result == value(static_cast<integer>(9)));
	});
}
<commit_msg>test for using a variable across two function boundaries<commit_after>#include "p0run/interpreter.hpp"
#include "p0run/string.hpp"
#include "p0run/table.hpp"
#include "p0compile/compiler.hpp"
#include "p0compile/compiler_error.hpp"
#include <boost/test/unit_test.hpp>
using namespace p0::run;

namespace
{
	bool expect_no_error(p0::compiler_error const &error)
	{
		std::cerr << error.what() << '\n';
		BOOST_CHECK(nullptr == "no error expected");
		return true;
	}

	template <class CheckResult>
	void run_valid_source(
			std::string const &source,
			std::vector<value> const &arguments,
			CheckResult const &check_result)
	{
		p0::source_range const source_range(
			source.data(),
			source.data() + source.size());

		p0::compiler compiler(source_range, expect_no_error);
		auto const program = compiler.compile();

		p0::run::interpreter interpreter(program, nullptr);
		auto const &main_function = program.functions().front();
		auto const result = interpreter.call(main_function, arguments);
		check_result(result, program);
	}
}

BOOST_AUTO_TEST_CASE(empty_function_compile_test)
{
	std::string const source = "";
	std::vector<p0::run::value> const arguments;
	run_valid_source(source, arguments,
		[](p0::run::value const &result, p0::intermediate::unit const &program)
	{
		auto const &main_function = program.functions().front();
		BOOST_CHECK(result == value(main_function));
	});
}

BOOST_AUTO_TEST_CASE(return_integer_compile_test)
{
	std::string const source = "return 123";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(result == value(static_cast<integer>(123)));
	});
}

BOOST_AUTO_TEST_CASE(return_null_compile_test)
{
	std::string const source = "return null";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(is_null(result));
	});
}

BOOST_AUTO_TEST_CASE(return_string_compile_test)
{
	std::string const source = "return \"hello, world!\"";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_REQUIRE(result.type == value_type::object);
		BOOST_REQUIRE(dynamic_cast<string const *>(result.obj));
		BOOST_CHECK(dynamic_cast<string const &>(*result.obj).content() == "hello, world!");
	});
}

BOOST_AUTO_TEST_CASE(return_empty_table_compile_test)
{
	std::string const source = "return []";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_REQUIRE(result.type == value_type::object);
		BOOST_REQUIRE(dynamic_cast<table const *>(result.obj));
	});
}

BOOST_AUTO_TEST_CASE(return_trivial_table_compile_test)
{
	std::string const source = "var t = [] t[123] = 456 return t";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_REQUIRE(result.type == value_type::object);
		BOOST_REQUIRE(dynamic_cast<table const *>(result.obj));
		auto const element = dynamic_cast<table const &>(*result.obj).get_element(
					value(static_cast<integer>(123)));
		BOOST_REQUIRE(element);
		BOOST_CHECK(*element == value(static_cast<integer>(456)));
	});
}

BOOST_AUTO_TEST_CASE(bind_local_variable_test)
{
	std::string const source =
			"var a = 7\n"
			"var f = function () { return a + 2 }\n"
			"return f()";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(result == value(static_cast<integer>(9)));
	});
}

BOOST_AUTO_TEST_CASE(bind_far_variable_test)
{
	std::string const source =
			"var a = 7\n"
			"var f = function () {\n"
			"	var g = function () {\n"
			"		return a + 2\n"
			"	}\n"
			"	return g\n"
			"}\n"
			"return f()()";
	std::vector<value> const arguments;
	run_valid_source(source, arguments,
		[](value const &result, p0::intermediate::unit const & /*program*/)
	{
		BOOST_CHECK(result == value(static_cast<integer>(9)));
	});
}
<|endoftext|>