<commit_before>// simulation.cpp
// implementation of functions for simulating magnetic dynamics
//
// Oliver W. Laslett (2016)
// O.Laslett@soton.ac.uk
#include "../include/simulation.hpp"
#include "../include/llg.hpp"
#include "../include/integrators.hpp"
#include "../include/io.hpp"
#include "../include/field.hpp"
#include "../include/trap.hpp"
#include "../include/easylogging++.h"
#include "../include/optimisation.hpp"
#include <exception>
#ifdef USEMKL
#include <mkl_cblas.h>
#else
#include <cblas.h>
#endif

using namespace std::placeholders;
using sde_function = std::function<void(double*,const double*,const double)>;

struct simulation::results simulation::full_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const d3 initial_magnetisation,
    const double time_step,
    const double end_time,
    Rng &rng,
    const bool renorm,
    const int max_samples )
{
    size_t dims = 3;

    /*
      To ease memory requirements - can specify the maximum number of
      samples to store in memory. This is used to compute the number
      of integration steps per write to the in-memory results arrays.

      max_samples=-1 is equivalent to max_samples=N_steps

      The sampling interval is taken to be regularly spaced and is interpolated
      from the integration steps using a zero-order-hold technique.
     */
    const size_t N_samples = max_samples==-1 ?
        int( end_time / time_step ) + 1
        : max_samples;
    const double sampling_time = end_time / ( N_samples-1 );

    // allocate memory for results
    simulation::results res( N_samples );

    // Allocate matrices needed for the midpoint method
    double *state = new double[dims*2]; // stores old and new state
                                        // i.e 2 *dims
    double *dwm = new double[dims];
    double *a_work = new double[dims];
    double *b_work = new double[dims*dims];
    double *adash_work = new double[dims*dims];
    double *bdash_work = new double[dims*dims*dims];
    double *x_guess = new double[dims];
    double *x_opt_tmp = new double[dims];
    double *x_opt_jac = new double[dims*dims];
    lapack_int *x_opt_ipiv = new lapack_int[2];

    // Limits for the implicit solver
    const double eps=1e-9;
    const size_t max_iter=1000;

    // Copy in the initial state
    res.time[0] = 0;
    res.field[0] = applied_field( 0 );
    res.mx[0] = initial_magnetisation[0];
    res.my[0] = initial_magnetisation[1];
    res.mz[0] = initial_magnetisation[2];

    // The wiener paths
    double wiener[3];

    // The effective field is updated at each time step
    double heff[3];

    // Vars for loops
    unsigned int step = 0;
    double t = 0;
    double hz = 0;
    double pstate[3], nstate[3];
    nstate[0] = initial_magnetisation[0];
    nstate[1] = initial_magnetisation[1];
    nstate[2] = initial_magnetisation[2];

    /*
      The time for each point in the regularly spaced grid is
      known. We want to obtain the state at each step
     */
    for( unsigned int sample=1; sample<N_samples; sample++ )
    {
        // Perform a simulation step until we breach the next sampling point
        while ( t <= sample*sampling_time )
        {
            // take a step
            pstate[0] = nstate[0];
            pstate[1] = nstate[1];
            pstate[2] = nstate[2];
            step++;

            // Compute current time
            // When max_samples=-1 uses sampling_time directly to avoid rounding
            // errors
            t = max_samples==-1 ? sample*sampling_time : step*time_step;

            // Compute the anisotropy field
            field::uniaxial_anisotropy( heff, pstate, anis_axis.data() );

            // Compute the applied field - always in the z-direction
            hz = applied_field( t );
            heff[2] += hz;

            // bind parameters to the LLG functions
            sde_function drift = std::bind(
                llg::drift, _1, _2, _3, damping, heff );
            sde_function diffusion = std::bind(
                llg::diffusion, _1, _2, _3, thermal_field_strength, damping );
            sde_function drift_jac = std::bind(
                llg::drift_jacobian, _1, _2, _3, damping, heff );
            sde_function diffusion_jac = std::bind(
                llg::diffusion_jacobian, _1, _2, _3, thermal_field_strength,
                damping );

            // Generate the wiener increments
            for( unsigned int i=0; i<3; i++ )
                wiener[i] = rng.get();

            // perform integration step
            int errcode = integrator::implicit_midpoint(
                nstate, dwm, a_work, b_work, adash_work, bdash_work, x_guess,
                x_opt_tmp, x_opt_jac, x_opt_ipiv, pstate, wiener, drift,
                diffusion, drift_jac, diffusion_jac, dims, dims, t, time_step,
                eps, max_iter );
            if( errcode != optimisation::SUCCESS )
                LOG(FATAL) << "integration error code: " << errcode;

            // Renormalise the length of the magnetisation
            if( renorm  )
            {
                double norm = cblas_dnrm2( 3, nstate, 1 );
                for( unsigned int i=0; i<dims; i++ )
                    nstate[i] = nstate[i]/norm;
            } // end renormalisation

        } // end integration stepping loop

        /*
          Once this point is reached, we are currently one step beyond
          the desired sampling point. Use a zero-order-hold:
          i.e. take the previous state before the sampling time as the
          state at the sampling time.
         */
        res.time[sample] = sample*sampling_time; // sampling time
        res.mx[sample] = pstate[0];
        res.my[sample] = pstate[1];
        res.mz[sample] = pstate[2];
        res.field[sample] = applied_field( sample*sampling_time );
    } // end sampling loop

    delete[] state;
    delete[] a_work;
    delete[] b_work;
    delete[] adash_work;
    delete[] bdash_work;
    delete[] x_guess;
    delete[] x_opt_tmp;
    delete[] x_opt_jac;
    delete[] x_opt_ipiv;

    return res; // Ensure elison else copy is made and dtor is called!
}

struct simulation::results simulation::ensemble_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const std::vector<d3> initial_mags,
    const double time_step,
    const double end_time,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size )
{
    // Initialise space for the ensemble results
    struct simulation::results ensemble( max_samples );
    simulation::zero_results( ensemble ); // initialise all values to zero

    // MONTE CARLO RUNS
    // Embarrassingly parallel - simulation per thread
    #pragma omp parallel for schedule(dynamic, 1) shared(ensemble)
    for( unsigned int run_id=0; run_id<ensemble_size; run_id++ )
    {
        // Simulate a single realisation of the system
        auto results = simulation::full_dynamics(
            damping, thermal_field_strength, anis_axis, applied_field,
            initial_mags[run_id], time_step, end_time, *(rngs[run_id].get()),
            renorm, max_samples );

        // Copy the results into the ensemble
        for( unsigned int j=0; j<results.N; j++ )
        {
            #pragma omp atomic
            ensemble.mx[j] += results.mx[j];
            #pragma omp atomic
            ensemble.my[j] += results.my[j];
            #pragma omp atomic
            ensemble.mz[j] += results.mz[j];
        } // end copying to ensemble

        // Copy in the field and time values
        if( run_id==0 )
            for( unsigned int j=0; j<results.N; j++ )
            {
                ensemble.time[j] = results.time[j];
                ensemble.field[j] = results.field[j];
            }
        #pragma omp critical
        LOG(INFO) << "Completed simulation " << run_id << "/"
                  << ensemble_size;
    } // end Monte-Carlo loop

    for( unsigned int i=0; i<ensemble.N; i++ )
    {
        ensemble.mx[i] /= ensemble_size;
        ensemble.my[i] /= ensemble_size;
        ensemble.mz[i] /= ensemble_size;
    }
    return ensemble;
}

struct simulation::results simulation::ensemble_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const d3 initial_mag,
    const double time_step,
    const double end_time,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size )
{
    std::vector<d3> init_mags;
    for( unsigned int i=0; i<ensemble_size; i++ )
        init_mags.push_back( initial_mag );
    return simulation::ensemble_dynamics(
        damping, thermal_field_strength, anis_axis, applied_field, init_mags,
        time_step, end_time, rngs, renorm, max_samples, ensemble_size );
}

std::vector<d3> simulation::ensemble_final_state(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const std::vector<d3> initial_mags,
    const double time_step,
    const double end_time,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size )
{
    // Initialise the total states
    std::vector<d3> states( initial_mags );

    // MONTE CARLO RUNS
    // Embarrassingly parallel - simulation per thread
    #pragma omp parallel for schedule(dynamic, 1) shared(states)
    for( unsigned int run_id=0; run_id<ensemble_size; run_id++ )
    {
        // Simulate a single realisation of the system
        auto results = simulation::full_dynamics(
            damping, thermal_field_strength, anis_axis, applied_field,
            initial_mags[run_id], time_step, end_time, *(rngs[run_id].get()),
            renorm, max_samples );
        // Copy in the final state
        #pragma omp critical
        {
            states[run_id][0] = results.mx[results.N-1];
            states[run_id][1] = results.my[results.N-1];
            states[run_id][2] = results.mz[results.N-1];
            LOG(INFO) << "Completed simulation " << run_id << "/" << ensemble_size;
        }
    } // end Monte-Carlo loop
    return states;
}

struct simulation::results simulation::steady_state_cycle_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const d3 initial_magnetisation,
    const double time_step,
    const double applied_field_period,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size,
    const double steady_state_condition )
{
    std::vector<d3> prev_mags;
    for( unsigned int i=0; i<ensemble_size; i++ )
        prev_mags.push_back( initial_magnetisation );

    unsigned int n_field_cycles=0;
    // Keep simulating until the steady state condition is met
    while ( true )
    {
        n_field_cycles++;
        auto mags = simulation::ensemble_final_state(
            damping, thermal_field_strength, anis_axis, applied_field,
            prev_mags, time_step, applied_field_period, rngs,
            renorm, max_samples, ensemble_size );

        // Compute the ensemble magnetisation before and after
        // Assume magnetisation is taken in the z-direction
        double mag_before=0, mag_after=0;
        for( unsigned int i=0; i<ensemble_size; i++ )
        {
            mag_before += prev_mags[i][2];
            mag_after += mags[i][2];
        }
        mag_before /= ensemble_size;
        mag_after /= ensemble_size;

        // Check the steady state condition
        if( std::abs( mag_before - mag_after ) < steady_state_condition )
        {
            auto full_res = simulation::ensemble_dynamics(
                damping, thermal_field_strength, anis_axis, applied_field,
                mags, time_step, applied_field_period, rngs, renorm,
                max_samples, ensemble_size );
            LOG(INFO) << "Steady state reached after " << n_field_cycles
                      << " field cycles";
            return full_res;
        }
        // If not reached - run another cycle from the current state
        prev_mags = mags;
        LOG(INFO) << "Error after cycle " << n_field_cycles
                  << ": " << std::abs( mag_before - mag_after );
    }
}

