<commit_before>#include "sn_sweeper.hpp"

#include <iomanip>

#include "error.hpp"

using std::cout;
using std::endl;
using std::cin;

namespace mocc {
    SnSweeper::SnSweeper( const pugi::xml_node& input, const CoreMesh& mesh ):
        core_mesh_( mesh ),
        ang_quad_( input.child("ang_quad") ),
        bc_type_( mesh.boundary() ),
        xstr_( mesh.n_pin(), 1 ),
        q_( mesh.n_pin(), 1 )
    {
        // Set up all of the stuff that would normally be done by the
        // TransportSweeper constructor. There is probably a better and more
        // maintainable way to do this; will revisit.
        xs_mesh_ = SP_XSMesh_t( new XSMeshHomogenized(mesh) );
        n_reg_ = mesh.n_pin();
        ng_ = xs_mesh_->n_group();
        flux_.resize( n_reg_, ng_ );
        flux_old_.resize( n_reg_, ng_ );
        vol_.resize( n_reg_, 1 );

        flux_1g_.resize( n_reg_, 1 );

        // Set the mesh volumes. Same as the pin volumes
        int ipin = 0;
        for( auto &pin: core_mesh_ ) {
            int i = core_mesh_.index_lex( core_mesh_.pin_position(ipin) );
            vol_(i) = pin->vol();
            ipin++;
        }

        // Make sure we have input from the XML
        if( input.empty() ) {
            throw EXCEPT("No input specified to initialize Sn sweeper.");
        }

        // Parse the number of inner iterations
        int int_in = input.attribute("n_inner").as_int(-1);
        if( int_in < 0 ) {
            throw EXCEPT("Invalid number of inner iterations specified (n_inner).");
        }
        n_inner_ = int_in;

        // Set up the mesh dimensions
        const VecF& core_x = core_mesh_.pin_hx();
        for( unsigned int i=0; i<core_x.size()-1; i++ ) {
            hx_.push_back(core_x[i+1]-core_x[i]);
        }
        const VecF& core_y = core_mesh_.pin_hy();
        for( unsigned int i=0; i<core_y.size()-1; i++ ) {
            hy_.push_back(core_y[i+1]-core_y[i]);
        }
        hz_ = core_mesh_.hz();

        nx_ = hx_.size();
        ny_ = hy_.size();
        nz_ = hz_.size();

        bc_in_ = SnBoundary( ng_, ang_quad_.ndir(), nx_, ny_, nz_ );
        bc_out_ = SnBoundary( 1, ang_quad_.ndir(), nx_, ny_, nz_ );

        return;
    }

    void SnSweeper::homogenize( CoarseData &data ) const {
        return;
    }

    void SnSweeper::sweep( int group ) {
        // Store the transport cross section somewhere useful
        for( auto &xsr: *xs_mesh_ ) {
            float_t xstr = xsr.xsmactr()[group];
            for( auto &ireg: xsr.reg() ) {
                xstr_(ireg) = xstr;
            }
        }

        flux_1g_ = flux_.col( group );

        // Perform inner iterations
        for( unsigned int inner=0; inner<n_inner_; inner++ ) {

            // Set the source (add upscatter and divide by 4PI)
            source_->self_scatter( group, flux_1g_, q_ );

            if( inner == n_inner_-1 && coarse_data_ ) {
                this->sweep_final( group );
            } else {
                this->sweep_std( group );
            }
        }
        flux_.col( group ) = flux_1g_;

        return;
    }

    void SnSweeper::sweep_std( int group ) {
        flux_1g_.fill(0.0);

		ArrayF x_flux(ny_*nz_);
		ArrayF y_flux(nx_*nz_);
		ArrayF z_flux(nx_*ny_);

        int iang = 0;
        for( auto ang: ang_quad_ ) {
            float_t wgt = ang.weight * HPI;
            float_t ox = ang.ox;
            float_t oy = ang.oy;
            float_t oz = ang.oz;

            // Configure the loop direction. Could template the below for speed
            // at some point.
            int sttx = 0;
            int stpx = nx_;
            int xdir = 1;
            if( ox < 0.0 ) {
                ox = -ox;
                sttx = nx_-1;
                stpx = -1;
                xdir = -1;
            }

            int stty = 0;
            int stpy = ny_;
            int ydir = 1;
            if( oy < 0.0 ) {
                oy = -oy;
                stty = ny_-1;
                stpy = -1;
                ydir = -1;
            }

            int sttz = 0;
            int stpz = nz_;
            int zdir = 1;
            if( oz < 0.0 ) {
                oz = -oz;
                sttz = nz_-1;
                stpz = -1;
                zdir = -1;
            }

            // initialize upwind condition
            x_flux = bc_in_.get_face( group, iang, Normal::X_NORM);
            y_flux = bc_in_.get_face( group, iang, Normal::Y_NORM);
            z_flux = bc_in_.get_face( group, iang, Normal::Z_NORM);

            for( int iz=sttz; iz!=stpz; iz+=zdir ) {
                float_t tz = oz/hz_[iz];
                for( int iy=stty; iy!=stpy; iy+=ydir ) {
                    float_t ty = oy/hy_[iy];
                    for( int ix=sttx; ix!=stpx; ix+=xdir ) {
                        // Gross. really need an Sn mesh abstraction
                        float_t psi_lx = x_flux[ny_*iz + iy];
                        float_t psi_ly = y_flux[nx_*iz + ix];
                        float_t psi_lz = z_flux[nx_*iy + ix];

                        int i = iz*nx_*ny_ + iy*nx_ + ix;
                        float_t tx = ox/hx_[ix];
                        float_t psi = 2.0*(tx*psi_lx +
                                           ty*psi_ly +
                                           tz*psi_lz) + q_(i);
                        psi /= 2.0*(tx + ty + tz) + xstr_(i);

                        flux_1g_(i) += psi*wgt;

                        x_flux[ny_*iz + iy] = 2.0*psi - x_flux[ny_*iz + iy];
                        y_flux[nx_*iz + ix] = 2.0*psi - y_flux[nx_*iz + ix];
                        z_flux[nx_*iy + ix] = 2.0*psi - z_flux[nx_*iy + ix];
                    }
                }
            }

            // store the downwind boundary condition
            bc_out_.set_face(0, iang, Normal::X_NORM, x_flux);
            bc_out_.set_face(0, iang, Normal::Y_NORM, y_flux);
            bc_out_.set_face(0, iang, Normal::Z_NORM, z_flux);
            iang++;
        }
        // Update the boundary condition
        this->update_boundary( group );

        return;
    }

    /// \todo implement current calculations here
    void SnSweeper::sweep_final( int group ) {
        this->sweep_std( group );
        return;
    }

    void SnSweeper::initialize() {
        flux_.fill(1.0);
        flux_old_.fill(1.0);
        bc_in_.initialize(0.0);

        return;
    }

    void SnSweeper::get_pin_flux( int ig, VecF& flux ) const {
        return;
    }

    void SnSweeper::update_boundary( int group ) {
        int iang = 0;
        for( auto &ang: ang_quad_ ) {
            Surface surf;
            Normal norm;
            int iang_refl;

            // X-normal surface
            norm = Normal::X_NORM;
            surf = (ang.ox > 0) ? Surface::WEST : Surface::EAST;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_type_[(int)surf] == Boundary::REFLECT ) {
                bc_in_.set_face(group, iang, norm,
                        bc_out_.get_face(0, iang_refl, norm ));
            } else {
                bc_in_.zero_face(group, iang, norm);
            }
            // Y-normal surface
            norm = Normal::Y_NORM;
            surf = (ang.oy > 0) ? Surface::SOUTH : Surface::NORTH;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_type_[(int)surf] == Boundary::REFLECT ) {
                bc_in_.set_face(group, iang, norm,
                        bc_out_.get_face(0, iang_refl, norm ));
            } else {
                bc_in_.zero_face(group, iang, norm);
            }
            // Z-normal surface
            norm = Normal::Z_NORM;
            surf = (ang.oz > 0) ? Surface::BOTTOM : Surface::TOP;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_type_[(int)surf] == Boundary::REFLECT ) {
                bc_in_.set_face(group, iang, norm,
                        bc_out_.get_face(0, iang_refl, norm ));
            } else {
                bc_in_.zero_face(group, iang, norm);
            }

            iang++;
        }
        return;
    }

    void SnSweeper::output( H5File& file ) const {
        VecI dims;
        dims.push_back(nz_);
        dims.push_back(ny_);
        dims.push_back(nx_);

        // Make a group in the file to store the flux
        file.mkdir("/flux");

        // Provide energy group upper bounds
        file.write("/eubounds", xs_mesh_->eubounds(), VecI(1, ng_));
        file.write("/ng", ng_);

        for( unsigned int ig=0; ig<ng_; ig++ ) {
            VecF flux;

            for( unsigned int ireg=0; ireg<n_reg_; ireg++ ) {
                flux.push_back( flux_( ireg, ig ) );
            }

            std::stringstream setname;
            setname << "/flux/" << std::setfill('0') << std::setw(3) << ig+1;

            file.write(setname.str(), flux, dims);
        }
        return;
    }
}
<commit_msg>Add xs mesh output to SnSweeper<commit_after>#include "sn_sweeper.hpp"

#include <iomanip>

#include "error.hpp"

using std::cout;
using std::endl;
using std::cin;

namespace mocc {
    SnSweeper::SnSweeper( const pugi::xml_node& input, const CoreMesh& mesh ):
        core_mesh_( mesh ),
        ang_quad_( input.child("ang_quad") ),
        bc_type_( mesh.boundary() ),
        xstr_( mesh.n_pin(), 1 ),
        q_( mesh.n_pin(), 1 )
    {
        // Set up all of the stuff that would normally be done by the
        // TransportSweeper constructor. There is probably a better and more
        // maintainable way to do this; will revisit.
        xs_mesh_ = SP_XSMesh_t( new XSMeshHomogenized(mesh) );
        n_reg_ = mesh.n_pin();
        ng_ = xs_mesh_->n_group();
        flux_.resize( n_reg_, ng_ );
        flux_old_.resize( n_reg_, ng_ );
        vol_.resize( n_reg_, 1 );

        flux_1g_.resize( n_reg_, 1 );

        // Set the mesh volumes. Same as the pin volumes
        int ipin = 0;
        for( auto &pin: core_mesh_ ) {
            int i = core_mesh_.index_lex( core_mesh_.pin_position(ipin) );
            vol_(i) = pin->vol();
            ipin++;
        }

        // Make sure we have input from the XML
        if( input.empty() ) {
            throw EXCEPT("No input specified to initialize Sn sweeper.");
        }

        // Parse the number of inner iterations
        int int_in = input.attribute("n_inner").as_int(-1);
        if( int_in < 0 ) {
            throw EXCEPT("Invalid number of inner iterations specified (n_inner).");
        }
        n_inner_ = int_in;

        // Set up the mesh dimensions
        const VecF& core_x = core_mesh_.pin_hx();
        for( unsigned int i=0; i<core_x.size()-1; i++ ) {
            hx_.push_back(core_x[i+1]-core_x[i]);
        }
        const VecF& core_y = core_mesh_.pin_hy();
        for( unsigned int i=0; i<core_y.size()-1; i++ ) {
            hy_.push_back(core_y[i+1]-core_y[i]);
        }
        hz_ = core_mesh_.hz();

        nx_ = hx_.size();
        ny_ = hy_.size();
        nz_ = hz_.size();

        bc_in_ = SnBoundary( ng_, ang_quad_.ndir(), nx_, ny_, nz_ );
        bc_out_ = SnBoundary( 1, ang_quad_.ndir(), nx_, ny_, nz_ );

        return;
    }