double simulation::power_loss(
    const struct results &res,
    double K, double Ms, double Hk, double f )
{
    double area = trap::trapezoidal( res.field.get(), res.mz.get(), res.N );
    return 2*K*Ms*Hk*area*f;
}

void simulation::save_results( const std::string fname, const struct results &res )
{
    std::stringstream magx_fname, magy_fname, magz_fname, field_fname, time_fname;
    magx_fname << fname << ".mx";
    magy_fname << fname << ".my";
    magz_fname << fname << ".mz";
    field_fname << fname << ".field";
    time_fname << fname << ".time";
    int err;
    err = io::write_array( magx_fname.str(), res.mx.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( magy_fname.str(), res.my.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( magz_fname.str(), res.mz.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( field_fname.str(), res.field.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( time_fname.str(), res.time.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
}

void simulation::zero_results( struct simulation::results &res )
{
    for( unsigned int i=0; i<res.N; i++ )
        res.mx[i] = res.my[i] = res.mz[i] = res.field[i] = res.time[i] = 0;
}
<commit_msg>update simulation to use new joint functions<commit_after>// simulation.cpp
// implementation of functions for simulating magnetic dynamics
//
// Oliver W. Laslett (2016)
// O.Laslett@soton.ac.uk
#include "../include/simulation.hpp"
#include "../include/llg.hpp"
#include "../include/integrators.hpp"
#include "../include/io.hpp"
#include "../include/field.hpp"
#include "../include/trap.hpp"
#include "../include/easylogging++.h"
#include "../include/optimisation.hpp"
#include <exception>
#ifdef USEMKL
#include <mkl_cblas.h>
#else
#include <cblas.h>
#endif

using namespace std::placeholders;
using sde_function = std::function<void(double*,const double*,const double)>;
using sde_jac = std::function<void(double*,double*,double*,double*,
                                   const double*,const double, const double)>;

struct simulation::results simulation::full_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const d3 initial_magnetisation,
    const double time_step,
    const double end_time,
    Rng &rng,
    const bool renorm,
    const int max_samples )
{
    size_t dims = 3;

    /*
      To ease memory requirements - can specify the maximum number of
      samples to store in memory. This is used to compute the number
      of integration steps per write to the in-memory results arrays.

      max_samples=-1 is equivalent to max_samples=N_steps

      The sampling interval is taken to be regularly spaced and is interpolated
      from the integration steps using a zero-order-hold technique.
     */
    const size_t N_samples = max_samples==-1 ?
        int( end_time / time_step ) + 1
        : max_samples;
    const double sampling_time = end_time / ( N_samples-1 );

    // allocate memory for results
    simulation::results res( N_samples );

    // Allocate matrices needed for the midpoint method
    double *state = new double[dims*2]; // stores old and new state
                                        // i.e 2 *dims
    double *dwm = new double[dims];
    double *a_work = new double[dims];
    double *b_work = new double[dims*dims];
    double *adash_work = new double[dims*dims];
    double *bdash_work = new double[dims*dims*dims];
    double *x_guess = new double[dims];
    double *x_opt_tmp = new double[dims];
    double *x_opt_jac = new double[dims*dims];
    lapack_int *x_opt_ipiv = new lapack_int[2];

    // Limits for the implicit solver
    const double eps=1e-9;
    const size_t max_iter=1000;

    // Copy in the initial state
    res.time[0] = 0;
    res.field[0] = applied_field( 0 );
    res.mx[0] = initial_magnetisation[0];
    res.my[0] = initial_magnetisation[1];
    res.mz[0] = initial_magnetisation[2];

    // The wiener paths
    double wiener[3];

    // The effective field and its Jacobian is updated at each time step
    double heff[3];
    double heffjac[9];
    double happ[3];

    // Vars for loops
    unsigned int step = 0;
    double t = 0;
    double hz = 0;
    double pstate[3], nstate[3];
    nstate[0] = initial_magnetisation[0];
    nstate[1] = initial_magnetisation[1];
    nstate[2] = initial_magnetisation[2];

    /*
      The time for each point in the regularly spaced grid is
      known. We want to obtain the state at each step
     */
    for( unsigned int sample=1; sample<N_samples; sample++ )
    {
        // Perform a simulation step until we breach the next sampling point
        while ( t <= sample*sampling_time )
        {
            // take a step
            pstate[0] = nstate[0];
            pstate[1] = nstate[1];
            pstate[2] = nstate[2];
            step++;

            // Compute current time
            // When max_samples=-1 uses sampling_time directly to avoid rounding
            // errors
            t = max_samples==-1 ? sample*sampling_time : step*time_step;

            // Compute the applied field - always in the z-direction
            happ[2] = applied_field( t );

            // Assumes that applied field is constant over the period
            // Bind the parameters to create the required SDE function
            sde_jac sde = std::bind(
                llg::jacobians_with_update, _1, _2, _3, _4, heff, heffjac,
                _5, _6, _7, happ, anis_axis.data(), damping,
                thermal_field_strength );

            // Generate the wiener increments
            for( unsigned int i=0; i<3; i++ )
                wiener[i] = rng.get();

            // perform integration step
            int errcode = integrator::implicit_midpoint(
                nstate, dwm, a_work, b_work, adash_work, bdash_work, x_guess,
                x_opt_tmp, x_opt_jac, x_opt_ipiv, pstate, wiener, sde,
                dims, dims, t, time_step, eps, max_iter );
            if( errcode != optimisation::SUCCESS )
                LOG(FATAL) << "integration error code: " << errcode;

            // Renormalise the length of the magnetisation
            if( renorm  )
            {
                double norm = cblas_dnrm2( 3, nstate, 1 );
                for( unsigned int i=0; i<dims; i++ )
                    nstate[i] = nstate[i]/norm;
            } // end renormalisation

        } // end integration stepping loop

        /*
          Once this point is reached, we are currently one step beyond
          the desired sampling point. Use a zero-order-hold:
          i.e. take the previous state before the sampling time as the
          state at the sampling time.
         */
        res.time[sample] = sample*sampling_time; // sampling time
        res.mx[sample] = pstate[0];
        res.my[sample] = pstate[1];
        res.mz[sample] = pstate[2];
        res.field[sample] = applied_field( sample*sampling_time );
    } // end sampling loop

    delete[] state;
    delete[] a_work;
    delete[] b_work;
    delete[] adash_work;
    delete[] bdash_work;
    delete[] x_guess;
    delete[] x_opt_tmp;
    delete[] x_opt_jac;
    delete[] x_opt_ipiv;

    return res; // Ensure elison else copy is made and dtor is called!
}

struct simulation::results simulation::ensemble_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const std::vector<d3> initial_mags,
    const double time_step,
    const double end_time,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size )
{
    // Initialise space for the ensemble results
    struct simulation::results ensemble( max_samples );
    simulation::zero_results( ensemble ); // initialise all values to zero

    // MONTE CARLO RUNS
    // Embarrassingly parallel - simulation per thread
    #pragma omp parallel for schedule(dynamic, 1) shared(ensemble)
    for( unsigned int run_id=0; run_id<ensemble_size; run_id++ )
    {
        // Simulate a single realisation of the system
        auto results = simulation::full_dynamics(
            damping, thermal_field_strength, anis_axis, applied_field,
            initial_mags[run_id], time_step, end_time, *(rngs[run_id].get()),
            renorm, max_samples );

        // Copy the results into the ensemble
        for( unsigned int j=0; j<results.N; j++ )
        {
            #pragma omp atomic
            ensemble.mx[j] += results.mx[j];
            #pragma omp atomic
            ensemble.my[j] += results.my[j];
            #pragma omp atomic
            ensemble.mz[j] += results.mz[j];
        } // end copying to ensemble

        // Copy in the field and time values
        if( run_id==0 )
            for( unsigned int j=0; j<results.N; j++ )
            {
                ensemble.time[j] = results.time[j];
                ensemble.field[j] = results.field[j];
            }
        #pragma omp critical
        LOG(INFO) << "Completed simulation " << run_id << "/"
                  << ensemble_size;
    } // end Monte-Carlo loop

    for( unsigned int i=0; i<ensemble.N; i++ )
    {
        ensemble.mx[i] /= ensemble_size;
        ensemble.my[i] /= ensemble_size;
        ensemble.mz[i] /= ensemble_size;
    }
    return ensemble;
}

struct simulation::results simulation::ensemble_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const d3 initial_mag,
    const double time_step,
    const double end_time,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size )
{
    std::vector<d3> init_mags;
    for( unsigned int i=0; i<ensemble_size; i++ )
        init_mags.push_back( initial_mag );
    return simulation::ensemble_dynamics(
        damping, thermal_field_strength, anis_axis, applied_field, init_mags,
        time_step, end_time, rngs, renorm, max_samples, ensemble_size );
}

std::vector<d3> simulation::ensemble_final_state(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const std::vector<d3> initial_mags,
    const double time_step,
    const double end_time,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size )
{
    // Initialise the total states
    std::vector<d3> states( initial_mags );

    // MONTE CARLO RUNS
    // Embarrassingly parallel - simulation per thread
    #pragma omp parallel for schedule(dynamic, 1) shared(states)
    for( unsigned int run_id=0; run_id<ensemble_size; run_id++ )
    {
        // Simulate a single realisation of the system
        auto results = simulation::full_dynamics(
            damping, thermal_field_strength, anis_axis, applied_field,
            initial_mags[run_id], time_step, end_time, *(rngs[run_id].get()),
            renorm, max_samples );
        // Copy in the final state
        #pragma omp critical
        {
            states[run_id][0] = results.mx[results.N-1];
            states[run_id][1] = results.my[results.N-1];
            states[run_id][2] = results.mz[results.N-1];
            LOG(INFO) << "Completed simulation " << run_id << "/" << ensemble_size;
        }
    } // end Monte-Carlo loop
    return states;
}

struct simulation::results simulation::steady_state_cycle_dynamics(
    const double damping,
    const double thermal_field_strength,
    const d3 anis_axis,
    const std::function<double(double)> applied_field,
    const d3 initial_magnetisation,
    const double time_step,
    const double applied_field_period,
    const rng_vec rngs,
    const bool renorm,
    const int max_samples,
    const size_t ensemble_size,
    const double steady_state_condition )
{
    std::vector<d3> prev_mags;
    for( unsigned int i=0; i<ensemble_size; i++ )
        prev_mags.push_back( initial_magnetisation );

    unsigned int n_field_cycles=0;
    // Keep simulating until the steady state condition is met
    while ( true )
    {
        n_field_cycles++;
        auto mags = simulation::ensemble_final_state(
            damping, thermal_field_strength, anis_axis, applied_field,
            prev_mags, time_step, applied_field_period, rngs,
            renorm, max_samples, ensemble_size );

        // Compute the ensemble magnetisation before and after
        // Assume magnetisation is taken in the z-direction
        double mag_before=0, mag_after=0;
        for( unsigned int i=0; i<ensemble_size; i++ )
        {
            mag_before += prev_mags[i][2];
            mag_after += mags[i][2];
        }
        mag_before /= ensemble_size;
        mag_after /= ensemble_size;

        // Check the steady state condition
        if( std::abs( mag_before - mag_after ) < steady_state_condition )
        {
            auto full_res = simulation::ensemble_dynamics(
                damping, thermal_field_strength, anis_axis, applied_field,
                mags, time_step, applied_field_period, rngs, renorm,
                max_samples, ensemble_size );
            LOG(INFO) << "Steady state reached after " << n_field_cycles
                      << " field cycles";
            return full_res;
        }
        // If not reached - run another cycle from the current state
        prev_mags = mags;
        LOG(INFO) << "Error after cycle " << n_field_cycles
                  << ": " << std::abs( mag_before - mag_after );
    }
}

double simulation::power_loss(
    const struct results &res,
    double K, double Ms, double Hk, double f )
{
    double area = trap::trapezoidal( res.field.get(), res.mz.get(), res.N );
    return 2*K*Ms*Hk*area*f;
}

void simulation::save_results( const std::string fname, const struct results &res )
{
    std::stringstream magx_fname, magy_fname, magz_fname, field_fname, time_fname;
    magx_fname << fname << ".mx";
    magy_fname << fname << ".my";
    magz_fname << fname << ".mz";
    field_fname << fname << ".field";
    time_fname << fname << ".time";
    int err;
    err = io::write_array( magx_fname.str(), res.mx.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( magy_fname.str(), res.my.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( magz_fname.str(), res.mz.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( field_fname.str(), res.field.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
    err = io::write_array( time_fname.str(), res.time.get(), res.N );
    if( err != 0 )
        throw std::runtime_error( "failed to write file" );
}

void simulation::zero_results( struct simulation::results &res )
{
    for( unsigned int i=0; i<res.N; i++ )
        res.mx[i] = res.my[i] = res.mz[i] = res.field[i] = res.time[i] = 0;
}
<|endoftext|>


<commit_before>/* The Halfling Project - A Graphics Engine and Projects
 *
 * The Halfling Project is the legal property of Adrian Astley
 * Copyright Adrian Astley 2013
 */

#include "obj_loader_demo/obj_loader_demo.h"

namespace ObjLoaderDemo {

LRESULT ObjLoaderDemo::MsgProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam) {
	// Send event message to AntTweakBar
	if (TwEventWin(hwnd, msg, wParam, lParam)) {
		return 0;    // Event has been handled by AntTweakBar
	}

	// Let the base engine handle any events that we don't handle
	return Halfling::HalflingEngine::MsgProc(hwnd, msg, wParam, lParam);
}

ObjLoaderDemo::ObjLoaderDemo(HINSTANCE hinstance)
	: Halfling::HalflingEngine(hinstance),
	  m_camera(0.5f * DirectX::XM_PI, 0.45f * DirectX::XM_PI, 100.0f),
	  m_showConsole(false),
	  m_sceneLoaded(false),
	  m_sceneIsSetup(false),
	  m_sceneScaleFactor(0.0f),
	  m_pointLightBufferNeedsRebuild(false),
	  m_spotLightBufferNeedsRebuild(false),
	  m_vsync(false),
	  m_wireframe(false),
	  m_animateLights(true),
	  m_shadingType(ShadingType::NoCullDeferred),
	  m_showLightLocations(false),
	  m_showGBuffers(false),
	  m_numPointLightsToDraw(100),
	  m_numSpotLightsToDraw(100),
	  m_renderTargetView(nullptr),
	  m_depthStencilBuffer(nullptr),
	  m_gBufferInputLayout(nullptr),
	  m_debugObjectInputLayout(nullptr),
	  m_forwardPixelShaderFrameConstantsBuffer(nullptr),
	  m_forwardPixelShaderObjectConstantsBuffer(nullptr),
	  m_gBufferVertexShaderObjectConstantsBuffer(nullptr),
	  m_gBufferPixelShaderObjectConstantsBuffer(nullptr),
	  m_noCullFinalGatherPixelShaderConstantsBuffer(nullptr),
	  m_transformedFullscreenTriangleVertexShaderConstantsBuffer(nullptr),
	  m_renderGbuffersPixelShaderConstantsBuffer(nullptr),
	  m_pointLightBuffer(nullptr),
	  m_spotLightBuffer(nullptr),
	  m_gbufferVertexShader(nullptr),
	  m_gbufferPixelShader(nullptr),
	  m_fullscreenTriangleVertexShader(nullptr),
	  m_noCullFinalGatherPixelShader(nullptr),
	  m_debugObjectVertexShader(nullptr),
	  m_debugObjectPixelShader(nullptr),
	  m_transformedFullscreenTriangleVertexShader(nullptr),
	  m_renderGbuffersPixelShader(nullptr) {
}

void ObjLoaderDemo::Shutdown() {
	// Release in the opposite order we initialized in
	ReleaseCOM(m_forwardPixelShaderFrameConstantsBuffer);
	ReleaseCOM(m_forwardPixelShaderObjectConstantsBuffer);
	ReleaseCOM(m_gBufferVertexShaderObjectConstantsBuffer);
	ReleaseCOM(m_gBufferPixelShaderObjectConstantsBuffer);
	ReleaseCOM(m_noCullFinalGatherPixelShaderConstantsBuffer);
	ReleaseCOM(m_transformedFullscreenTriangleVertexShaderConstantsBuffer);
	ReleaseCOM(m_renderGbuffersPixelShaderConstantsBuffer);
	delete m_pointLightBuffer;
	delete m_spotLightBuffer;
	delete m_frameMaterialListBuffer;
	ReleaseCOM(m_gbufferVertexShader);
	ReleaseCOM(m_gbufferPixelShader);
	ReleaseCOM(m_fullscreenTriangleVertexShader);
	ReleaseCOM(m_noCullFinalGatherPixelShader);
	ReleaseCOM(m_debugObjectVertexShader);
	ReleaseCOM(m_debugObjectPixelShader);
	ReleaseCOM(m_transformedFullscreenTriangleVertexShader);
	ReleaseCOM(m_renderGbuffersPixelShader);
	ReleaseCOM(m_gBufferInputLayout);
	ReleaseCOM(m_debugObjectInputLayout);

	for (auto iter = m_models.begin(); iter != m_models.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_pointLights.begin(); iter != m_pointLights.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_pointLightAnimators.begin(); iter != m_pointLightAnimators.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_spotLights.begin(); iter != m_spotLights.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_spotLightAnimators.begin(); iter != m_spotLightAnimators.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_gBuffers.begin(); iter != m_gBuffers.end(); ++iter) {
		delete *iter;
	}

	delete m_depthStencilBuffer;
	ReleaseCOM(m_renderTargetView);

	if (m_sceneLoaderThread.joinable()) {
		m_sceneLoaderThread.detach();
	}

	TwTerminate();

	Halfling::HalflingEngine::Shutdown();
}

void ObjLoaderDemo::OnResize() {
	if (!m_d3dInitialized) {
		return;
	}

	// Update the aspect ratio and the projection matrix
	m_worldViewProj.projection = DirectX::XMMatrixPerspectiveFovLH(0.25f * DirectX::XM_PI, float(m_clientWidth) / m_clientHeight, 10000.0f, 1.0f);

	// Release the gBuffers
	for (auto gbuffer : m_gBuffers) {
		delete gbuffer;
	}
	m_gBuffers.clear();
	m_gBufferRTVs.clear();
	m_gBufferSRVs.clear();

	// Release the old views and the old depth/stencil buffer.
	ReleaseCOM(m_renderTargetView);
	delete m_depthStencilBuffer;
	m_depthStencilBuffer = nullptr;

	// Resize the swap chain and recreate the render target view.
	HR(m_swapChain->ResizeBuffers(2, m_clientWidth, m_clientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));

	// Recreate the render target view.
	ID3D11Texture2D *backBuffer;
	HR(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBuffer)));
	HR(m_device->CreateRenderTargetView(backBuffer, 0, &m_renderTargetView));
	ReleaseCOM(backBuffer);

	// Create the depth/stencil buffer and view.
	DXGI_SAMPLE_DESC sampleDesc;

	// Use MSAA?
	if (m_msaaCount > 1) {
		uint msaaQuality;
		HR(m_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, m_msaaCount, &msaaQuality));
		assert(msaaQuality > 0);

		sampleDesc.Count = m_msaaCount;
		sampleDesc.Quality = msaaQuality - 1;
	} else {
		sampleDesc.Count = 1;
		sampleDesc.Quality = 0;
	}

	m_depthStencilBuffer = new Common::Depth2D(m_device, m_clientWidth, m_clientHeight,
											   D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE,
											   sampleDesc, m_stencil);

	// Create the gBuffers
	// Albedo
	m_gBuffers.push_back(new Common::Texture2D(m_device, m_clientWidth, m_clientHeight,
		DXGI_FORMAT_R11G11B10_FLOAT,
		D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
		sampleDesc));

	// Normal
	m_gBuffers.push_back(new Common::Texture2D(m_device, m_clientWidth, m_clientHeight,
		DXGI_FORMAT_R16G16_FLOAT,
		D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
		sampleDesc));

	// MaterialId
	m_gBuffers.push_back(new Common::Texture2D(m_device, m_clientWidth, m_clientHeight,
		DXGI_FORMAT_R16_UINT,
		D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
		sampleDesc));

	// Set up GBuffer resource list
	size_t size = m_gBuffers.size();
	m_gBufferRTVs.resize(size, 0);
	m_gBufferSRVs.resize(size + 1, 0);
	for (std::size_t i = 0; i < size; ++i) {
		m_gBufferRTVs[i] = m_gBuffers[i]->GetRenderTarget();
		m_gBufferSRVs[i] = m_gBuffers[i]->GetShaderResource();
	}

	// Add the depth buffer as a SRV for the Compute Shader
	m_gBufferSRVs.back() = m_depthStencilBuffer->GetShaderResource();

	// Set the viewport transform.
	m_screenViewport.TopLeftX = 0;
	m_screenViewport.TopLeftY = 0;
	m_screenViewport.Width = static_cast<float>(m_clientWidth);
	m_screenViewport.Height = static_cast<float>(m_clientHeight);
	m_screenViewport.MinDepth = 0.0f;
	m_screenViewport.MaxDepth = 1.0f;

	m_immediateContext->RSSetViewports(1, &m_screenViewport);
}

void ObjLoaderDemo::MouseDown(WPARAM buttonState, int x, int y) {
	m_mouseLastPos.x = x;
	m_mouseLastPos.y = y;

	SetCapture(m_hwnd);
}

void ObjLoaderDemo::MouseUp(WPARAM buttonState, int x, int y) {
	ReleaseCapture();
}

void ObjLoaderDemo::MouseMove(WPARAM buttonState, int x, int y) {
	if ((buttonState & MK_LBUTTON) != 0) {
		// Calculate the new phi and theta based on mouse position relative to where the user clicked
		// Four mouse pixel movements is 1 degree
		float dPhi = ((float)(m_mouseLastPos.y - y) / 300);
		float dTheta = ((float)(x - m_mouseLastPos.x) / 300);

		m_camera.MoveCamera(dTheta, dPhi, 0.0f);
	}

	m_mouseLastPos.x = x;
	m_mouseLastPos.y = y;
}

void ObjLoaderDemo::MouseWheel(int zDelta) {
	// Make each wheel dedent correspond to a size based on the scene
	m_camera.MoveCamera(0.0f, 0.0f, -0.1f * (float)zDelta);
}

void ObjLoaderDemo::CharacterInput(wchar character) {
	if (m_showConsole) {
		m_console.InputCharacter(character);
	}
}

} // End of namespace ObjLoaderDemo
<commit_msg>OBJ_LOADER_DEMO: Reduce the far clip plane<commit_after>/* The Halfling Project - A Graphics Engine and Projects
 *
 * The Halfling Project is the legal property of Adrian Astley
 * Copyright Adrian Astley 2013
 */

#include "obj_loader_demo/obj_loader_demo.h"

namespace ObjLoaderDemo {

LRESULT ObjLoaderDemo::MsgProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam) {
	// Send event message to AntTweakBar
	if (TwEventWin(hwnd, msg, wParam, lParam)) {
		return 0;    // Event has been handled by AntTweakBar
	}

	// Let the base engine handle any events that we don't handle
	return Halfling::HalflingEngine::MsgProc(hwnd, msg, wParam, lParam);
}

ObjLoaderDemo::ObjLoaderDemo(HINSTANCE hinstance)
	: Halfling::HalflingEngine(hinstance),
	  m_camera(0.5f * DirectX::XM_PI, 0.45f * DirectX::XM_PI, 100.0f),
	  m_showConsole(false),
	  m_sceneLoaded(false),
	  m_sceneIsSetup(false),
	  m_sceneScaleFactor(0.0f),
	  m_pointLightBufferNeedsRebuild(false),
	  m_spotLightBufferNeedsRebuild(false),
	  m_vsync(false),
	  m_wireframe(false),
	  m_animateLights(true),
	  m_shadingType(ShadingType::NoCullDeferred),
	  m_showLightLocations(false),
	  m_showGBuffers(false),
	  m_numPointLightsToDraw(100),
	  m_numSpotLightsToDraw(100),
	  m_renderTargetView(nullptr),
	  m_depthStencilBuffer(nullptr),
	  m_gBufferInputLayout(nullptr),
	  m_debugObjectInputLayout(nullptr),
	  m_forwardPixelShaderFrameConstantsBuffer(nullptr),
	  m_forwardPixelShaderObjectConstantsBuffer(nullptr),
	  m_gBufferVertexShaderObjectConstantsBuffer(nullptr),
	  m_gBufferPixelShaderObjectConstantsBuffer(nullptr),
	  m_noCullFinalGatherPixelShaderConstantsBuffer(nullptr),
	  m_transformedFullscreenTriangleVertexShaderConstantsBuffer(nullptr),
	  m_renderGbuffersPixelShaderConstantsBuffer(nullptr),
	  m_pointLightBuffer(nullptr),
	  m_spotLightBuffer(nullptr),
	  m_gbufferVertexShader(nullptr),
	  m_gbufferPixelShader(nullptr),
	  m_fullscreenTriangleVertexShader(nullptr),
	  m_noCullFinalGatherPixelShader(nullptr),
	  m_debugObjectVertexShader(nullptr),
	  m_debugObjectPixelShader(nullptr),
	  m_transformedFullscreenTriangleVertexShader(nullptr),
	  m_renderGbuffersPixelShader(nullptr) {
}

void ObjLoaderDemo::Shutdown() {
	// Release in the opposite order we initialized in
	ReleaseCOM(m_forwardPixelShaderFrameConstantsBuffer);
	ReleaseCOM(m_forwardPixelShaderObjectConstantsBuffer);
	ReleaseCOM(m_gBufferVertexShaderObjectConstantsBuffer);
	ReleaseCOM(m_gBufferPixelShaderObjectConstantsBuffer);
	ReleaseCOM(m_noCullFinalGatherPixelShaderConstantsBuffer);
	ReleaseCOM(m_transformedFullscreenTriangleVertexShaderConstantsBuffer);
	ReleaseCOM(m_renderGbuffersPixelShaderConstantsBuffer);
	delete m_pointLightBuffer;
	delete m_spotLightBuffer;
	delete m_frameMaterialListBuffer;
	ReleaseCOM(m_gbufferVertexShader);
	ReleaseCOM(m_gbufferPixelShader);
	ReleaseCOM(m_fullscreenTriangleVertexShader);
	ReleaseCOM(m_noCullFinalGatherPixelShader);
	ReleaseCOM(m_debugObjectVertexShader);
	ReleaseCOM(m_debugObjectPixelShader);
	ReleaseCOM(m_transformedFullscreenTriangleVertexShader);
	ReleaseCOM(m_renderGbuffersPixelShader);
	ReleaseCOM(m_gBufferInputLayout);
	ReleaseCOM(m_debugObjectInputLayout);

	for (auto iter = m_models.begin(); iter != m_models.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_pointLights.begin(); iter != m_pointLights.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_pointLightAnimators.begin(); iter != m_pointLightAnimators.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_spotLights.begin(); iter != m_spotLights.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_spotLightAnimators.begin(); iter != m_spotLightAnimators.end(); ++iter) {
		delete *iter;
	}
	for (auto iter = m_gBuffers.begin(); iter != m_gBuffers.end(); ++iter) {
		delete *iter;
	}

	delete m_depthStencilBuffer;
	ReleaseCOM(m_renderTargetView);

	if (m_sceneLoaderThread.joinable()) {
		m_sceneLoaderThread.detach();
	}

	TwTerminate();

	Halfling::HalflingEngine::Shutdown();
}

void ObjLoaderDemo::OnResize() {
	if (!m_d3dInitialized) {
		return;
	}

	// Update the aspect ratio and the projection matrix
	m_worldViewProj.projection = DirectX::XMMatrixPerspectiveFovLH(0.25f * DirectX::XM_PI, float(m_clientWidth) / m_clientHeight, 800.0f, 1.0f);

	// Release the gBuffers
	for (auto gbuffer : m_gBuffers) {
		delete gbuffer;
	}
	m_gBuffers.clear();
	m_gBufferRTVs.clear();
	m_gBufferSRVs.clear();

	// Release the old views and the old depth/stencil buffer.
	ReleaseCOM(m_renderTargetView);
	delete m_depthStencilBuffer;
	m_depthStencilBuffer = nullptr;

	// Resize the swap chain and recreate the render target view.
	HR(m_swapChain->ResizeBuffers(2, m_clientWidth, m_clientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));

	// Recreate the render target view.
	ID3D11Texture2D *backBuffer;
	HR(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBuffer)));
	HR(m_device->CreateRenderTargetView(backBuffer, 0, &m_renderTargetView));
	ReleaseCOM(backBuffer);

	// Create the depth/stencil buffer and view.
	DXGI_SAMPLE_DESC sampleDesc;

	// Use MSAA?
	if (m_msaaCount > 1) {
		uint msaaQuality;
		HR(m_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, m_msaaCount, &msaaQuality));
		assert(msaaQuality > 0);

		sampleDesc.Count = m_msaaCount;
		sampleDesc.Quality = msaaQuality - 1;
	} else {
		sampleDesc.Count = 1;
		sampleDesc.Quality = 0;
	}

	m_depthStencilBuffer = new Common::Depth2D(m_device, m_clientWidth, m_clientHeight,
											   D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE,
											   sampleDesc, m_stencil);

	// Create the gBuffers
	// Albedo
	m_gBuffers.push_back(new Common::Texture2D(m_device, m_clientWidth, m_clientHeight,
		DXGI_FORMAT_R11G11B10_FLOAT,
		D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
		sampleDesc));

	// Normal
	m_gBuffers.push_back(new Common::Texture2D(m_device, m_clientWidth, m_clientHeight,
		DXGI_FORMAT_R16G16_FLOAT,
		D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
		sampleDesc));

	// MaterialId
	m_gBuffers.push_back(new Common::Texture2D(m_device, m_clientWidth, m_clientHeight,
		DXGI_FORMAT_R16_UINT,
		D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
		sampleDesc));

	// Set up GBuffer resource list
	size_t size = m_gBuffers.size();
	m_gBufferRTVs.resize(size, 0);
	m_gBufferSRVs.resize(size + 1, 0);
	for (std::size_t i = 0; i < size; ++i) {
		m_gBufferRTVs[i] = m_gBuffers[i]->GetRenderTarget();
		m_gBufferSRVs[i] = m_gBuffers[i]->GetShaderResource();
	}

	// Add the depth buffer as a SRV for the Compute Shader
	m_gBufferSRVs.back() = m_depthStencilBuffer->GetShaderResource();

	// Set the viewport transform.
	m_screenViewport.TopLeftX = 0;
	m_screenViewport.TopLeftY = 0;
	m_screenViewport.Width = static_cast<float>(m_clientWidth);
	m_screenViewport.Height = static_cast<float>(m_clientHeight);
	m_screenViewport.MinDepth = 0.0f;
	m_screenViewport.MaxDepth = 1.0f;

	m_immediateContext->RSSetViewports(1, &m_screenViewport);
}

void ObjLoaderDemo::MouseDown(WPARAM buttonState, int x, int y) {
	m_mouseLastPos.x = x;
	m_mouseLastPos.y = y;

	SetCapture(m_hwnd);
}

void ObjLoaderDemo::MouseUp(WPARAM buttonState, int x, int y) {
	ReleaseCapture();
}

void ObjLoaderDemo::MouseMove(WPARAM buttonState, int x, int y) {
	if ((buttonState & MK_LBUTTON) != 0) {
		// Calculate the new phi and theta based on mouse position relative to where the user clicked
		// Four mouse pixel movements is 1 degree
		float dPhi = ((float)(m_mouseLastPos.y - y) / 300);
		float dTheta = ((float)(x - m_mouseLastPos.x) / 300);

		m_camera.MoveCamera(dTheta, dPhi, 0.0f);
	}

	m_mouseLastPos.x = x;
	m_mouseLastPos.y = y;
}

void ObjLoaderDemo::MouseWheel(int zDelta) {
	// Make each wheel dedent correspond to a size based on the scene
	m_camera.MoveCamera(0.0f, 0.0f, -0.1f * (float)zDelta);
}

void ObjLoaderDemo::CharacterInput(wchar character) {
	if (m_showConsole) {
		m_console.InputCharacter(character);
	}
}

} // End of namespace ObjLoaderDemo
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/storage.hpp"
#include <deque>
#include "libtorrent/disk_io_thread.hpp"