    void SnSweeper::homogenize( CoarseData &data ) const {
        return;
    }

    void SnSweeper::sweep( int group ) {
        // Store the transport cross section somewhere useful
        for( auto &xsr: *xs_mesh_ ) {
            float_t xstr = xsr.xsmactr()[group];
            for( auto &ireg: xsr.reg() ) {
                xstr_(ireg) = xstr;
            }
        }

        flux_1g_ = flux_.col( group );

        // Perform inner iterations
        for( unsigned int inner=0; inner<n_inner_; inner++ ) {

            // Set the source (add upscatter and divide by 4PI)
            source_->self_scatter( group, flux_1g_, q_ );

            if( inner == n_inner_-1 && coarse_data_ ) {
                this->sweep_final( group );
            } else {
                this->sweep_std( group );
            }
        }
        flux_.col( group ) = flux_1g_;

        return;
    }

    void SnSweeper::sweep_std( int group ) {
        flux_1g_.fill(0.0);

		ArrayF x_flux(ny_*nz_);
		ArrayF y_flux(nx_*nz_);
		ArrayF z_flux(nx_*ny_);

        int iang = 0;
        for( auto ang: ang_quad_ ) {
            float_t wgt = ang.weight * HPI;
            float_t ox = ang.ox;
            float_t oy = ang.oy;
            float_t oz = ang.oz;

            // Configure the loop direction. Could template the below for speed
            // at some point.
            int sttx = 0;
            int stpx = nx_;
            int xdir = 1;
            if( ox < 0.0 ) {
                ox = -ox;
                sttx = nx_-1;
                stpx = -1;
                xdir = -1;
            }

            int stty = 0;
            int stpy = ny_;
            int ydir = 1;
            if( oy < 0.0 ) {
                oy = -oy;
                stty = ny_-1;
                stpy = -1;
                ydir = -1;
            }

            int sttz = 0;
            int stpz = nz_;
            int zdir = 1;
            if( oz < 0.0 ) {
                oz = -oz;
                sttz = nz_-1;
                stpz = -1;
                zdir = -1;
            }

            // initialize upwind condition
            x_flux = bc_in_.get_face( group, iang, Normal::X_NORM );
            y_flux = bc_in_.get_face( group, iang, Normal::Y_NORM );
            z_flux = bc_in_.get_face( group, iang, Normal::Z_NORM );

            for( int iz=sttz; iz!=stpz; iz+=zdir ) {
                float_t tz = oz/hz_[iz];
                for( int iy=stty; iy!=stpy; iy+=ydir ) {
                    float_t ty = oy/hy_[iy];
                    for( int ix=sttx; ix!=stpx; ix+=xdir ) {
                        // Gross. really need an Sn mesh abstraction
                        float_t psi_lx = x_flux[ny_*iz + iy];
                        float_t psi_ly = y_flux[nx_*iz + ix];
                        float_t psi_lz = z_flux[nx_*iy + ix];

                        int i = iz*nx_*ny_ + iy*nx_ + ix;
                        float_t tx = ox/hx_[ix];
                        float_t psi = 2.0*(tx*psi_lx +
                                           ty*psi_ly +
                                           tz*psi_lz) + q_(i);
                        psi /= 2.0*(tx + ty + tz) + xstr_(i);

                        flux_1g_(i) += psi*wgt;

                        x_flux[ny_*iz + iy] = 2.0*psi - x_flux[ny_*iz + iy];
                        y_flux[nx_*iz + ix] = 2.0*psi - y_flux[nx_*iz + ix];
                        z_flux[nx_*iy + ix] = 2.0*psi - z_flux[nx_*iy + ix];
                    }
                }
            }

            // store the downwind boundary condition
            bc_out_.set_face(0, iang, Normal::X_NORM, x_flux);
            bc_out_.set_face(0, iang, Normal::Y_NORM, y_flux);
            bc_out_.set_face(0, iang, Normal::Z_NORM, z_flux);
            iang++;
        }
        // Update the boundary condition
        this->update_boundary( group );

        return;
    }

    /// \todo implement current calculations here
    void SnSweeper::sweep_final( int group ) {
        this->sweep_std( group );
        return;
    }

    void SnSweeper::initialize() {
        flux_.fill(1.0);
        flux_old_.fill(1.0);
        bc_in_.initialize(0.0);

        return;
    }

    void SnSweeper::get_pin_flux( int ig, VecF& flux ) const {
        return;
    }

    void SnSweeper::update_boundary( int group ) {
        int iang = 0;

        for( auto &ang: ang_quad_ ) {
            Surface surf;
            Normal norm;
            int iang_refl;

            // X-normal surface
            norm = Normal::X_NORM;
            surf = (ang.ox > 0) ? Surface::WEST : Surface::EAST;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_type_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = bc_out_.get_face( 0, iang_refl, norm );
                bc_in_.set_face( group, iang, norm, new_bc );
            } else {
                bc_in_.zero_face(group, iang, norm);
            }
            // Y-normal surface
            norm = Normal::Y_NORM;
            surf = (ang.oy > 0) ? Surface::SOUTH : Surface::NORTH;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_type_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = bc_out_.get_face( 0, iang_refl, norm );
                bc_in_.set_face(group, iang, norm, new_bc);
            } else {
                bc_in_.zero_face(group, iang, norm);
            }
            // Z-normal surface
            norm = Normal::Z_NORM;
            surf = (ang.oz > 0) ? Surface::BOTTOM : Surface::TOP;
            iang_refl = ang_quad_.reflect( iang, norm );
            if( bc_type_[(int)surf] == Boundary::REFLECT ) {
                auto new_bc = bc_out_.get_face( 0, iang_refl, norm );
                bc_in_.set_face(group, iang, norm, new_bc );
            } else {
                bc_in_.zero_face(group, iang, norm);
            }