namespace libtorrent
{

	disk_io_thread::disk_io_thread(int block_size)
		: m_abort(false)
		, m_queue_buffer_size(0)
		, m_pool(block_size)
		, m_disk_io_thread(boost::ref(*this))
	{}

	disk_io_thread::~disk_io_thread()
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_abort = true;
		m_signal.notify_all();
		l.unlock();

		m_disk_io_thread.join();
	}

	// aborts read operations
	void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
	{
		boost::mutex::scoped_lock l(m_mutex);
		// read jobs are aborted, write and move jobs are syncronized
		for (std::deque<disk_io_job>::iterator i = m_jobs.begin();
			i != m_jobs.end();)
		{
			if (i->storage != s)
			{
				++i;
				continue;
			}
			if (i->action == disk_io_job::read)
			{
				i->callback(-1, *i);
				m_jobs.erase(i++);
				continue;
			}
			++i;
		}
		m_signal.notify_all();
	}

	bool range_overlap(int start1, int length1, int start2, int length2)
	{
		return (start1 <= start2 && start1 + length1 > start2)
			|| (start2 <= start1 && start2 + length2 > start1);
	}

	namespace
	{
		bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
		{
			if (lhs.storage.get() < rhs.storage.get()) return true;
			if (lhs.storage.get() > rhs.storage.get()) return false;
			if (lhs.piece < rhs.piece) return true;
			if (lhs.piece > rhs.piece) return false;
			if (lhs.offset < rhs.offset) return true;
//			if (lhs.offset > rhs.offset) return false;
			return false;
		}
	}

	void disk_io_thread::add_job(disk_io_job const& j
		, boost::function<void(int, disk_io_job const&)> const& f)
	{
		assert(!j.callback);
		boost::mutex::scoped_lock l(m_mutex);

		std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
		if (j.action == disk_io_job::read)
		{
			// when we're reading, we may not skip
			// ahead of any write operation that overlaps
			// the region we're reading
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::read && *i < j)
					break;
				if (i->action == disk_io_job::write
					&& i->storage == j.storage
					&& i->piece == j.piece
					&& range_overlap(i->offset, i->buffer_size
						, j.offset, j.buffer_size))
				{
					// we have to stop, and we haven't
					// found a suitable place for this job
					// so just queue it up at the end
					i = m_jobs.rbegin();
					break;
				}
			}
		}
		else if (j.action == disk_io_job::write)
		{
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::write && *i < j)
				{
					if (i != m_jobs.rbegin()
						&& i.base()->storage.get() != j.storage.get())
						i = m_jobs.rbegin();
					break;
				}
			}
		}

		if (i == m_jobs.rend()) i = m_jobs.rbegin();

		std::deque<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
		k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
		if (j.action == disk_io_job::write)
			m_queue_buffer_size += j.buffer_size;
		assert(j.storage.get());
		m_signal.notify_all();
	}

	char* disk_io_thread::allocate_buffer()
	{
		boost::mutex::scoped_lock l(m_mutex);
		return (char*)m_pool.ordered_malloc();
	}

	void disk_io_thread::operator()()
	{
		for (;;)
		{
			boost::mutex::scoped_lock l(m_mutex);
			while (m_jobs.empty() && !m_abort)
				m_signal.wait(l);
			if (m_abort && m_jobs.empty()) return;

			boost::function<void(int, disk_io_job const&)> handler;
			handler.swap(m_jobs.front().callback);
			disk_io_job j = m_jobs.front();
			m_jobs.pop_front();
			m_queue_buffer_size -= j.buffer_size;
			l.unlock();

			int ret = 0;

			try
			{
//				std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
				switch (j.action)
				{
					case disk_io_job::read:
						l.lock();
						j.buffer = (char*)m_pool.ordered_malloc();
						l.unlock();
						if (j.buffer == 0)
						{
							ret = -1;
							j.str = "out of memory";
						}
						else
						{
							ret = j.storage->read_impl(j.buffer, j.piece, j.offset
								, j.buffer_size);

							// simulates slow drives
							// usleep(300);
						}
						break;
					case disk_io_job::write:
						assert(j.buffer);
						j.storage->write_impl(j.buffer, j.piece, j.offset
							, j.buffer_size);

						// simulates a slow drive
						// usleep(300);
						break;
					case disk_io_job::hash:
						{
							sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
							j.str.resize(20);
							std::memcpy(&j.str[0], &h[0], 20);
						}
						break;
					case disk_io_job::move_storage:
						ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
						break;
					case disk_io_job::release_files:
						j.storage->release_files_impl();
						break;
				}
			}
			catch (std::exception& e)
			{
//				std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
				j.str = e.what();
				ret = -1;
			}

//			if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
//			else std::cerr << "DISK THREAD: invoking callback" << std::endl;
			try { if (handler) handler(ret, j); }
			catch (std::exception&) {}

			if (j.buffer)
			{
				l.lock();
				m_pool.ordered_free(j.buffer);
			}
		}
	}
}