            iang++;
        }
        return;
    }

    void SnSweeper::output( H5File& file ) const {
        VecI dims;
        dims.push_back(nz_);
        dims.push_back(ny_);
        dims.push_back(nx_);

        // Make a group in the file to store the flux
        file.mkdir("/flux");

        // Provide energy group upper bounds
        file.write("/eubounds", xs_mesh_->eubounds(), VecI(1, ng_));
        file.write("/ng", ng_);

        for( unsigned int ig=0; ig<ng_; ig++ ) {
            VecF flux;

            for( unsigned int ireg=0; ireg<n_reg_; ireg++ ) {
                flux.push_back( flux_( ireg, ig ) );
            }

            std::stringstream setname;
            setname << "/flux/" << std::setfill('0') << std::setw(3) << ig+1;

            file.write(setname.str(), flux, dims);
        }

        xs_mesh_->output( file );
        return;
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <qmdnsengine/dns.h>
#include <qmdnsengine/message.h>
#include <qmdnsengine/prober.h>
#include <qmdnsengine/query.h>
#include <qmdnsengine/responder.h>
#include <qmdnsengine/server.h>

#include "responder_p.h"

using namespace QMdnsEngine;

ResponderPrivate::ResponderPrivate(QObject *parent, Server *server)
    : QObject(parent),
      server(server)
{
    connect(server, &Server::messageReceived, this, &ResponderPrivate::onMessageReceived);
}

void ResponderPrivate::onMessageReceived(const Message &message)
{
    if (message.isResponse()) {
        return;
    }
    Message reply;
    reply.reply(message);
    foreach (Query query, message.queries()) {
        foreach (Record record, records.values(query.name())) {
            if (query.type() == record.type()) {
                reply.addRecord(record);
            }
        }
    }
    if (reply.records().count()) {
        server->sendMessage(message);
    }
}

QByteArray ResponderPrivate::translate(const QByteArray &name) const
{
    return renames.value(name, name);
}

void ResponderPrivate::insertRecords(const QByteArray &oldName, const QByteArray &newName)
{
    foreach (Record record, pendingRecords.values(oldName)) {
        record.setName(newName);
        records.insert(newName, record);
    }
    pendingRecords.remove(oldName);
    renames.insert(oldName, newName);
}

Responder::Responder(Server *server, QObject *parent)
    : QObject(parent),
      d(new ResponderPrivate(parent, server))
{
}

void Responder::addRecord(const Record &record)
{
    QByteArray name = d->translate(record.name());
    if (d->records.count(name)) {

        // If a record with the same name exists in records, then it is safe to
        // insert the record (changing its name to match)
        Record newRecord = record;
        newRecord.setName(name);
        d->records.insert(name, newRecord);

    } else {

        // Either a pending probe exists (in which case, this record can be
        // added to the pending list) or one does not (in which case, a new
        // probe is started)
        if (!d->pendingRecords.count(name)) {
            Prober *prober = new Prober(d->server, record, this);
            connect(prober, &Prober::nameConfirmed, [this, name](const QByteArray &newName) {
                d->insertRecords(name, newName);
            });
        }
        d->pendingRecords.insert(name, record);
    }
}

void Responder::removeRecord(const Record &record)
{
    // Remove all active records that match
    QByteArray name = d->translate(record.name());
    for (auto i = d->records.find(name); i != d->records.end() && i.key() == name;) {
        if (i.value() == record) {
            i = d->records.erase(i);
        } else {
            ++i;
        }
    }

    // Remove the entry from the translation map if no records are using it
    if (!d->records.count(name)) {
        d->renames.remove(record.name());
    }

    // Remove pending records that match
    d->pendingRecords.remove(record.name(), record);
}
<commit_msg>Fix typo.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <qmdnsengine/dns.h>
#include <qmdnsengine/message.h>
#include <qmdnsengine/prober.h>
#include <qmdnsengine/query.h>
#include <qmdnsengine/responder.h>
#include <qmdnsengine/server.h>

#include "responder_p.h"

using namespace QMdnsEngine;

ResponderPrivate::ResponderPrivate(QObject *parent, Server *server)
    : QObject(parent),
      server(server)
{
    connect(server, &Server::messageReceived, this, &ResponderPrivate::onMessageReceived);
}

void ResponderPrivate::onMessageReceived(const Message &message)
{
    if (message.isResponse()) {
        return;
    }
    Message reply;
    reply.reply(message);
    foreach (Query query, message.queries()) {
        foreach (Record record, records.values(query.name())) {
            if (query.type() == record.type()) {
                reply.addRecord(record);
            }
        }
    }
    if (reply.records().count()) {
        server->sendMessage(reply);
    }
}

QByteArray ResponderPrivate::translate(const QByteArray &name) const
{
    return renames.value(name, name);
}

void ResponderPrivate::insertRecords(const QByteArray &oldName, const QByteArray &newName)
{
    foreach (Record record, pendingRecords.values(oldName)) {
        record.setName(newName);
        records.insert(newName, record);
    }
    pendingRecords.remove(oldName);
    renames.insert(oldName, newName);
}

Responder::Responder(Server *server, QObject *parent)
    : QObject(parent),
      d(new ResponderPrivate(parent, server))
{
}

void Responder::addRecord(const Record &record)
{
    QByteArray name = d->translate(record.name());
    if (d->records.count(name)) {

        // If a record with the same name exists in records, then it is safe to
        // insert the record (changing its name to match)
        Record newRecord = record;
        newRecord.setName(name);
        d->records.insert(name, newRecord);

    } else {

        // Either a pending probe exists (in which case, this record can be
        // added to the pending list) or one does not (in which case, a new
        // probe is started)
        if (!d->pendingRecords.count(name)) {
            Prober *prober = new Prober(d->server, record, this);
            connect(prober, &Prober::nameConfirmed, [this, name](const QByteArray &newName) {
                d->insertRecords(name, newName);
            });
        }
        d->pendingRecords.insert(name, record);
    }
}

void Responder::removeRecord(const Record &record)
{
    // Remove all active records that match
    QByteArray name = d->translate(record.name());
    for (auto i = d->records.find(name); i != d->records.end() && i.key() == name;) {
        if (i.value() == record) {
            i = d->records.erase(i);
        } else {
            ++i;
        }
    }

    // Remove the entry from the translation map if no records are using it
    if (!d->records.count(name)) {
        d->renames.remove(record.name());
    }

    // Remove pending records that match
    d->pendingRecords.remove(record.name(), record);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/targeting/common/hbrt_target.C $                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#include <targeting/common/hbrt_target.H>
#include <targeting/common/targetservice.H>
#include <targeting/common/targreasoncodes.H>
#include <targeting/common/trace.H>
#include <targeting/targplatutil.H>
#ifdef __HOSTBOOT_MODULE
#include <errl/errludtarget.H>
#include <limits.h>
#else
#define KILOBYTE  (1024ul)            /**< 1 KB */
#define MEGABYTE  (1024 * 1024ul)     /**< 1 MB */
#define GIGABYTE  (MEGABYTE * 1024ul) /**< 1 GB */
#define TERABYTE  (GIGABYTE * 1024ul) /**< 1 TB */
#endif

extern trace_desc_t* g_trac_hbrt;
using namespace TARGETING;

namespace TARGETING
{

errlHndl_t getRtTarget(
    const TARGETING::Target* i_pTarget,
          rtChipId_t&        o_rtTargetId)
{
    errlHndl_t pError = NULL;

    do
    {
        if(i_pTarget == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL)
        {
            TARGETING::Target* masterProcChip = NULL;
            TARGETING::targetService().
                masterProcChipTargetHandle(masterProcChip);
            i_pTarget = masterProcChip;
        }

        TARGETING::ATTR_HBRT_HYP_ID_type hbrtHypId = HBRT_HYP_ID_UNKNOWN;
        if(   (!i_pTarget->tryGetAttr<TARGETING::ATTR_HBRT_HYP_ID>(hbrtHypId))
           || (hbrtHypId == HBRT_HYP_ID_UNKNOWN))
        {
            TARGETING::ATTR_HUID_type huid = get_huid(i_pTarget);
            TARGETING::ATTR_TYPE_type targetingTargetType =
                i_pTarget->getAttr<TARGETING::ATTR_TYPE>();
            TARG_ERR("getRtTarget: Targeting target type of 0x%08X not supported. "
                     "HUID: 0x%08X",
                     targetingTargetType,
                     huid);
            /*@
             * @errortype
             * @moduleid    TARG_RT_GET_RT_TARGET
             * @reasoncode  TARG_RT_TARGET_TYPE_NOT_SUPPORTED
             * @userdata1   Target's HUID
             * @userdata2   target's targeting type
             * @devdesc     Targeting target's type not supported by runtime
             *              code
             */
            UTIL::createTracingError(TARGETING::TARG_RT_GET_RT_TARGET,
                               TARGETING::TARG_RT_TARGET_TYPE_NOT_SUPPORTED,
                               huid,
                               targetingTargetType,
                               0,0,
                               pError);
#ifdef __HOSTBOOT_MODULE

            ERRORLOG::ErrlUserDetailsTarget(i_pTarget,"Targeting Target").
                addToLog(pError);
#endif
            break;
        }

        o_rtTargetId = hbrtHypId;

    } while(0);

    return pError;
}

errlHndl_t getMemTargetMmioInfo ( TARGETING::Target * i_memTarget,
                                  std::vector<TARGETING::ocmbMmioAddressRange_t>& o_ocmbMmioSpaces)
{
    errlHndl_t l_err;

    do{
        TARGETING::ocmbMmioAddressRange_t l_tmpRange;
        TARGETING::ATTR_TYPE_type l_targetType = i_memTarget->getAttr<TARGETING::ATTR_TYPE>();

        TARG_ASSERT(l_targetType == TARGETING::TYPE_OCMB_CHIP,
              "Target type % passed to getMemTargetMmioInfo."
              " Currently this function only supports TYPE_OCMB_CHIP",
               l_targetType);

        // We need to store in a local variable initially because we cannot
        // pass a ptr to the getRtTarget member of the packed ocmbMmioAddressRange_t struct
        rtChipId_t l_hbrtId;
        l_err = TARGETING::getRtTarget(i_memTarget, l_hbrtId);
        if(l_err)
        {
            break;
        }
        l_tmpRange.hbrtId = l_hbrtId;

        TARGETING::ATTR_MMIO_PHYS_ADDR_type l_ocmbBaseMmioPhysAddr =
                    i_memTarget->getAttr<TARGETING::ATTR_MMIO_PHYS_ADDR>();

        TARG_ASSERT(l_ocmbBaseMmioPhysAddr != 0,
               "0 returned for physical address of OCMB's MMIO space. MMIO map probably isn't set up yet.");

        // CONFIG space ( 2 GB )
        l_tmpRange.mmioBaseAddr = l_ocmbBaseMmioPhysAddr;
        l_tmpRange.mmioEndAddr = l_tmpRange.mmioBaseAddr + (2 * GIGABYTE) - 1;
        l_tmpRange.accessSize = 4;
        o_ocmbMmioSpaces.push_back(l_tmpRange);

        // Microchip Scom Access Space ( 128 MB )
        //   Scom addresses 0x00000000..0x07FFFFFF, no shifting
        l_tmpRange.mmioBaseAddr = l_ocmbBaseMmioPhysAddr + (4 * GIGABYTE);
        l_tmpRange.mmioEndAddr = l_tmpRange.mmioBaseAddr + (128 * MEGABYTE) - 1;
        l_tmpRange.accessSize = 4;
        o_ocmbMmioSpaces.push_back(l_tmpRange);

        // IBM Scom Access Space ( Remainder )
        //   Scom addresses 0x08000000..0x08FFFFFF, then shifted 3 bits left
        //   but we can just cheat and reserve the rest of the 4G..6G range
        l_tmpRange.mmioBaseAddr = l_ocmbBaseMmioPhysAddr + (4 * GIGABYTE) + (128 * MEGABYTE);
        l_tmpRange.mmioEndAddr = l_ocmbBaseMmioPhysAddr + (6 * GIGABYTE) - 1;
        l_tmpRange.accessSize = 8;
        o_ocmbMmioSpaces.push_back(l_tmpRange);

    }while(0);

    return l_err;
}

}
<commit_msg>Increase the Size of Constants on FSP<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/targeting/common/hbrt_target.C $                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2019,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#include <targeting/common/hbrt_target.H>
#include <targeting/common/targetservice.H>
#include <targeting/common/targreasoncodes.H>
#include <targeting/common/trace.H>
#include <targeting/targplatutil.H>
#ifdef __HOSTBOOT_MODULE
#include <errl/errludtarget.H>
#include <limits.h>
#else
#define KILOBYTE  (1024ull)            /**< 1 KB */
#define MEGABYTE  (1024 * 1024ull)     /**< 1 MB */
#define GIGABYTE  (MEGABYTE * 1024ull) /**< 1 GB */
#define TERABYTE  (GIGABYTE * 1024ull) /**< 1 TB */
#endif

extern trace_desc_t* g_trac_hbrt;
using namespace TARGETING;

namespace TARGETING
{

errlHndl_t getRtTarget(
    const TARGETING::Target* i_pTarget,
          rtChipId_t&        o_rtTargetId)
{
    errlHndl_t pError = NULL;

    do
    {
        if(i_pTarget == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL)
        {
            TARGETING::Target* masterProcChip = NULL;
            TARGETING::targetService().
                masterProcChipTargetHandle(masterProcChip);
            i_pTarget = masterProcChip;
        }

        TARGETING::ATTR_HBRT_HYP_ID_type hbrtHypId = HBRT_HYP_ID_UNKNOWN;
        if(   (!i_pTarget->tryGetAttr<TARGETING::ATTR_HBRT_HYP_ID>(hbrtHypId))
           || (hbrtHypId == HBRT_HYP_ID_UNKNOWN))
        {
            TARGETING::ATTR_HUID_type huid = get_huid(i_pTarget);
            TARGETING::ATTR_TYPE_type targetingTargetType =
                i_pTarget->getAttr<TARGETING::ATTR_TYPE>();
            TARG_ERR("getRtTarget: Targeting target type of 0x%08X not supported. "
                     "HUID: 0x%08X",
                     targetingTargetType,
                     huid);
            /*@
             * @errortype
             * @moduleid    TARG_RT_GET_RT_TARGET
             * @reasoncode  TARG_RT_TARGET_TYPE_NOT_SUPPORTED
             * @userdata1   Target's HUID
             * @userdata2   target's targeting type
             * @devdesc     Targeting target's type not supported by runtime
             *              code
             */
            UTIL::createTracingError(TARGETING::TARG_RT_GET_RT_TARGET,
                               TARGETING::TARG_RT_TARGET_TYPE_NOT_SUPPORTED,
                               huid,
                               targetingTargetType,
                               0,0,
                               pError);
#ifdef __HOSTBOOT_MODULE

            ERRORLOG::ErrlUserDetailsTarget(i_pTarget,"Targeting Target").
                addToLog(pError);
#endif
            break;
        }

        o_rtTargetId = hbrtHypId;

    } while(0);

    return pError;
}

errlHndl_t getMemTargetMmioInfo ( TARGETING::Target * i_memTarget,
                                  std::vector<TARGETING::ocmbMmioAddressRange_t>& o_ocmbMmioSpaces)
{
    errlHndl_t l_err;

    do{
        TARGETING::ocmbMmioAddressRange_t l_tmpRange;
        TARGETING::ATTR_TYPE_type l_targetType = i_memTarget->getAttr<TARGETING::ATTR_TYPE>();

        TARG_ASSERT(l_targetType == TARGETING::TYPE_OCMB_CHIP,
              "Target type % passed to getMemTargetMmioInfo."
              " Currently this function only supports TYPE_OCMB_CHIP",
               l_targetType);

        // We need to store in a local variable initially because we cannot
        // pass a ptr to the getRtTarget member of the packed ocmbMmioAddressRange_t struct
        rtChipId_t l_hbrtId;
        l_err = TARGETING::getRtTarget(i_memTarget, l_hbrtId);
        if(l_err)
        {
            break;
        }
        l_tmpRange.hbrtId = l_hbrtId;

        TARGETING::ATTR_MMIO_PHYS_ADDR_type l_ocmbBaseMmioPhysAddr =
                    i_memTarget->getAttr<TARGETING::ATTR_MMIO_PHYS_ADDR>();

        TARG_ASSERT(l_ocmbBaseMmioPhysAddr != 0,
               "0 returned for physical address of OCMB's MMIO space. MMIO map probably isn't set up yet.");

        // CONFIG space ( 2 GB )
        l_tmpRange.mmioBaseAddr = l_ocmbBaseMmioPhysAddr;
        l_tmpRange.mmioEndAddr = l_tmpRange.mmioBaseAddr + (2 * GIGABYTE) - 1;
        l_tmpRange.accessSize = 4;
        o_ocmbMmioSpaces.push_back(l_tmpRange);

        // Microchip Scom Access Space ( 128 MB )
        //   Scom addresses 0x00000000..0x07FFFFFF, no shifting
        l_tmpRange.mmioBaseAddr = l_ocmbBaseMmioPhysAddr + (4 * GIGABYTE);
        l_tmpRange.mmioEndAddr = l_tmpRange.mmioBaseAddr + (128 * MEGABYTE) - 1;
        l_tmpRange.accessSize = 4;
        o_ocmbMmioSpaces.push_back(l_tmpRange);

        // IBM Scom Access Space ( Remainder )
        //   Scom addresses 0x08000000..0x08FFFFFF, then shifted 3 bits left
        //   but we can just cheat and reserve the rest of the 4G..6G range
        l_tmpRange.mmioBaseAddr = l_ocmbBaseMmioPhysAddr + (4 * GIGABYTE) + (128 * MEGABYTE);
        l_tmpRange.mmioEndAddr = l_ocmbBaseMmioPhysAddr + (6 * GIGABYTE) - 1;
        l_tmpRange.accessSize = 8;
        o_ocmbMmioSpaces.push_back(l_tmpRange);

    }while(0);

    return l_err;
}

}
<|endoftext|>


<commit_before>/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <iostream>

#include "sx6119.h"

using namespace upm;
using namespace std;

SX6119::SX6119(int powerPin, int seekPin)
{
  if ( !(m_gpioPower = mraa_gpio_init(powerPin)) )
    {
      cerr << __FUNCTION__ << ": mraa_gpio_init() failed" << endl;
      return;
    }

  mraa_gpio_dir(m_gpioPower, MRAA_GPIO_OUT);
  mraa_gpio_write(m_gpioPower, 1);

  if ( !(m_gpioSeek = mraa_gpio_init(seekPin)) )
    {
      cerr << __FUNCTION__ << ": mraa_gpio_init() failed" << endl;
      return;
    }

  mraa_gpio_dir(m_gpioSeek, MRAA_GPIO_OUT);
  mraa_gpio_write(m_gpioSeek, 1);
}

SX6119::~SX6119()
{
  mraa_gpio_close(m_gpioPower);
  mraa_gpio_close(m_gpioSeek);
}

void SX6119::togglePower()
{
  // this is just a toggle -- we set LOW for one second and power will
  // be turned on or off depending on the previous condition.
  mraa_gpio_write(m_gpioPower, 0);
  sleep(1);
  mraa_gpio_write(m_gpioPower, 1);
}

void SX6119::seek()
{
  // this is just a trigger -- we set LOW for 500ms to seek to the
  // next available station, wrapping around when we reach the end.
  mraa_gpio_write(m_gpioSeek, 0);
  usleep(500000);
  mraa_gpio_write(m_gpioSeek, 1);
}
<commit_msg>sx6119: throw exception(s) on fatal errors<commit_after>/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <iostream>
#include <string>
#include <stdexcept>

#include "sx6119.h"

using namespace upm;
using namespace std;

SX6119::SX6119(int powerPin, int seekPin)
{
  if ( !(m_gpioPower = mraa_gpio_init(powerPin)) )
    {
      throw std::invalid_argument(std::string(__FUNCTION__) +
                                  ": mraa_gpio_init(power) failed, invalid pin?");
      return;
    }

  mraa_gpio_dir(m_gpioPower, MRAA_GPIO_OUT);
  mraa_gpio_write(m_gpioPower, 1);

  if ( !(m_gpioSeek = mraa_gpio_init(seekPin)) )
    {
      throw std::invalid_argument(std::string(__FUNCTION__) +
                                  ": mraa_gpio_init(seek) failed, invalid pin?");
      return;
    }

  mraa_gpio_dir(m_gpioSeek, MRAA_GPIO_OUT);
  mraa_gpio_write(m_gpioSeek, 1);
}

SX6119::~SX6119()
{
  mraa_gpio_close(m_gpioPower);
  mraa_gpio_close(m_gpioSeek);
}

void SX6119::togglePower()
{
  // this is just a toggle -- we set LOW for one second and power will
  // be turned on or off depending on the previous condition.
  mraa_gpio_write(m_gpioPower, 0);
  sleep(1);
  mraa_gpio_write(m_gpioPower, 1);
}

void SX6119::seek()
{
  // this is just a trigger -- we set LOW for 500ms to seek to the
  // next available station, wrapping around when we reach the end.
  mraa_gpio_write(m_gpioSeek, 0);
  usleep(500000);
  mraa_gpio_write(m_gpioSeek, 1);
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Audio.h"
#include "SoundResource.h"

namespace ouzel
{
    namespace audio
    {
        Audio::Audio(Driver aDriver):
            driver(aDriver)
        {
        }

        Audio::~Audio()
        {
            running = false;

#if OUZEL_MULTITHREADED
            if (audioThread.joinable()) audioThread.join();
#endif
        }

        bool Audio::init()
        {
#if OUZEL_MULTITHREADED
            audioThread = std::thread(&Audio::run, this);
#endif

            return true;
        }

        bool Audio::update()
        {
            std::lock_guard<std::mutex> lock(resourceMutex);

            for (const std::unique_ptr<Resource>& resource : resources)
            {
                resource->update();
            }

            return true;
        }

        void Audio::deleteResource(Resource* resource)
        {
            std::lock_guard<std::mutex> lock(resourceMutex);

            // TODO: delete
        }

        void Audio::setListenerPosition(const Vector3& newPosition)
        {
            listenerPosition = newPosition;
        }

        void Audio::setListenerRotation(const Quaternion& newRotation)
        {
            listenerRotation = newRotation;
        }

        void Audio::run()
        {
            while (running)
            {
                update();

                std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
        }

        void Audio::stop()
        {
            running = false;

#if OUZEL_MULTITHREADED
            if (audioThread.joinable()) audioThread.join();
#endif
        }
    } // namespace audio
} // namespace ouzel
<commit_msg>Implement Audio resource deleting<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Audio.h"
#include "SoundResource.h"

namespace ouzel
{
    namespace audio
    {
        Audio::Audio(Driver aDriver):
            driver(aDriver)
        {
        }

        Audio::~Audio()
        {
            running = false;

#if OUZEL_MULTITHREADED
            if (audioThread.joinable()) audioThread.join();
#endif
        }

        bool Audio::init()
        {
#if OUZEL_MULTITHREADED
            audioThread = std::thread(&Audio::run, this);
#endif

            return true;
        }

        bool Audio::update()
        {
            std::lock_guard<std::mutex> lock(resourceMutex);

            for (const std::unique_ptr<Resource>& resource : resources)
            {
                resource->update();
            }

            return true;
        }

        void Audio::deleteResource(Resource* resource)
        {
            std::lock_guard<std::mutex> lock(resourceMutex);

            std::vector<std::unique_ptr<Resource>>::iterator i = std::find_if(resources.begin(), resources.end(), [resource](const std::unique_ptr<Resource>& ptr) {
                return ptr.get() == resource;
            });

            if (i != resources.end())
            {
                resourceDeleteSet.push_back(std::move(*i));
                resources.erase(i);
            }
        }

        void Audio::setListenerPosition(const Vector3& newPosition)
        {
            listenerPosition = newPosition;
        }

        void Audio::setListenerRotation(const Quaternion& newRotation)
        {
            listenerRotation = newRotation;
        }

        void Audio::run()
        {
            while (running)
            {
                update();

                std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
        }

        void Audio::stop()
        {
            running = false;

#if OUZEL_MULTITHREADED
            if (audioThread.joinable()) audioThread.join();
#endif
        }
    } // namespace audio
} // namespace ouzel
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Sound.hpp"
#include "Audio.hpp"
#include "AudioDevice.hpp"
#include "SoundData.hpp"
#include "Stream.hpp"
#include "core/Engine.hpp"
#include "math/MathUtils.hpp"

namespace ouzel
{
    namespace audio
    {
        Sound::Sound():
            scene::Component(scene::Component::SOUND)
        {
            updateCallback.callback = std::bind(&Sound::update, this, std::placeholders::_1);
        }

        Sound::~Sound()
        {
        }

        bool Sound::init(const std::shared_ptr<SoundData>& newSoundData)
        {
            soundData = newSoundData;
            stream = soundData->createStream();
            resetCount = 0;

            return true;
        }

        void Sound::update(float)
        {
            if (stream)
            {
                uint32_t newResetCount = stream->getResetCount();

                for (uint32_t i = resetCount; i < newResetCount; ++i)
                {
                    Event resetEvent;
                    resetEvent.type = Event::Type::SOUND_RESET;
                    resetEvent.soundEvent.sound = this;
                    ++resetCount;
                }

                if (!stream->isPlaying())
                {
                    playing = false;

                    Event resetEvent;
                    resetEvent.type = Event::Type::SOUND_FINISH;
                    resetEvent.soundEvent.sound = this;

                    sharedEngine->unscheduleUpdate(&updateCallback);
                }

                if (actor) position = actor->getWorldPosition();
            }
            else
            {
                sharedEngine->unscheduleUpdate(&updateCallback);
            }
        }

        void Sound::setPosition(const Vector3& newPosition)
        {
            position = newPosition;
        }

        void Sound::setPitch(float newPitch)
        {
            pitch = newPitch;
        }

        void Sound::setGain(float newGain)
        {
            gain = newGain;
        }

        void Sound::setRolloffFactor(float newRolloffFactor)
        {
            rolloffFactor = newRolloffFactor;
        }

        void Sound::setMinDistance(float newMinDistance)
        {
            minDistance = newMinDistance;
        }

        void Sound::setMaxDistance(float newMaxDistance)
        {
            maxDistance = newMaxDistance;
        }

        void Sound::setSpatialized(bool newSpatialized)
        {
            spatialized = newSpatialized;
        }

        bool Sound::play(bool repeatSound)
        {
            if (actor) position = actor->getWorldPosition();

            playing = true;
            repeating = repeatSound;

            Event resetEvent;
            resetEvent.type = Event::Type::SOUND_START;
            resetEvent.soundEvent.sound = this;

            if (stream)
            {
                stream->setRepeating(repeatSound);
                stream->setPlaying(true);
            }

            sharedEngine->scheduleUpdate(&updateCallback);

            return true;
        }

        bool Sound::pause()
        {
            playing = false;
            if (stream) stream->setPlaying(false);

            sharedEngine->unscheduleUpdate(&updateCallback);

            return true;
        }

        bool Sound::stop()
        {
            playing = false;
            if (stream)
            {
                stream->setPlaying(false);
                stream->setShouldReset(true);
            }

            sharedEngine->unscheduleUpdate(&updateCallback);

            return true;
        }

        AudioDevice::RenderCommand Sound::getRenderCommand()
        {
            AudioDevice::RenderCommand renderCommand;

            renderCommand.attributeCallback = std::bind(&Sound::setAttributes,
                                                        std::placeholders::_1,
                                                        std::placeholders::_2,
                                                        std::placeholders::_3,
                                                        std::placeholders::_4,
                                                        std::placeholders::_5,
                                                        pitch,
                                                        gain,
                                                        rolloffFactor);

            renderCommand.renderCallback = std::bind(&Sound::render,
                                                     std::placeholders::_1,
                                                     std::placeholders::_2,
                                                     std::placeholders::_3,
                                                     std::placeholders::_4,
                                                     std::placeholders::_5,
                                                     std::placeholders::_6,
                                                     std::placeholders::_7,
                                                     std::placeholders::_8,
                                                     std::placeholders::_9,
                                                     soundData,
                                                     stream,
                                                     position,
                                                     minDistance,
                                                     maxDistance,
                                                     spatialized);

            return renderCommand;
        }

        void Sound::setAttributes(Vector3&,
                                  Quaternion&,
                                  float& pitch,
                                  float& gain,
                                  float& rolloffFactor,
                                  float pitchScale,
                                  float gainScale,
                                  float rolloffScale)
        {
            pitch *= pitchScale;
            gain *= gainScale;
            rolloffFactor *= rolloffScale;
        }

        bool Sound::render(uint32_t frames,
                           uint16_t channels,
                           uint32_t sampleRate,
                           const Vector3& listenerPosition,
                           const Quaternion& listenerRotation,
                           float pitch,
                           float gain,
                           float rolloffFactor,
                           std::vector<float>& result,
                           const std::shared_ptr<SoundData>& soundData,
                           const std::shared_ptr<Stream>& stream,
                           const Vector3& position,
                           float minDistance,
                           float maxDistance,
                           bool spatialized)
        {
            if (soundData && soundData->getChannels() > 0 && stream)
            {
                if (!stream->isPlaying())
                {
                    result.clear();
                }
                else
                {
                    if (stream->getShouldReset())
                    {
                        stream->reset();
                        stream->setShouldReset(false);
                    }

                    soundData->getData(stream.get(), frames, channels, sampleRate, pitch, result);

                    std::vector<float> channelVolume(channels, gain);

                    if (spatialized)
                    {
                        Vector3 offset = position - listenerPosition;
                        float distance = clamp(offset.length(), minDistance, maxDistance);
                        float attenuation = minDistance / (minDistance + rolloffFactor * (distance - minDistance)); // inverse distance

                        for (float& volume : channelVolume)
                        {
                            volume *= attenuation;
                        }

                        if (channelVolume.size() > 1)
                        {
                            Quaternion inverseRotation = -listenerRotation;
                            Vector3 relative = inverseRotation * offset;
                            relative.normalize();
                            float angle = atan2f(relative.x, relative.z);
                            float c = cosf(angle);
                            float s = sinf(angle);

                            // constant power panning
                            channelVolume[0] *= clamp(SQRT2 / 2.0f * (c - s), 0.0f, 1.0f);
                            channelVolume[1] *= clamp(SQRT2 / 2.0f * (c + s), 0.0f, 1.0f);
                        }
                    }

                    for (uint32_t frame = 0; frame < result.size() / channels; ++frame)
                    {
                        for (uint32_t channel = 0; channel < channels; ++channel)
                        {
                            result[frame * channels + channel] *= channelVolume[channel];
                        }
                    }
                }
            }

            return true;
        }
    } // namespace audio
} // namespace ouzel
<commit_msg>Add callbacks only if sound data is set<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Sound.hpp"
#include "Audio.hpp"
#include "AudioDevice.hpp"
#include "SoundData.hpp"
#include "Stream.hpp"
#include "core/Engine.hpp"
#include "math/MathUtils.hpp"

namespace ouzel
{
    namespace audio
    {
        Sound::Sound():
            scene::Component(scene::Component::SOUND)
        {
            updateCallback.callback = std::bind(&Sound::update, this, std::placeholders::_1);
        }

        Sound::~Sound()
        {
        }

        bool Sound::init(const std::shared_ptr<SoundData>& newSoundData)
        {
            soundData = newSoundData;
            stream = soundData->createStream();
            resetCount = 0;

            return true;
        }

        void Sound::update(float)
        {
            if (stream)
            {
                uint32_t newResetCount = stream->getResetCount();

                for (uint32_t i = resetCount; i < newResetCount; ++i)
                {
                    Event resetEvent;
                    resetEvent.type = Event::Type::SOUND_RESET;
                    resetEvent.soundEvent.sound = this;
                    ++resetCount;
                }

                if (!stream->isPlaying())
                {
                    playing = false;

                    Event resetEvent;
                    resetEvent.type = Event::Type::SOUND_FINISH;
                    resetEvent.soundEvent.sound = this;

                    sharedEngine->unscheduleUpdate(&updateCallback);
                }

                if (actor) position = actor->getWorldPosition();
            }
            else
            {
                sharedEngine->unscheduleUpdate(&updateCallback);
            }
        }

        void Sound::setPosition(const Vector3& newPosition)
        {
            position = newPosition;
        }

        void Sound::setPitch(float newPitch)
        {
            pitch = newPitch;
        }

        void Sound::setGain(float newGain)
        {
            gain = newGain;
        }

        void Sound::setRolloffFactor(float newRolloffFactor)
        {
            rolloffFactor = newRolloffFactor;
        }

        void Sound::setMinDistance(float newMinDistance)
        {
            minDistance = newMinDistance;
        }

        void Sound::setMaxDistance(float newMaxDistance)
        {
            maxDistance = newMaxDistance;
        }

        void Sound::setSpatialized(bool newSpatialized)
        {
            spatialized = newSpatialized;
        }

        bool Sound::play(bool repeatSound)
        {
            if (actor) position = actor->getWorldPosition();

            playing = true;
            repeating = repeatSound;

            Event resetEvent;
            resetEvent.type = Event::Type::SOUND_START;
            resetEvent.soundEvent.sound = this;

            if (stream)
            {
                stream->setRepeating(repeatSound);
                stream->setPlaying(true);
            }

            sharedEngine->scheduleUpdate(&updateCallback);

            return true;
        }

        bool Sound::pause()
        {
            playing = false;
            if (stream) stream->setPlaying(false);

            sharedEngine->unscheduleUpdate(&updateCallback);

            return true;
        }

        bool Sound::stop()
        {
            playing = false;
            if (stream)
            {
                stream->setPlaying(false);
                stream->setShouldReset(true);
            }

            sharedEngine->unscheduleUpdate(&updateCallback);

            return true;
        }

        AudioDevice::RenderCommand Sound::getRenderCommand()
        {
            AudioDevice::RenderCommand renderCommand;

            if (soundData)
            {
                renderCommand.attributeCallback = std::bind(&Sound::setAttributes,
                                                            std::placeholders::_1,
                                                            std::placeholders::_2,
                                                            std::placeholders::_3,
                                                            std::placeholders::_4,
                                                            std::placeholders::_5,
                                                            pitch,
                                                            gain,
                                                            rolloffFactor);

                renderCommand.renderCallback = std::bind(&Sound::render,
                                                         std::placeholders::_1,
                                                         std::placeholders::_2,
                                                         std::placeholders::_3,
                                                         std::placeholders::_4,
                                                         std::placeholders::_5,
                                                         std::placeholders::_6,
                                                         std::placeholders::_7,
                                                         std::placeholders::_8,
                                                         std::placeholders::_9,
                                                         soundData,
                                                         stream,
                                                         position,
                                                         minDistance,
                                                         maxDistance,
                                                         spatialized);
            }

            return renderCommand;
        }

        void Sound::setAttributes(Vector3&,
                                  Quaternion&,
                                  float& pitch,
                                  float& gain,
                                  float& rolloffFactor,
                                  float pitchScale,
                                  float gainScale,
                                  float rolloffScale)
        {
            pitch *= pitchScale;
            gain *= gainScale;
            rolloffFactor *= rolloffScale;
        }

        bool Sound::render(uint32_t frames,
                           uint16_t channels,
                           uint32_t sampleRate,
                           const Vector3& listenerPosition,
                           const Quaternion& listenerRotation,
                           float pitch,
                           float gain,
                           float rolloffFactor,
                           std::vector<float>& result,
                           const std::shared_ptr<SoundData>& soundData,
                           const std::shared_ptr<Stream>& stream,
                           const Vector3& position,
                           float minDistance,
                           float maxDistance,
                           bool spatialized)
        {
            if (soundData && soundData->getChannels() > 0 && stream)
            {
                if (!stream->isPlaying())
                {
                    result.clear();
                }
                else
                {
                    if (stream->getShouldReset())
                    {
                        stream->reset();
                        stream->setShouldReset(false);
                    }

                    soundData->getData(stream.get(), frames, channels, sampleRate, pitch, result);

                    std::vector<float> channelVolume(channels, gain);

                    if (spatialized)
                    {
                        Vector3 offset = position - listenerPosition;
                        float distance = clamp(offset.length(), minDistance, maxDistance);
                        float attenuation = minDistance / (minDistance + rolloffFactor * (distance - minDistance)); // inverse distance

                        for (float& volume : channelVolume)
                        {
                            volume *= attenuation;
                        }

                        if (channelVolume.size() > 1)
                        {
                            Quaternion inverseRotation = -listenerRotation;
                            Vector3 relative = inverseRotation * offset;
                            relative.normalize();
                            float angle = atan2f(relative.x, relative.z);
                            float c = cosf(angle);
                            float s = sinf(angle);

                            // constant power panning
                            channelVolume[0] *= clamp(SQRT2 / 2.0f * (c - s), 0.0f, 1.0f);
                            channelVolume[1] *= clamp(SQRT2 / 2.0f * (c + s), 0.0f, 1.0f);
                        }
                    }

                    for (uint32_t frame = 0; frame < result.size() / channels; ++frame)
                    {
                        for (uint32_t channel = 0; channel < channels; ++channel)
                        {
                            result[frame * channels + channel] *= channelVolume[channel];
                        }
                    }
                }
            }

            return true;
        }
    } // namespace audio
} // namespace ouzel
<|endoftext|>


<commit_before>/*
 * MomentumUpdater.cpp
 *
 *  Created on: Feburary 27, 2014
 *      Author: slundquist
 */

#include "MomentumUpdater.hpp"

namespace PV {

MomentumUpdater::MomentumUpdater(char const *name, PVParams *params, Communicator const *comm) {
   initialize(name, params, comm);
}

void MomentumUpdater::initialize(char const *name, PVParams *params, Communicator const *comm) {
   HebbianUpdater::initialize(name, params, comm);
}

void MomentumUpdater::setObjectType() { mObjectType = "MomentumUpdater"; }

int MomentumUpdater::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
   int status = HebbianUpdater::ioParamsFillGroup(ioFlag);
   ioParam_momentumMethod(ioFlag);
   ioParam_timeConstantTau(ioFlag);
   ioParam_momentumTau(ioFlag);
   ioParam_momentumDecay(ioFlag);
   return status;
}

void MomentumUpdater::ioParam_momentumMethod(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      parameters()->ioParamStringRequired(ioFlag, name, "momentumMethod", &mMomentumMethod);
      if (strcmp(mMomentumMethod, "viscosity") == 0) {
         mMethod = VISCOSITY;
      }
      else if (strcmp(mMomentumMethod, "simple") == 0) {
         mMethod = SIMPLE;
      }
      else if (strcmp(mMomentumMethod, "alex") == 0) {
         mMethod = ALEX;
      }
      else {
         Fatal() << "MomentumUpdater " << name << ": momentumMethod of " << mMomentumMethod
                 << " is not known. Options are \"viscosity\", \"simple\", and \"alex\".\n";
      }
   }
}

void MomentumUpdater::ioParam_timeConstantTau(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      pvAssert(!parameters()->presentAndNotBeenRead(name, "momentumMethod"));
      float defaultVal = 0;
      switch (mMethod) {
         case VISCOSITY: defaultVal = mDefaultTimeConstantTauViscosity; break;
         case SIMPLE: defaultVal    = mDefaultTimeConstantTauSimple; break;
         case ALEX: defaultVal      = mDefaultTimeConstantTauAlex; break;
         default: pvAssertMessage(0, "Unrecognized momentumMethod\n"); break;
      }

      // If momentumTau is being used instead of timeConstantTau, ioParam_momentumTau
      // will print a warning, so we don't warn if timeConstantTau is absent here.
      // When momentumTau is removed, warnIfAbsent should be set to true here.
      bool warnIfAbsent = !parameters()->present(getName(), "momentumTau");
      parameters()->ioParamValue(
            ioFlag, name, "timeConstantTau", &mTimeConstantTau, defaultVal, warnIfAbsent);
      if (ioFlag == PARAMS_IO_READ) {
         checkTimeConstantTau();
      }
   }
}

void MomentumUpdater::checkTimeConstantTau() {
   switch (mMethod) {
      case VISCOSITY:
         FatalIf(
               mTimeConstantTau < 0,
               "%s uses momentumMethod \"viscosity\" and so must have "
               "TimeConstantTau >= 0"
               " (value is %f).\n",
               getDescription_c(),
               (double)mTimeConstantTau);
         break;
      case SIMPLE:
         FatalIf(
               mTimeConstantTau < 0 or mTimeConstantTau >= 1,
               "%s uses momentumMethod \"simple\" and so must have "
               "TimeConstantTau >= 0 and timeConstantTau < 1"
               " (value is %f).\n",
               getDescription_c(),
               (double)mTimeConstantTau);
         break;
      case ALEX:
         FatalIf(
               mTimeConstantTau < 0 or mTimeConstantTau >= 1,
               "%s uses momentumMethod \"alex\" and so must have "
               "TimeConstantTau >= 0 and timeConstantTau < 1"
               " (value is %f).\n",
               getDescription_c(),
               (double)mTimeConstantTau);
         break;
   }
}

void MomentumUpdater::ioParam_momentumTau(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      pvAssert(!parameters()->presentAndNotBeenRead(name, "momentumMethod"));
      pvAssert(!parameters()->presentAndNotBeenRead(name, "timeConstantTau"));
      if (!parameters()->present(getName(), "momentumTau")) {
         return;
      }
      if (parameters()->present(getName(), "timeConstantTau")) {
         WarnLog().printf(
               "%s sets timeConstantTau, so momentumTau will be ignored.\n", getDescription_c());
         return;
      }
      mUsingDeprecatedMomentumTau = true;
      parameters()->ioParamValueRequired(ioFlag, name, "momentumTau", &mMomentumTau);
      WarnLog().printf(
            "%s uses momentumTau, which is deprecated. Use timeConstantTau instead.\n",
            getDescription_c());
   }
}

void MomentumUpdater::ioParam_momentumDecay(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      parameters()->ioParamValue(ioFlag, name, "momentumDecay", &mMomentumDecay, mMomentumDecay);
      if (mMomentumDecay < 0.0f || mMomentumDecay > 1.0f) {
         Fatal() << "MomentumUpdater " << name
                 << ": momentumDecay must be between 0 and 1 inclusive\n";
      }
   }
}

Response::Status MomentumUpdater::allocateDataStructures() {
   auto status = HebbianUpdater::allocateDataStructures();
   if (!Response::completed(status)) {
      return status;
   }
   if (!mPlasticityFlag) {
      return status;
   }
   mPrevDeltaWeights = new Weights(name);
   mPrevDeltaWeights->initialize(mWeights);
   mPrevDeltaWeights->setMargins(
         mConnectionData->getPre()->getLayerLoc()->halo,
         mConnectionData->getPost()->getLayerLoc()->halo);
   mPrevDeltaWeights->allocateDataStructures();
   return Response::SUCCESS;
}

Response::Status
MomentumUpdater::registerData(std::shared_ptr<RegisterDataMessage<Checkpointer> const> message) {
   auto status = HebbianUpdater::registerData(message);
   if (!Response::completed(status)) {
      return status;
   }
   // Note: HebbianUpdater does not checkpoint dW if the mImmediateWeightUpdate flag is true.
   // Do we need to handle it here and in readStateFromCheckpoint? --pschultz, 2017-12-16
   if (mPlasticityFlag) {
      auto *checkpointer = message->mDataRegistry;
      mPrevDeltaWeights->checkpointWeightPvp(
            checkpointer, name, "prev_dW", mWriteCompressedCheckpoints);
   }
   return Response::SUCCESS;
}

Response::Status MomentumUpdater::readStateFromCheckpoint(Checkpointer *checkpointer) {
   pvAssert(mInitializeFromCheckpointFlag);
   // Note: HebbianUpdater does not checkpoint dW if the mImmediateWeightUpdate flag is true.
   // Do we need to handle it here and in registerData? --pschultz, 2017-12-16
   if (mPlasticityFlag) {
      checkpointer->readNamedCheckpointEntry(
            std::string(name), std::string("prev_dW"), false /*not constant*/);
   }
   return Response::SUCCESS;
}

int MomentumUpdater::updateWeights(int arborId) {
   // Add momentum right before updateWeights
   if (mUsingDeprecatedMomentumTau) { // MomentumTau was deprecated Nov 19, 2018.
      WarnLog().printf(
            "%s is using momentumTau, which has been deprecated in favor of timeConstantTau.\n",
            getDescription_c());
      applyMomentumDeprecated(arborId);
   }
   else {
      applyMomentum(arborId);
   }

   // Current dW saved to prev_dW
   pvAssert(mPrevDeltaWeights);
   std::memcpy(
         mPrevDeltaWeights->getData(arborId),
         mDeltaWeights->getDataReadOnly(arborId),
         sizeof(float) * mDeltaWeights->getPatchSizeOverall() * mDeltaWeights->getNumDataPatches());

   // add dw to w
   return HebbianUpdater::updateWeights(arborId);
}

void MomentumUpdater::applyMomentum(int arborId) {
   // Shared weights done in parallel, parallel in numkernels
   switch (mMethod) {
      case VISCOSITY:
         applyMomentum(arborId, std::exp(-1.0f / mTimeConstantTau), mMomentumDecay);
         break;
      case SIMPLE: applyMomentum(arborId, mTimeConstantTau, mMomentumDecay); break;
      case ALEX: applyMomentum(arborId, mTimeConstantTau, mMomentumDecay * mDWMax); break;
      default: pvAssertMessage(0, "Unrecognized momentumMethod\n"); break;
   }
}

void MomentumUpdater::applyMomentum(int arborId, float dwFactor, float wFactor) {
   int const numKernels = mDeltaWeights->getNumDataPatches();
   pvAssert(numKernels == mPrevDeltaWeights->getNumDataPatches());
   int const patchSizeOverall = mDeltaWeights->getPatchSizeOverall();
   pvAssert(patchSizeOverall == mPrevDeltaWeights->getPatchSizeOverall());
#ifdef PV_USE_OPENMP_THREADS
#pragma omp parallel for
#endif
   for (int kernelIdx = 0; kernelIdx < numKernels; kernelIdx++) {
      float *dwdata_start        = mDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *prev_dw_start = mPrevDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *wdata_start   = mWeights->getDataFromDataIndex(arborId, kernelIdx);
      for (int k = 0; k < patchSizeOverall; k++) {
         dwdata_start[k] *= 1 - dwFactor;
         dwdata_start[k] += dwFactor * prev_dw_start[k];
         dwdata_start[k] -= wFactor * wdata_start[k]; // TODO handle decay in a separate component
      }
   }
   // Since weights data is allocated with all patches of a given arbor in a single vector,
   // these two for-loops can probably be collapsed. --pschultz 2017-12-16
}

void MomentumUpdater::applyMomentumDeprecated(int arborId) {
   // Shared weights done in parallel, parallel in numkernels
   switch (mMethod) {
      case VISCOSITY:
         applyMomentumDeprecated(arborId, std::exp(-1.0f / mMomentumTau), mMomentumDecay);
         break;
      case SIMPLE: applyMomentumDeprecated(arborId, mMomentumTau, mMomentumDecay); break;
      case ALEX: applyMomentumDeprecated(arborId, mMomentumTau, mMomentumDecay * mDWMax); break;
      default: pvAssertMessage(0, "Unrecognized momentumMethod\n"); break;
   }
}

void MomentumUpdater::applyMomentumDeprecated(int arborId, float dwFactor, float wFactor) {
   int const numKernels = mDeltaWeights->getNumDataPatches();
   pvAssert(numKernels == mPrevDeltaWeights->getNumDataPatches());
   int const patchSizeOverall = mDeltaWeights->getPatchSizeOverall();
   pvAssert(patchSizeOverall == mPrevDeltaWeights->getPatchSizeOverall());
#ifdef PV_USE_OPENMP_THREADS
#pragma omp parallel for
#endif
   for (int kernelIdx = 0; kernelIdx < numKernels; kernelIdx++) {
      float *dwdata_start        = mDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *prev_dw_start = mPrevDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *wdata_start   = mWeights->getDataFromDataIndex(arborId, kernelIdx);
      for (int k = 0; k < patchSizeOverall; k++) {
         dwdata_start[k] += dwFactor * prev_dw_start[k] - wFactor * wdata_start[k];
      }
   }
   // Since weights data is allocated with all patches of a given arbor in a single vector,
   // these two for-loops can probably be collapsed. --pschultz 2017-12-16
}

} // namespace PV
<commit_msg>Adds default case to switch statement<commit_after>/*
 * MomentumUpdater.cpp
 *
 *  Created on: Feburary 27, 2014
 *      Author: slundquist
 */

#include "MomentumUpdater.hpp"

namespace PV {

MomentumUpdater::MomentumUpdater(char const *name, PVParams *params, Communicator const *comm) {
   initialize(name, params, comm);
}

void MomentumUpdater::initialize(char const *name, PVParams *params, Communicator const *comm) {
   HebbianUpdater::initialize(name, params, comm);
}

void MomentumUpdater::setObjectType() { mObjectType = "MomentumUpdater"; }

int MomentumUpdater::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
   int status = HebbianUpdater::ioParamsFillGroup(ioFlag);
   ioParam_momentumMethod(ioFlag);
   ioParam_timeConstantTau(ioFlag);
   ioParam_momentumTau(ioFlag);
   ioParam_momentumDecay(ioFlag);
   return status;
}

void MomentumUpdater::ioParam_momentumMethod(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      parameters()->ioParamStringRequired(ioFlag, name, "momentumMethod", &mMomentumMethod);
      if (strcmp(mMomentumMethod, "viscosity") == 0) {
         mMethod = VISCOSITY;
      }
      else if (strcmp(mMomentumMethod, "simple") == 0) {
         mMethod = SIMPLE;
      }
      else if (strcmp(mMomentumMethod, "alex") == 0) {
         mMethod = ALEX;
      }
      else {
         Fatal() << "MomentumUpdater " << name << ": momentumMethod of " << mMomentumMethod
                 << " is not known. Options are \"viscosity\", \"simple\", and \"alex\".\n";
      }
   }
}