<commit_msg>fixed intended behavior for async_move_storage<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/storage.hpp"
#include <deque>
#include "libtorrent/disk_io_thread.hpp"

namespace libtorrent
{

	disk_io_thread::disk_io_thread(int block_size)
		: m_abort(false)
		, m_queue_buffer_size(0)
		, m_pool(block_size)
		, m_disk_io_thread(boost::ref(*this))
	{}

	disk_io_thread::~disk_io_thread()
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_abort = true;
		m_signal.notify_all();
		l.unlock();

		m_disk_io_thread.join();
	}

	// aborts read operations
	void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
	{
		boost::mutex::scoped_lock l(m_mutex);
		// read jobs are aborted, write and move jobs are syncronized
		for (std::deque<disk_io_job>::iterator i = m_jobs.begin();
			i != m_jobs.end();)
		{
			if (i->storage != s)
			{
				++i;
				continue;
			}
			if (i->action == disk_io_job::read)
			{
				i->callback(-1, *i);
				m_jobs.erase(i++);
				continue;
			}
			++i;
		}
		m_signal.notify_all();
	}

	bool range_overlap(int start1, int length1, int start2, int length2)
	{
		return (start1 <= start2 && start1 + length1 > start2)
			|| (start2 <= start1 && start2 + length2 > start1);
	}

	namespace
	{
		bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
		{
			if (lhs.storage.get() < rhs.storage.get()) return true;
			if (lhs.storage.get() > rhs.storage.get()) return false;
			if (lhs.piece < rhs.piece) return true;
			if (lhs.piece > rhs.piece) return false;
			if (lhs.offset < rhs.offset) return true;
//			if (lhs.offset > rhs.offset) return false;
			return false;
		}
	}

	void disk_io_thread::add_job(disk_io_job const& j
		, boost::function<void(int, disk_io_job const&)> const& f)
	{
		assert(!j.callback);
		boost::mutex::scoped_lock l(m_mutex);

		std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
		if (j.action == disk_io_job::read)
		{
			// when we're reading, we may not skip
			// ahead of any write operation that overlaps
			// the region we're reading
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::read && *i < j)
					break;
				if (i->action == disk_io_job::write
					&& i->storage == j.storage
					&& i->piece == j.piece
					&& range_overlap(i->offset, i->buffer_size
						, j.offset, j.buffer_size))
				{
					// we have to stop, and we haven't
					// found a suitable place for this job
					// so just queue it up at the end
					i = m_jobs.rbegin();
					break;
				}
			}
		}
		else if (j.action == disk_io_job::write)
		{
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::write && *i < j)
				{
					if (i != m_jobs.rbegin()
						&& i.base()->storage.get() != j.storage.get())
						i = m_jobs.rbegin();
					break;
				}
			}
		}

		if (i == m_jobs.rend()) i = m_jobs.rbegin();

		std::deque<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
		k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
		if (j.action == disk_io_job::write)
			m_queue_buffer_size += j.buffer_size;
		assert(j.storage.get());
		m_signal.notify_all();
	}

	char* disk_io_thread::allocate_buffer()
	{
		boost::mutex::scoped_lock l(m_mutex);
		return (char*)m_pool.ordered_malloc();
	}

	void disk_io_thread::operator()()
	{
		for (;;)
		{
			boost::mutex::scoped_lock l(m_mutex);
			while (m_jobs.empty() && !m_abort)
				m_signal.wait(l);
			if (m_abort && m_jobs.empty()) return;

			boost::function<void(int, disk_io_job const&)> handler;
			handler.swap(m_jobs.front().callback);
			disk_io_job j = m_jobs.front();
			m_jobs.pop_front();
			m_queue_buffer_size -= j.buffer_size;
			l.unlock();

			int ret = 0;

			try
			{
//				std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
				switch (j.action)
				{
					case disk_io_job::read:
						l.lock();
						j.buffer = (char*)m_pool.ordered_malloc();
						l.unlock();
						if (j.buffer == 0)
						{
							ret = -1;
							j.str = "out of memory";
						}
						else
						{
							ret = j.storage->read_impl(j.buffer, j.piece, j.offset
								, j.buffer_size);

							// simulates slow drives
							// usleep(300);
						}
						break;
					case disk_io_job::write:
						assert(j.buffer);
						j.storage->write_impl(j.buffer, j.piece, j.offset
							, j.buffer_size);

						// simulates a slow drive
						// usleep(300);
						break;
					case disk_io_job::hash:
						{
							sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
							j.str.resize(20);
							std::memcpy(&j.str[0], &h[0], 20);
						}
						break;
					case disk_io_job::move_storage:
						ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
						if (ret) j.str = j.storage->save_path().string();
						break;
					case disk_io_job::release_files:
						j.storage->release_files_impl();
						break;
				}
			}
			catch (std::exception& e)
			{
//				std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
				j.str = e.what();
				ret = -1;
			}

//			if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
//			else std::cerr << "DISK THREAD: invoking callback" << std::endl;
			try { if (handler) handler(ret, j); }
			catch (std::exception&) {}

			if (j.buffer)
			{
				l.lock();
				m_pool.ordered_free(j.buffer);
			}
		}
	}
}