void MomentumUpdater::ioParam_timeConstantTau(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      pvAssert(!parameters()->presentAndNotBeenRead(name, "momentumMethod"));
      float defaultVal = 0;
      switch (mMethod) {
         case VISCOSITY: defaultVal = mDefaultTimeConstantTauViscosity; break;
         case SIMPLE: defaultVal    = mDefaultTimeConstantTauSimple; break;
         case ALEX: defaultVal      = mDefaultTimeConstantTauAlex; break;
         default: pvAssertMessage(0, "Unrecognized momentumMethod\n"); break;
      }

      // If momentumTau is being used instead of timeConstantTau, ioParam_momentumTau
      // will print a warning, so we don't warn if timeConstantTau is absent here.
      // When momentumTau is removed, warnIfAbsent should be set to true here.
      bool warnIfAbsent = !parameters()->present(getName(), "momentumTau");
      parameters()->ioParamValue(
            ioFlag, name, "timeConstantTau", &mTimeConstantTau, defaultVal, warnIfAbsent);
      if (ioFlag == PARAMS_IO_READ) {
         checkTimeConstantTau();
      }
   }
}

void MomentumUpdater::checkTimeConstantTau() {
   switch (mMethod) {
      case VISCOSITY:
         FatalIf(
               mTimeConstantTau < 0,
               "%s uses momentumMethod \"viscosity\" and so must have "
               "TimeConstantTau >= 0"
               " (value is %f).\n",
               getDescription_c(),
               (double)mTimeConstantTau);
         break;
      case SIMPLE:
         FatalIf(
               mTimeConstantTau < 0 or mTimeConstantTau >= 1,
               "%s uses momentumMethod \"simple\" and so must have "
               "TimeConstantTau >= 0 and timeConstantTau < 1"
               " (value is %f).\n",
               getDescription_c(),
               (double)mTimeConstantTau);
         break;
      case ALEX:
         FatalIf(
               mTimeConstantTau < 0 or mTimeConstantTau >= 1,
               "%s uses momentumMethod \"alex\" and so must have "
               "TimeConstantTau >= 0 and timeConstantTau < 1"
               " (value is %f).\n",
               getDescription_c(),
               (double)mTimeConstantTau);
         break;
      default: Fatal().printf("Unrecognized momentumMethod\n"); break;
   }
}

void MomentumUpdater::ioParam_momentumTau(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      pvAssert(!parameters()->presentAndNotBeenRead(name, "momentumMethod"));
      pvAssert(!parameters()->presentAndNotBeenRead(name, "timeConstantTau"));
      if (!parameters()->present(getName(), "momentumTau")) {
         return;
      }
      if (parameters()->present(getName(), "timeConstantTau")) {
         WarnLog().printf(
               "%s sets timeConstantTau, so momentumTau will be ignored.\n", getDescription_c());
         return;
      }
      mUsingDeprecatedMomentumTau = true;
      parameters()->ioParamValueRequired(ioFlag, name, "momentumTau", &mMomentumTau);
      WarnLog().printf(
            "%s uses momentumTau, which is deprecated. Use timeConstantTau instead.\n",
            getDescription_c());
   }
}

void MomentumUpdater::ioParam_momentumDecay(enum ParamsIOFlag ioFlag) {
   pvAssert(!parameters()->presentAndNotBeenRead(name, "plasticityFlag"));
   if (mPlasticityFlag) {
      parameters()->ioParamValue(ioFlag, name, "momentumDecay", &mMomentumDecay, mMomentumDecay);
      if (mMomentumDecay < 0.0f || mMomentumDecay > 1.0f) {
         Fatal() << "MomentumUpdater " << name
                 << ": momentumDecay must be between 0 and 1 inclusive\n";
      }
   }
}