<|endoftext|>


<commit_before>///
/// @file   cmdoptions.cpp
/// @brief  Parse command-line options for the primecount console
///         (terminal) application.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "cmdoptions.hpp"
#include "calculator.hpp"

#include <stdint.h>
#include <vector>
#include <string>
#include <map>
#include <exception>
#include <cstdlib>
#include <cstddef>

using std::string;

namespace primecount {

void help();
void version();
bool test();

/// e.g. id = "--threads", value = "4"
struct Option
{
  string id;
  string value;
  template <typename T>
  T getValue() const
  {
    return calculator::eval<T>(value);
  }
};

/// Command-line options
std::map<string, OptionValues> optionMap;

void initOptionMap()
{
  optionMap["-h"]           = OPTION_HELP;
  optionMap["--help"]       = OPTION_HELP;
  optionMap["--legendre"]   = OPTION_LEGENDRE;
  optionMap["-l"]           = OPTION_LEHMER;
  optionMap["--lehmer"]     = OPTION_LEHMER;
  optionMap["--lmo"]        = OPTION_LMO;
  optionMap["--lmo1"]       = OPTION_LMO1;
  optionMap["--lmo2"]       = OPTION_LMO2;
  optionMap["--lmo3"]       = OPTION_LMO3;
  optionMap["--lmo4"]       = OPTION_LMO4;
  optionMap["--lmo5"]       = OPTION_LMO5;
  optionMap["--Li"]         = OPTION_LI;
  optionMap["--Li_inverse"] = OPTION_LIINV;
  optionMap["-m"]           = OPTION_MEISSEL;
  optionMap["--meissel"]    = OPTION_MEISSEL;
  optionMap["-n"]           = OPTION_NTHPRIME;
  optionMap["--nthprime"]   = OPTION_NTHPRIME;
  optionMap["--number"]     = OPTION_NUMBER;
  optionMap["--phi"]        = OPTION_PHI;
  optionMap["-p"]           = OPTION_PRIMESIEVE;
  optionMap["--primesieve"] = OPTION_PRIMESIEVE;
  optionMap["--test"]       = OPTION_TEST;
  optionMap["-t"]           = OPTION_THREADS;
  optionMap["--threads"]    = OPTION_THREADS;
  optionMap["-v"]           = OPTION_VERSION;
  optionMap["--version"]    = OPTION_VERSION;
}

/// e.g. "--threads=8" -> { id = "--threads", value = "8" }
Option makeOption(const string& str)
{
  Option option;
  size_t delimiter = string::npos;
  if (optionMap.count(str) == 0)
    delimiter = str.find_first_of("=0123456789");

  if (delimiter == string::npos)
    option.id = str;
  else
  {
    option.id = str.substr(0, delimiter);
    option.value = str.substr(delimiter + (str.at(delimiter) == '=' ? 1 : 0));
  }
  if (option.id.empty() && !option.value.empty())
    option.id = "--number";
  if (optionMap.count(option.id) == 0)
    option.id = "--help";

  return option;
}

PrimeCountOptions parseOptions(int argc, char** argv)
{
  initOptionMap();
  PrimeCountOptions pco;
  std::vector<int64_t> numbers;

  try
  {
    // iterate over the command-line options
    for (int i = 1; i < argc; i++)
    {
      Option option = makeOption(argv[i]);
      switch (optionMap[option.id])
      {
        case OPTION_NUMBER:  numbers.push_back(option.getValue<int64_t>()); break;
        case OPTION_THREADS: pco.threads = option.getValue<int>(); break;
        case OPTION_HELP:    help(); break;
        case OPTION_TEST:    if (test()) exit(0); exit(1);
        case OPTION_VERSION: version(); break;
        default:             pco.option = optionMap[option.id];
      }
    }
  }
  catch (std::exception&) {
    help();
  }

  if (numbers.size() >= 1)
    pco.x = numbers[0];
  if (numbers.size() >= 2)
    pco.a = numbers[1];

  return pco;
}

} // namespace primecount
<commit_msg>Add OPTION_PI<commit_after>///
/// @file   cmdoptions.cpp
/// @brief  Parse command-line options for the primecount console
///         (terminal) application.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "cmdoptions.hpp"
#include "calculator.hpp"

#include <stdint.h>
#include <vector>
#include <string>
#include <map>
#include <exception>
#include <cstdlib>
#include <cstddef>

using std::string;

namespace primecount {

void help();
void version();
bool test();

/// e.g. id = "--threads", value = "4"
struct Option
{
  string id;
  string value;
  template <typename T>
  T getValue() const
  {
    return calculator::eval<T>(value);
  }
};

/// Command-line options
std::map<string, OptionValues> optionMap;

void initOptionMap()
{
  optionMap["-h"]           = OPTION_HELP;
  optionMap["--help"]       = OPTION_HELP;
  optionMap["--legendre"]   = OPTION_LEGENDRE;
  optionMap["-l"]           = OPTION_LEHMER;
  optionMap["--lehmer"]     = OPTION_LEHMER;
  optionMap["--lmo"]        = OPTION_LMO;
  optionMap["--lmo1"]       = OPTION_LMO1;
  optionMap["--lmo2"]       = OPTION_LMO2;
  optionMap["--lmo3"]       = OPTION_LMO3;
  optionMap["--lmo4"]       = OPTION_LMO4;
  optionMap["--lmo5"]       = OPTION_LMO5;
  optionMap["--Li"]         = OPTION_LI;
  optionMap["--Li_inverse"] = OPTION_LIINV;
  optionMap["-m"]           = OPTION_MEISSEL;
  optionMap["--meissel"]    = OPTION_MEISSEL;
  optionMap["-n"]           = OPTION_NTHPRIME;
  optionMap["--nthprime"]   = OPTION_NTHPRIME;
  optionMap["--number"]     = OPTION_NUMBER;
  optionMap["--phi"]        = OPTION_PHI;
  optionMap["--pi"]         = OPTION_PI;
  optionMap["-p"]           = OPTION_PRIMESIEVE;
  optionMap["--primesieve"] = OPTION_PRIMESIEVE;
  optionMap["--test"]       = OPTION_TEST;
  optionMap["-t"]           = OPTION_THREADS;
  optionMap["--threads"]    = OPTION_THREADS;
  optionMap["-v"]           = OPTION_VERSION;
  optionMap["--version"]    = OPTION_VERSION;
}

/// e.g. "--threads=8" -> { id = "--threads", value = "8" }
Option makeOption(const string& str)
{
  Option option;
  size_t delimiter = string::npos;
  if (optionMap.count(str) == 0)
    delimiter = str.find_first_of("=0123456789");

  if (delimiter == string::npos)
    option.id = str;
  else
  {
    option.id = str.substr(0, delimiter);
    option.value = str.substr(delimiter + (str.at(delimiter) == '=' ? 1 : 0));
  }
  if (option.id.empty() && !option.value.empty())
    option.id = "--number";
  if (optionMap.count(option.id) == 0)
    option.id = "--help";

  return option;
}

PrimeCountOptions parseOptions(int argc, char** argv)
{
  initOptionMap();
  PrimeCountOptions pco;
  std::vector<int64_t> numbers;

  try
  {
    // iterate over the command-line options
    for (int i = 1; i < argc; i++)
    {
      Option option = makeOption(argv[i]);
      switch (optionMap[option.id])
      {
        case OPTION_NUMBER:  numbers.push_back(option.getValue<int64_t>()); break;
        case OPTION_THREADS: pco.threads = option.getValue<int>(); break;
        case OPTION_HELP:    help(); break;
        case OPTION_TEST:    if (test()) exit(0); exit(1);
        case OPTION_VERSION: version(); break;
        default:             pco.option = optionMap[option.id];
      }
    }
  }
  catch (std::exception&) {
    help();
  }

  if (numbers.size() >= 1)
    pco.x = numbers[0];
  if (numbers.size() >= 2)
    pco.a = numbers[1];

  return pco;
}

} // namespace primecount
<|endoftext|>