Response::Status MomentumUpdater::allocateDataStructures() {
   auto status = HebbianUpdater::allocateDataStructures();
   if (!Response::completed(status)) {
      return status;
   }
   if (!mPlasticityFlag) {
      return status;
   }
   mPrevDeltaWeights = new Weights(name);
   mPrevDeltaWeights->initialize(mWeights);
   mPrevDeltaWeights->setMargins(
         mConnectionData->getPre()->getLayerLoc()->halo,
         mConnectionData->getPost()->getLayerLoc()->halo);
   mPrevDeltaWeights->allocateDataStructures();
   return Response::SUCCESS;
}

Response::Status
MomentumUpdater::registerData(std::shared_ptr<RegisterDataMessage<Checkpointer> const> message) {
   auto status = HebbianUpdater::registerData(message);
   if (!Response::completed(status)) {
      return status;
   }
   // Note: HebbianUpdater does not checkpoint dW if the mImmediateWeightUpdate flag is true.
   // Do we need to handle it here and in readStateFromCheckpoint? --pschultz, 2017-12-16
   if (mPlasticityFlag) {
      auto *checkpointer = message->mDataRegistry;
      mPrevDeltaWeights->checkpointWeightPvp(
            checkpointer, name, "prev_dW", mWriteCompressedCheckpoints);
   }
   return Response::SUCCESS;
}

Response::Status MomentumUpdater::readStateFromCheckpoint(Checkpointer *checkpointer) {
   pvAssert(mInitializeFromCheckpointFlag);
   // Note: HebbianUpdater does not checkpoint dW if the mImmediateWeightUpdate flag is true.
   // Do we need to handle it here and in registerData? --pschultz, 2017-12-16
   if (mPlasticityFlag) {
      checkpointer->readNamedCheckpointEntry(
            std::string(name), std::string("prev_dW"), false /*not constant*/);
   }
   return Response::SUCCESS;
}

int MomentumUpdater::updateWeights(int arborId) {
   // Add momentum right before updateWeights
   if (mUsingDeprecatedMomentumTau) { // MomentumTau was deprecated Nov 19, 2018.
      WarnLog().printf(
            "%s is using momentumTau, which has been deprecated in favor of timeConstantTau.\n",
            getDescription_c());
      applyMomentumDeprecated(arborId);
   }
   else {
      applyMomentum(arborId);
   }

   // Current dW saved to prev_dW
   pvAssert(mPrevDeltaWeights);
   std::memcpy(
         mPrevDeltaWeights->getData(arborId),
         mDeltaWeights->getDataReadOnly(arborId),
         sizeof(float) * mDeltaWeights->getPatchSizeOverall() * mDeltaWeights->getNumDataPatches());

   // add dw to w
   return HebbianUpdater::updateWeights(arborId);
}

void MomentumUpdater::applyMomentum(int arborId) {
   // Shared weights done in parallel, parallel in numkernels
   switch (mMethod) {
      case VISCOSITY:
         applyMomentum(arborId, std::exp(-1.0f / mTimeConstantTau), mMomentumDecay);
         break;
      case SIMPLE: applyMomentum(arborId, mTimeConstantTau, mMomentumDecay); break;
      case ALEX: applyMomentum(arborId, mTimeConstantTau, mMomentumDecay * mDWMax); break;
      default: pvAssertMessage(0, "Unrecognized momentumMethod\n"); break;
   }
}

void MomentumUpdater::applyMomentum(int arborId, float dwFactor, float wFactor) {
   int const numKernels = mDeltaWeights->getNumDataPatches();
   pvAssert(numKernels == mPrevDeltaWeights->getNumDataPatches());
   int const patchSizeOverall = mDeltaWeights->getPatchSizeOverall();
   pvAssert(patchSizeOverall == mPrevDeltaWeights->getPatchSizeOverall());
#ifdef PV_USE_OPENMP_THREADS
#pragma omp parallel for
#endif
   for (int kernelIdx = 0; kernelIdx < numKernels; kernelIdx++) {
      float *dwdata_start        = mDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *prev_dw_start = mPrevDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *wdata_start   = mWeights->getDataFromDataIndex(arborId, kernelIdx);
      for (int k = 0; k < patchSizeOverall; k++) {
         dwdata_start[k] *= 1 - dwFactor;
         dwdata_start[k] += dwFactor * prev_dw_start[k];
         dwdata_start[k] -= wFactor * wdata_start[k]; // TODO handle decay in a separate component
      }
   }
   // Since weights data is allocated with all patches of a given arbor in a single vector,
   // these two for-loops can probably be collapsed. --pschultz 2017-12-16
}

void MomentumUpdater::applyMomentumDeprecated(int arborId) {
   // Shared weights done in parallel, parallel in numkernels
   switch (mMethod) {
      case VISCOSITY:
         applyMomentumDeprecated(arborId, std::exp(-1.0f / mMomentumTau), mMomentumDecay);
         break;
      case SIMPLE: applyMomentumDeprecated(arborId, mMomentumTau, mMomentumDecay); break;
      case ALEX: applyMomentumDeprecated(arborId, mMomentumTau, mMomentumDecay * mDWMax); break;
      default: pvAssertMessage(0, "Unrecognized momentumMethod\n"); break;
   }
}

void MomentumUpdater::applyMomentumDeprecated(int arborId, float dwFactor, float wFactor) {
   int const numKernels = mDeltaWeights->getNumDataPatches();
   pvAssert(numKernels == mPrevDeltaWeights->getNumDataPatches());
   int const patchSizeOverall = mDeltaWeights->getPatchSizeOverall();
   pvAssert(patchSizeOverall == mPrevDeltaWeights->getPatchSizeOverall());
#ifdef PV_USE_OPENMP_THREADS
#pragma omp parallel for
#endif
   for (int kernelIdx = 0; kernelIdx < numKernels; kernelIdx++) {
      float *dwdata_start        = mDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *prev_dw_start = mPrevDeltaWeights->getDataFromDataIndex(arborId, kernelIdx);
      float const *wdata_start   = mWeights->getDataFromDataIndex(arborId, kernelIdx);
      for (int k = 0; k < patchSizeOverall; k++) {
         dwdata_start[k] += dwFactor * prev_dw_start[k] - wFactor * wdata_start[k];
      }
   }
   // Since weights data is allocated with all patches of a given arbor in a single vector,
   // these two for-loops can probably be collapsed. --pschultz 2017-12-16
}

} // namespace PV
<|endoftext|>


<commit_before>// latency accumulator -- a chain of ops with data dependency between each two ops;
// to break the dependency set COISSUE

#if __aarch64__ == 0 && __SSSE3__ == 0
	#error wrong target arch
#endif

#include <stddef.h>

int main(int, char**) {
	size_t const rep = size_t(5e8);

	for (size_t i = 0; i < rep; ++i) {

#if __aarch64__
#if COISSUE
		asm volatile (
			"tbl v17.16b, {v1.16b},  v0.16b\n\t"
			"tbl v18.16b, {v2.16b},  v0.16b\n\t"
			"tbl v19.16b, {v3.16b},  v0.16b\n\t"
			"tbl v20.16b, {v4.16b},  v0.16b\n\t"
			"tbl v21.16b, {v5.16b},  v0.16b\n\t"
			"tbl v22.16b, {v6.16b},  v0.16b\n\t"
			"tbl v23.16b, {v7.16b},  v0.16b\n\t"
			"tbl v24.16b, {v8.16b},  v0.16b\n\t"
			"tbl v25.16b, {v9.16b},  v0.16b\n\t"
			"tbl v26.16b, {v10.16b}, v0.16b\n\t"
			"tbl v27.16b, {v11.16b}, v0.16b\n\t"
			"tbl v28.16b, {v12.16b}, v0.16b\n\t"
			"tbl v29.16b, {v13.16b}, v0.16b\n\t"
			"tbl v30.16b, {v14.16b}, v0.16b\n\t"
			"tbl v31.16b, {v15.16b}, v0.16b\n\t"
			"tbl v0.16b,  {v16.16b}, v0.16b"
			: : : "memory");

#else
		asm volatile (
			"tbl v2.16b,  {v1.16b},  v0.16b\n\t"
			"tbl v3.16b,  {v2.16b},  v0.16b\n\t"
			"tbl v4.16b,  {v3.16b},  v0.16b\n\t"
			"tbl v5.16b,  {v4.16b},  v0.16b\n\t"
			"tbl v6.16b,  {v5.16b},  v0.16b\n\t"
			"tbl v7.16b,  {v6.16b},  v0.16b\n\t"
			"tbl v8.16b,  {v7.16b},  v0.16b\n\t"
			"tbl v9.16b,  {v8.16b},  v0.16b\n\t"
			"tbl v10.16b, {v9.16b},  v0.16b\n\t"
			"tbl v11.16b, {v10.16b}, v0.16b\n\t"
			"tbl v12.16b, {v11.16b}, v0.16b\n\t"
			"tbl v13.16b, {v12.16b}, v0.16b\n\t"
			"tbl v14.16b, {v13.16b}, v0.16b\n\t"
			"tbl v15.16b, {v14.16b}, v0.16b\n\t"
			"tbl v16.16b, {v15.16b}, v0.16b\n\t"
			"tbl v17.16b, {v16.16b}, v0.16b"
			: : : "memory");

#endif
#elif __SSSE3__
#if COISSUE
		asm volatile (
			"pshufb %%xmm0,  %%xmm1\n\t"
			"pshufb %%xmm0,  %%xmm2\n\t"
			"pshufb %%xmm0,  %%xmm3\n\t"
			"pshufb %%xmm0,  %%xmm4\n\t"
			"pshufb %%xmm0,  %%xmm5\n\t"
			"pshufb %%xmm0,  %%xmm6\n\t"
			"pshufb %%xmm0,  %%xmm7\n\t"
			"pshufb %%xmm0,  %%xmm8\n\t"
			"pshufb %%xmm0,  %%xmm9\n\t"
			"pshufb %%xmm0, %%xmm10\n\t"
			"pshufb %%xmm0, %%xmm11\n\t"
			"pshufb %%xmm0, %%xmm12\n\t"
			"pshufb %%xmm0, %%xmm13\n\t"
			"pshufb %%xmm0, %%xmm14\n\t"
			"pshufb %%xmm0, %%xmm15\n\t"
			"pshufb %%xmm0, %%xmm0"
			: : : "memory");

#else
		asm volatile (
			"pshufb %%xmm0,  %%xmm1\n\t"
			"pshufb %%xmm1,  %%xmm2\n\t"
			"pshufb %%xmm2,  %%xmm3\n\t"
			"pshufb %%xmm3,  %%xmm4\n\t"
			"pshufb %%xmm4,  %%xmm5\n\t"
			"pshufb %%xmm5,  %%xmm6\n\t"
			"pshufb %%xmm6,  %%xmm7\n\t"
			"pshufb %%xmm7,  %%xmm8\n\t"
			"pshufb %%xmm8,  %%xmm9\n\t"
			"pshufb %%xmm9,  %%xmm10\n\t"
			"pshufb %%xmm10, %%xmm11\n\t"
			"pshufb %%xmm11, %%xmm12\n\t"
			"pshufb %%xmm12, %%xmm13\n\t"
			"pshufb %%xmm13, %%xmm14\n\t"
			"pshufb %%xmm14, %%xmm15\n\t"
			"pshufb %%xmm15, %%xmm0"
			: : : "memory");

#endif
#endif
    }

    return 0;
}
<commit_msg>tweak lattest<commit_after>// latency accumulator -- a chain of ops with data dependency between each two ops;
// to break the dependency set COISSUE

#if __aarch64__ == 0 && __SSSE3__ == 0
	#error wrong target arch
#endif

#include <stddef.h>

int main(int, char**) {
	size_t const rep = size_t(5e8);

	for (size_t i = 0; i < rep; ++i) {

#if __aarch64__
#if COISSUE
		asm volatile (
			"tbl v17.16b, {v1.16b},  v0.16b\n\t"
			"tbl v18.16b, {v2.16b},  v0.16b\n\t"
			"tbl v19.16b, {v3.16b},  v0.16b\n\t"
			"tbl v20.16b, {v4.16b},  v0.16b\n\t"
			"tbl v21.16b, {v5.16b},  v0.16b\n\t"
			"tbl v22.16b, {v6.16b},  v0.16b\n\t"
			"tbl v23.16b, {v7.16b},  v0.16b\n\t"
			"tbl v24.16b, {v8.16b},  v0.16b\n\t"
			"tbl v25.16b, {v9.16b},  v0.16b\n\t"
			"tbl v26.16b, {v10.16b}, v0.16b\n\t"
			"tbl v27.16b, {v11.16b}, v0.16b\n\t"
			"tbl v28.16b, {v12.16b}, v0.16b\n\t"
			"tbl v29.16b, {v13.16b}, v0.16b\n\t"
			"tbl v30.16b, {v14.16b}, v0.16b\n\t"
			"tbl v31.16b, {v15.16b}, v0.16b\n\t"
			"tbl v16.16b, {v16.16b}, v0.16b"
			: : : "memory");

#else
		asm volatile (
			"tbl v2.16b,  {v1.16b},  v0.16b\n\t"
			"tbl v3.16b,  {v2.16b},  v0.16b\n\t"
			"tbl v4.16b,  {v3.16b},  v0.16b\n\t"
			"tbl v5.16b,  {v4.16b},  v0.16b\n\t"
			"tbl v6.16b,  {v5.16b},  v0.16b\n\t"
			"tbl v7.16b,  {v6.16b},  v0.16b\n\t"
			"tbl v8.16b,  {v7.16b},  v0.16b\n\t"
			"tbl v9.16b,  {v8.16b},  v0.16b\n\t"
			"tbl v10.16b, {v9.16b},  v0.16b\n\t"
			"tbl v11.16b, {v10.16b}, v0.16b\n\t"
			"tbl v12.16b, {v11.16b}, v0.16b\n\t"
			"tbl v13.16b, {v12.16b}, v0.16b\n\t"
			"tbl v14.16b, {v13.16b}, v0.16b\n\t"
			"tbl v15.16b, {v14.16b}, v0.16b\n\t"
			"tbl v16.16b, {v15.16b}, v0.16b\n\t"
			"tbl v17.16b, {v16.16b}, v0.16b"
			: : : "memory");

#endif
#elif __SSSE3__
#if COISSUE
		asm volatile (
			"pshufb %%xmm0,  %%xmm1\n\t"
			"pshufb %%xmm0,  %%xmm2\n\t"
			"pshufb %%xmm0,  %%xmm3\n\t"
			"pshufb %%xmm0,  %%xmm4\n\t"
			"pshufb %%xmm0,  %%xmm5\n\t"
			"pshufb %%xmm0,  %%xmm6\n\t"
			"pshufb %%xmm0,  %%xmm7\n\t"
			"pshufb %%xmm0,  %%xmm8\n\t"
			"pshufb %%xmm0,  %%xmm9\n\t"
			"pshufb %%xmm0, %%xmm10\n\t"
			"pshufb %%xmm0, %%xmm11\n\t"
			"pshufb %%xmm0, %%xmm12\n\t"
			"pshufb %%xmm0, %%xmm13\n\t"
			"pshufb %%xmm0, %%xmm14\n\t"
			"pshufb %%xmm0, %%xmm15\n\t"
			"pshufb %%xmm0, %%xmm0"
			: : : "memory");

#else
		asm volatile (
			"pshufb %%xmm0,  %%xmm1\n\t"
			"pshufb %%xmm1,  %%xmm2\n\t"
			"pshufb %%xmm2,  %%xmm3\n\t"
			"pshufb %%xmm3,  %%xmm4\n\t"
			"pshufb %%xmm4,  %%xmm5\n\t"
			"pshufb %%xmm5,  %%xmm6\n\t"
			"pshufb %%xmm6,  %%xmm7\n\t"
			"pshufb %%xmm7,  %%xmm8\n\t"
			"pshufb %%xmm8,  %%xmm9\n\t"
			"pshufb %%xmm9,  %%xmm10\n\t"
			"pshufb %%xmm10, %%xmm11\n\t"
			"pshufb %%xmm11, %%xmm12\n\t"
			"pshufb %%xmm12, %%xmm13\n\t"
			"pshufb %%xmm13, %%xmm14\n\t"
			"pshufb %%xmm14, %%xmm15\n\t"
			"pshufb %%xmm15, %%xmm0"
			: : : "memory");

#endif
#endif
    }

    return 0;
}
<|endoftext|>


<commit_before>//
// SDL2pp tutorial
//
// Written in 2015 by Dmitry Marakasiv <amdmi3@amdmi3.ru>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//
// Lesson 02:
//
// - Event processing
//

#include <iostream>
#include <exception>

#include <SDL2pp/SDL2pp.hh>

using namespace SDL2pp;

int main() try {
	// Initialize SDL library
	SDL sdl(SDL_INIT_VIDEO);

	// Create main window: 640x480 dimensions, resizable, "SDL2pp demo" title
	Window window("SDL2pp demo",
			SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
			640, 480,
			SDL_WINDOW_RESIZABLE);

	// Create accelerated video renderer with default driver
	Renderer renderer(window, -1, SDL_RENDERER_ACCELERATED);

	// Load sprites image as a new texture
	Texture sprites(renderer, DATA_PATH "/M484SpaceSoldier.png");

	// Main loop
	while (1) {
		// Event processing:
		// - If window is closed, or Q or Escape buttons are pressed,
		//   quit the application
		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) {
				return 0;
			} else if (event.type == SDL_KEYDOWN) {
				switch (event.key.keysym.sym) {
				case SDLK_ESCAPE: case SDLK_q:
					return 0;
				}
			}
		}

		int vcenter = renderer.GetOutputHeight() / 2; // Y coordinate of window center

		// Clear screen
		renderer.Clear();

		// Draw player sprite
		renderer.Copy(
				sprites,
				Rect(8, 11, 50, 50),
				Rect(0, vcenter - 50, 50, 50)
			);

		// Show rendered frame
		renderer.Present();

		// Frame limiter: sleep for a little bit to not eat 100% of CPU
		SDL_Delay(1);
	}

	// Here all resources are automatically released and library deinitialized
	return 0;
} catch (std::exception& e) {
	// If case of error, print it and exit with error
	std::cerr << e.what() << std::endl;
	return 1;
}
<commit_msg>Extend description<commit_after>//
// SDL2pp tutorial
//
// Written in 2015 by Dmitry Marakasiv <amdmi3@amdmi3.ru>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with
// this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//
// Lesson 02:
//
// - Main loop
// - Event processing
//

#include <iostream>
#include <exception>

#include <SDL2pp/SDL2pp.hh>

using namespace SDL2pp;

int main() try {
	// Initialize SDL library
	SDL sdl(SDL_INIT_VIDEO);

	// Create main window: 640x480 dimensions, resizable, "SDL2pp demo" title
	Window window("SDL2pp demo",
			SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
			640, 480,
			SDL_WINDOW_RESIZABLE);

	// Create accelerated video renderer with default driver
	Renderer renderer(window, -1, SDL_RENDERER_ACCELERATED);

	// Load sprites image as a new texture
	Texture sprites(renderer, DATA_PATH "/M484SpaceSoldier.png");

	// Main loop
	while (1) {
		// Event processing:
		// - If window is closed, or Q or Escape buttons are pressed,
		//   quit the application
		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) {
				return 0;
			} else if (event.type == SDL_KEYDOWN) {
				switch (event.key.keysym.sym) {
				case SDLK_ESCAPE: case SDLK_q:
					return 0;
				}
			}
		}

		int vcenter = renderer.GetOutputHeight() / 2; // Y coordinate of window center

		// Clear screen
		renderer.Clear();

		// Draw player sprite
		renderer.Copy(
				sprites,
				Rect(8, 11, 50, 50),
				Rect(0, vcenter - 50, 50, 50)
			);

		// Show rendered frame
		renderer.Present();

		// Frame limiter: sleep for a little bit to not eat 100% of CPU
		SDL_Delay(1);
	}

	// Here all resources are automatically released and library deinitialized
	return 0;
} catch (std::exception& e) {
	// If case of error, print it and exit with error
	std::cerr << e.what() << std::endl;
	return 1;
}
<|endoftext|>