<commit_before>/**
 * Copyright © 2014-2015, Matthijs Möhlmann
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *   Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/exception.h>

#include <algorithm>
#include <iostream>

#include "detail/prepared_statement_handle.h"
#include "detail/connection_handle.h"

namespace sqlpp
{
  namespace postgresql
  {
    namespace
    {
      detail::prepared_statement_handle_t prepare_statement(detail::connection_handle& handle,
                                                            const std::string& stmt,
                                                            const size_t& paramCount)
      {
        if (handle.config->debug)
        {
          std::cerr << "PostgreSQL debug: preparing: " << stmt << std::endl;
        }

        detail::prepared_statement_handle_t result(handle.postgres, paramCount, handle.config->debug);

        // Generate a random name for the prepared statement
        while (std::find(handle.prepared_statement_names.begin(), handle.prepared_statement_names.end(), result.name) !=
               handle.prepared_statement_names.end())
        {
          std::generate_n(result.name.begin(), 6, []()
                          {
                            const char charset[] = "0123456789"
                                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                                   "abcdefghijklmnopqrstuvwxyz";
                            constexpr size_t max = (sizeof(charset) - 1);
                            std::random_device rd;
                            return charset[rd() % max];
                          });
        }
        handle.prepared_statement_names.push_back(result.name);

        // Create the prepared statement
        PGresult* res = PQprepare(handle.postgres, result.name.c_str(), stmt.c_str(), 0, nullptr);
        std::string errmsg = "PostgreSQL error: ";
        ExecStatusType ret = PQresultStatus(res);
        std::string rerrmsg(PQresultErrorMessage(res));
        PQclear(res);
        switch (ret)
        {
          case PGRES_EMPTY_QUERY:
          case PGRES_COPY_OUT:
          case PGRES_COPY_IN:
          case PGRES_BAD_RESPONSE:
          case PGRES_NONFATAL_ERROR:
          case PGRES_FATAL_ERROR:
          case PGRES_COPY_BOTH:
            errmsg.append(std::string(PQresStatus(ret)) + std::string(": ") + rerrmsg);
            throw sqlpp::exception(errmsg);
          case PGRES_COMMAND_OK:
          case PGRES_TUPLES_OK:
          case PGRES_SINGLE_TUPLE:
          default:
            result.valid = true;
            break;
        }

        return result;
      }

      void execute_statement(detail::connection_handle& handle, detail::prepared_statement_handle_t& prepared)
      {
        // Execute a prepared statement
        char* paramValues[prepared.paramValues.size()];
        // int paramLengths[prepared.paramValues.size()];
        for (uint32_t i = 0; i < prepared.paramValues.size(); i++)
        {
          if (!prepared.nullValues[i])
          {
            paramValues[i] = const_cast<char*>(prepared.paramValues[i].c_str());
            // paramLengths[i] = prepared.paramValues[i].size();
          }
          else
          {
            paramValues[i] = nullptr;
            // paramLengths[i] = 0;
          }
        }

        // Execute prepared statement with the parameters.
        if (prepared.result)
        {
          PQclear(prepared.result);
          prepared.result = nullptr;
        }
        prepared.count = 0;
        prepared.totalCount = 0;
        prepared.result = PQexecPrepared(handle.postgres, prepared.name.c_str(), prepared.paramValues.size(),
                                         paramValues, nullptr, nullptr, 0);

        // check statement
        std::string errmsg = "PostgreSQL error: ";
        ExecStatusType ret = PQresultStatus(prepared.result);
        switch (ret)
        {
          case PGRES_EMPTY_QUERY:
          case PGRES_COPY_OUT:
          case PGRES_COPY_IN:
          case PGRES_BAD_RESPONSE:
          case PGRES_NONFATAL_ERROR:
          case PGRES_FATAL_ERROR:
          case PGRES_COPY_BOTH:
            prepared.valid = false;
            errmsg.append(std::string(PQresStatus(ret)) + std::string(": ") +
                          std::string(PQresultErrorMessage(prepared.result)));
            throw sqlpp::exception(errmsg);
          case PGRES_COMMAND_OK:
          case PGRES_TUPLES_OK:
          case PGRES_SINGLE_TUPLE:
          default:
            prepared.valid = true;
            break;
        }
      }
    }

    connection::connection(const std::shared_ptr<connection_config>& config)
        : _handle(new detail::connection_handle(config))
    {
    }

    connection::~connection()
    {
    }

    // direct execution
    bind_result_t connection::select_impl(const std::string& stmt)
    {
      // Prepare statement
      std::unique_ptr<detail::prepared_statement_handle_t> prepared(
          new detail::prepared_statement_handle_t(prepare_statement(*_handle, stmt, 0)));
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, *prepared);
      return {std::move(prepared)};
    }

    size_t connection::insert_impl(const std::string& stmt)
    {
      // Prepare statement
      detail::prepared_statement_handle_t prepared = prepare_statement(*_handle, stmt, 0);
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, prepared);
      std::istringstream in(PQcmdTuples(prepared.result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::update_impl(const std::string& stmt)
    {
      // Prepare statement
      detail::prepared_statement_handle_t prepared = prepare_statement(*_handle, stmt, 0);
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, prepared);
      std::istringstream in(PQcmdTuples(prepared.result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::remove_impl(const std::string& stmt)
    {
      // Prepare statement
      detail::prepared_statement_handle_t prepared = prepare_statement(*_handle, stmt, 0);
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, prepared);
      std::istringstream in(PQcmdTuples(prepared.result));
      size_t result;
      in >> result;
      return result;
    }

    // prepared execution
    prepared_statement_t connection::prepare_impl(const std::string& stmt, const size_t& paramCount)
    {
      return {std::unique_ptr<detail::prepared_statement_handle_t>(
          new detail::prepared_statement_handle_t(prepare_statement(*_handle, stmt, paramCount)))};
    }

    bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      return {prep._handle};
    }

    size_t connection::run_prepared_execute_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::run_prepared_insert_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::run_prepared_update_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::run_prepared_remove_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    // TODO: Fix escaping.
    std::string connection::escape(const std::string& s) const
    {
      // Escape strings
      char to[(s.size() * 2) + 1];
      int err;
      size_t length = PQescapeStringConn(_handle->postgres, to, s.c_str(), s.size(), &err);
      std::string result(to, length);
      return std::move(result);
    }

    //! start transaction
    void connection::start_transaction()
    {
      if (_transaction_active)
      {
        throw sqlpp::exception("PostgreSQL error: transaction already open");
      }

      auto prepared = prepare_statement(*_handle, "BEGIN", 0);
      execute_statement(*_handle, prepared);
      _transaction_active = true;
    }

    //! commit transaction (or throw transaction if transaction has
    // finished already)
    void connection::commit_transaction()
    {
      if (!_transaction_active)
      {
        throw sqlpp::exception("PostgreSQL error: transaction failed or finished.");
      }

      _transaction_active = false;
      auto prepared = prepare_statement(*_handle, "COMMIT", 0);
      execute_statement(*_handle, prepared);
    }

    //! rollback transaction
    void connection::rollback_transaction(bool report)
    {
      if (!_transaction_active)
      {
        throw sqlpp::exception("PostgreSQL error: transaction failed or finished.");
      }
      if (report)
      {
        std::cerr << "PostgreSQL warning: rolling back unfinished transaction" << std::endl;
      }

      _transaction_active = false;
      auto prepared = prepare_statement(*_handle, "ROLLBACK", 0);
      execute_statement(*_handle, prepared);
    }

    //! report rollback failure
    void connection::report_rollback_failure(const std::string& message) noexcept
    {
      std::cerr << "PostgreSQL error: " << message << std::endl;
    }

    uint64_t connection::last_insert_id(const std::string& table, const std::string& fieldname)
    {
      std::string sql = "SELECT currval('" + table + "_" + fieldname + "_seq')";
      PGresult* res = PQexec(_handle->postgres, sql.c_str());

      // Parse the number and return.
      // TODO: A copy is happening here, how to prevent that?
      std::string in{PQgetvalue(res, 0, 0)};
      PQclear(res);
      return std::stoi(in);
    }

    ::PGconn* connection::native_handle()
    {
      return _handle->postgres;
    }
  }
}
<commit_msg>Let the compiler decide about a move or copy.<commit_after>/**
 * Copyright © 2014-2015, Matthijs Möhlmann
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *   Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sqlpp11/postgresql/connection.h>
#include <sqlpp11/exception.h>

#include <algorithm>
#include <iostream>

#include "detail/prepared_statement_handle.h"
#include "detail/connection_handle.h"

namespace sqlpp
{
  namespace postgresql
  {
    namespace
    {
      detail::prepared_statement_handle_t prepare_statement(detail::connection_handle& handle,
                                                            const std::string& stmt,
                                                            const size_t& paramCount)
      {
        if (handle.config->debug)
        {
          std::cerr << "PostgreSQL debug: preparing: " << stmt << std::endl;
        }

        detail::prepared_statement_handle_t result(handle.postgres, paramCount, handle.config->debug);

        // Generate a random name for the prepared statement
        while (std::find(handle.prepared_statement_names.begin(), handle.prepared_statement_names.end(), result.name) !=
               handle.prepared_statement_names.end())
        {
          std::generate_n(result.name.begin(), 6, []()
                          {
                            const char charset[] = "0123456789"
                                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                                   "abcdefghijklmnopqrstuvwxyz";
                            constexpr size_t max = (sizeof(charset) - 1);
                            std::random_device rd;
                            return charset[rd() % max];
                          });
        }
        handle.prepared_statement_names.push_back(result.name);

        // Create the prepared statement
        PGresult* res = PQprepare(handle.postgres, result.name.c_str(), stmt.c_str(), 0, nullptr);
        std::string errmsg = "PostgreSQL error: ";
        ExecStatusType ret = PQresultStatus(res);
        std::string rerrmsg(PQresultErrorMessage(res));
        PQclear(res);
        switch (ret)
        {
          case PGRES_EMPTY_QUERY:
          case PGRES_COPY_OUT:
          case PGRES_COPY_IN:
          case PGRES_BAD_RESPONSE:
          case PGRES_NONFATAL_ERROR:
          case PGRES_FATAL_ERROR:
          case PGRES_COPY_BOTH:
            errmsg.append(std::string(PQresStatus(ret)) + std::string(": ") + rerrmsg);
            throw sqlpp::exception(errmsg);
          case PGRES_COMMAND_OK:
          case PGRES_TUPLES_OK:
          case PGRES_SINGLE_TUPLE:
          default:
            result.valid = true;
            break;
        }

        return result;
      }

      void execute_statement(detail::connection_handle& handle, detail::prepared_statement_handle_t& prepared)
      {
        // Execute a prepared statement
        char* paramValues[prepared.paramValues.size()];
        // int paramLengths[prepared.paramValues.size()];
        for (uint32_t i = 0; i < prepared.paramValues.size(); i++)
        {
          if (!prepared.nullValues[i])
          {
            paramValues[i] = const_cast<char*>(prepared.paramValues[i].c_str());
            // paramLengths[i] = prepared.paramValues[i].size();
          }
          else
          {
            paramValues[i] = nullptr;
            // paramLengths[i] = 0;
          }
        }

        // Execute prepared statement with the parameters.
        if (prepared.result)
        {
          PQclear(prepared.result);
          prepared.result = nullptr;
        }
        prepared.count = 0;
        prepared.totalCount = 0;
        prepared.result = PQexecPrepared(handle.postgres, prepared.name.c_str(), prepared.paramValues.size(),
                                         paramValues, nullptr, nullptr, 0);

        // check statement
        std::string errmsg = "PostgreSQL error: ";
        ExecStatusType ret = PQresultStatus(prepared.result);
        switch (ret)
        {
          case PGRES_EMPTY_QUERY:
          case PGRES_COPY_OUT:
          case PGRES_COPY_IN:
          case PGRES_BAD_RESPONSE:
          case PGRES_NONFATAL_ERROR:
          case PGRES_FATAL_ERROR:
          case PGRES_COPY_BOTH:
            prepared.valid = false;
            errmsg.append(std::string(PQresStatus(ret)) + std::string(": ") +
                          std::string(PQresultErrorMessage(prepared.result)));
            throw sqlpp::exception(errmsg);
          case PGRES_COMMAND_OK:
          case PGRES_TUPLES_OK:
          case PGRES_SINGLE_TUPLE:
          default:
            prepared.valid = true;
            break;
        }
      }
    }

    connection::connection(const std::shared_ptr<connection_config>& config)
        : _handle(new detail::connection_handle(config))
    {
    }

    connection::~connection()
    {
    }

    // direct execution
    bind_result_t connection::select_impl(const std::string& stmt)
    {
      // Prepare statement
      std::unique_ptr<detail::prepared_statement_handle_t> prepared(
          new detail::prepared_statement_handle_t(prepare_statement(*_handle, stmt, 0)));
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, *prepared);
      return {std::move(prepared)};
    }

    size_t connection::insert_impl(const std::string& stmt)
    {
      // Prepare statement
      detail::prepared_statement_handle_t prepared = prepare_statement(*_handle, stmt, 0);
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, prepared);
      std::istringstream in(PQcmdTuples(prepared.result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::update_impl(const std::string& stmt)
    {
      // Prepare statement
      detail::prepared_statement_handle_t prepared = prepare_statement(*_handle, stmt, 0);
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, prepared);
      std::istringstream in(PQcmdTuples(prepared.result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::remove_impl(const std::string& stmt)
    {
      // Prepare statement
      detail::prepared_statement_handle_t prepared = prepare_statement(*_handle, stmt, 0);
      if (!prepared)
      {
        throw sqlpp::exception("PostgreSQL error: could not store result set");
      }

      // Execute statement
      execute_statement(*_handle, prepared);
      std::istringstream in(PQcmdTuples(prepared.result));
      size_t result;
      in >> result;
      return result;
    }

    // prepared execution
    prepared_statement_t connection::prepare_impl(const std::string& stmt, const size_t& paramCount)
    {
      return {std::unique_ptr<detail::prepared_statement_handle_t>(
          new detail::prepared_statement_handle_t(prepare_statement(*_handle, stmt, paramCount)))};
    }

    bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      return {prep._handle};
    }

    size_t connection::run_prepared_execute_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::run_prepared_insert_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::run_prepared_update_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    size_t connection::run_prepared_remove_impl(prepared_statement_t& prep)
    {
      execute_statement(*_handle, *prep._handle.get());

      std::istringstream in(PQcmdTuples(prep._handle->result));
      size_t result;
      in >> result;
      return result;
    }

    // TODO: Fix escaping.
    std::string connection::escape(const std::string& s) const
    {
      // Escape strings
      char to[(s.size() * 2) + 1];
      int err;
      size_t length = PQescapeStringConn(_handle->postgres, to, s.c_str(), s.size(), &err);
      std::string result(to, length);
      return result;
    }

    //! start transaction
    void connection::start_transaction()
    {
      if (_transaction_active)
      {
        throw sqlpp::exception("PostgreSQL error: transaction already open");
      }

      auto prepared = prepare_statement(*_handle, "BEGIN", 0);
      execute_statement(*_handle, prepared);
      _transaction_active = true;
    }

    //! commit transaction (or throw transaction if transaction has
    // finished already)
    void connection::commit_transaction()
    {
      if (!_transaction_active)
      {
        throw sqlpp::exception("PostgreSQL error: transaction failed or finished.");
      }

      _transaction_active = false;
      auto prepared = prepare_statement(*_handle, "COMMIT", 0);
      execute_statement(*_handle, prepared);
    }

    //! rollback transaction
    void connection::rollback_transaction(bool report)
    {
      if (!_transaction_active)
      {
        throw sqlpp::exception("PostgreSQL error: transaction failed or finished.");
      }
      if (report)
      {
        std::cerr << "PostgreSQL warning: rolling back unfinished transaction" << std::endl;
      }

      _transaction_active = false;
      auto prepared = prepare_statement(*_handle, "ROLLBACK", 0);
      execute_statement(*_handle, prepared);
    }

    //! report rollback failure
    void connection::report_rollback_failure(const std::string& message) noexcept
    {
      std::cerr << "PostgreSQL error: " << message << std::endl;
    }

    uint64_t connection::last_insert_id(const std::string& table, const std::string& fieldname)
    {
      std::string sql = "SELECT currval('" + table + "_" + fieldname + "_seq')";
      PGresult* res = PQexec(_handle->postgres, sql.c_str());

      // Parse the number and return.
      // TODO: A copy is happening here, how to prevent that?
      std::string in{PQgetvalue(res, 0, 0)};
      PQclear(res);
      return std::stoi(in);
    }

    ::PGconn* connection::native_handle()
    {
      return _handle->postgres;
    }
  }
}
<|endoftext|>


<commit_before>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Author: Eugen Wintersberger <eugen.wintersberger@desy.de>
// Created on: Oct 5, 2017
//
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include "attribute_test_fixtures.hpp"

using namespace hdf5;

namespace hdf5 {
namespace datatype {

template<typename T> class TypeTrait<std::complex<T>>
{
  public:
};

}
}

BOOST_AUTO_TEST_SUITE(AttributeTest)

BOOST_FIXTURE_TEST_SUITE(AttributeComplexIOTest,AttributeFixture)

BOOST_AUTO_TEST_CASE(test_complex_scalar)
{

}

BOOST_AUTO_TEST_CASE(test_complex_vector)
{

}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>complex was not included<commit_after>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor
// Boston, MA  02110-1301 USA
// ===========================================================================
//
// Author: Eugen Wintersberger <eugen.wintersberger@desy.de>
// Created on: Oct 5, 2017
//
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include "attribute_test_fixtures.hpp"
#include <complex>

using namespace hdf5;

namespace hdf5 {
namespace datatype {

template<typename T> class TypeTrait<std::complex<T>>
{
  public:
};

}
}

BOOST_AUTO_TEST_SUITE(AttributeTest)

BOOST_FIXTURE_TEST_SUITE(AttributeComplexIOTest,AttributeFixture)

BOOST_AUTO_TEST_CASE(test_complex_scalar)
{

}

BOOST_AUTO_TEST_CASE(test_complex_vector)
{

}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>