<commit_before>// This file is part of the dune-mlmc project:
//   http://users.dune-project.org/projects/dune-mlmc
// Copyright Holders: Rene Milk
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include <config.h>

#include <dune/common/exceptions.hh> // We use exceptions

#include <dune/mlmc/msfem.hh>
#include <dune/mlmc/mlmc.hh>
#include <dune/multiscale/common/main_init.hh>

#include <dune/stuff/common/profiler.hh>
#include <dune/stuff/common/configuration.hh>

int main(int argc, char** argv) {
  using namespace MultiLevelMonteCarlo;
  try {
    msfem_init(argc, argv);
    //    DSC::OutputScopedTiming tm("mlmc.all", DSC_LOG_INFO_0);
    DSC::ScopedTiming tm("mlmc.all");
    auto msfem_single = std::make_shared<MsFemSingleDifference>();
    auto ms_cg_fem_diff = std::make_shared<MsCgFemDifference>();
    MultiLevelMonteCarlo::MLMC mlmc;
    mlmc.addDifference(msfem_single, DSC_CONFIG_GET("mlmc.coarse_ranks", 1u));
    mlmc.addDifference(ms_cg_fem_diff, DSC_CONFIG_GET("mlmc.fine_ranks", 1u));
    const auto tolerance = DSC_CONFIG_GET("mlmc.tolerance", 0.1f);
    const auto breaks = DSC_CONFIG_GET("mlmc.breaks", 2u);
    const auto value = mlmc.expectation(tolerance, breaks);
    DSC_LOG_INFO_0 << "\nExpected " << value << std::endl;
  } catch (Dune::Exception& e) {
    return Dune::Multiscale::handle_exception(e);
  } catch (std::exception& s) {
    return Dune::Multiscale::handle_exception(s);
  }
  DSC_PROFILER.outputTimings("profiler");
  Dune::Multiscale::mem_usage();
  return 0;
}

#if 0  // example code only
int run(int argc, char **argv) {
  Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv);
  if (argc!=10) {
    if(helper.rank()==0) {
  std::cout << "usage: dune_mlmc <pFast> <pMedium> <pSlow> <log2seg> <overlap> "
                << "<corrLen> <sigma> <tol> <breaks>\n";
    }
    return 1;
  }

  // Read parameters
  const auto pFast   = DSC_CONFIG_GET("mlmc.pFast", 1u);
  const auto pMedium = DSC_CONFIG_GET("mlmc.pMedium", 2u);
  const auto pSlow   = DSC_CONFIG_GET("mlmc.pSlow", 3u);
  const auto log2seg = DSC_CONFIG_GET("mlmc.log2seg", 2u);
  const auto overlap = DSC_CONFIG_GET("mlmc.overlap", 1u);
  const auto corrLen = DSC_CONFIG_GET("mlmc.corrLen", 0.2f);
  const auto sigma   = DSC_CONFIG_GET("mlmc.sigma", 1.0f);
  const auto tol     = DSC_CONFIG_GET("mlmc.tol", 0.03f);
  const auto breaks  = DSC_CONFIG_GET("mlmc.breaks", 4u);

  // Multi level Monte Carlo estimator
  MLMC mlmc;
  Single single(log2seg,overlap,corrLen,sigma);
  Fast fast(log2seg,overlap,corrLen,sigma);
  Medium medium(log2seg,overlap,corrLen,sigma);
  Slow slow(log2seg,overlap,corrLen,sigma);

//    mlmc.addDifference(single,pSlow);

  mlmc.addDifference(fast,pFast);
  mlmc.addDifference(medium,pMedium);
  mlmc.addDifference(slow,pSlow);

  // Compute mean flux
  double t = MPI_Wtime();
  double mean = mlmc.expectation(tol,breaks,MPI_COMM_WORLD);
  t = MPI_Wtime() - t;
  DSC_LOG_INFO_0 << "Expected value: " << mean
                 << " Time: " << t << "\n";
}
#endif // 0 example code only
<commit_msg>output expectation to file<commit_after>// This file is part of the dune-mlmc project:
//   http://users.dune-project.org/projects/dune-mlmc
// Copyright Holders: Rene Milk
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include <config.h>

#include <dune/common/exceptions.hh> // We use exceptions

#include <dune/mlmc/msfem.hh>
#include <dune/mlmc/mlmc.hh>
#include <dune/multiscale/common/main_init.hh>

#include <dune/stuff/common/profiler.hh>
#include <dune/stuff/common/configuration.hh>

int main(int argc, char** argv) {
  using namespace MultiLevelMonteCarlo;
  using namespace std;
  try {
    msfem_init(argc, argv);
    //    DSC::OutputScopedTiming tm("mlmc.all", DSC_LOG_INFO_0);
    DSC::ScopedTiming tm("mlmc.all");
    auto msfem_single = make_shared<MsFemSingleDifference>();
    auto ms_cg_fem_diff = make_shared<MsCgFemDifference>();
    MultiLevelMonteCarlo::MLMC mlmc;
    mlmc.addDifference(msfem_single, DSC_CONFIG_GET("mlmc.coarse_ranks", 1u));
    mlmc.addDifference(ms_cg_fem_diff, DSC_CONFIG_GET("mlmc.fine_ranks", 1u));
    const auto tolerance = DSC_CONFIG_GET("mlmc.tolerance", 0.1f);
    const auto breaks = DSC_CONFIG_GET("mlmc.breaks", 2u);
    const auto value = mlmc.expectation(tolerance, breaks);
    DSC_LOG_INFO_0 << "\nExpected " << value << endl;
    if(Dune::MPIHelper::getCollectiveCommunication().rank() == 0) {
      unique_ptr<boost::filesystem::ofstream> csvfile(
          DSC::make_ofstream(DSC_CONFIG_GET("global.datadir", "data/") + string("/errors.csv")));
      map<string, double> csv{{"expectation", value}};
      const string sep(",");
      for (const auto& key_val : csv) {
        *csvfile << key_val.first << sep;
      }
      *csvfile << endl;
      for (const auto& key_val : csv) {
        *csvfile << key_val.second << sep;
      }
      *csvfile << endl;
    }

  } catch (Dune::Exception& e) {
    return Dune::Multiscale::handle_exception(e);
  } catch (exception& s) {
    return Dune::Multiscale::handle_exception(s);
  }
  DSC_PROFILER.outputTimings("profiler");
  Dune::Multiscale::mem_usage();
  return 0;
}

#if 0  // example code only
int run(int argc, char **argv) {
  Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv);
  if (argc!=10) {
    if(helper.rank()==0) {
  std::cout << "usage: dune_mlmc <pFast> <pMedium> <pSlow> <log2seg> <overlap> "
                << "<corrLen> <sigma> <tol> <breaks>\n";
    }
    return 1;
  }

  // Read parameters
  const auto pFast   = DSC_CONFIG_GET("mlmc.pFast", 1u);
  const auto pMedium = DSC_CONFIG_GET("mlmc.pMedium", 2u);
  const auto pSlow   = DSC_CONFIG_GET("mlmc.pSlow", 3u);
  const auto log2seg = DSC_CONFIG_GET("mlmc.log2seg", 2u);
  const auto overlap = DSC_CONFIG_GET("mlmc.overlap", 1u);
  const auto corrLen = DSC_CONFIG_GET("mlmc.corrLen", 0.2f);
  const auto sigma   = DSC_CONFIG_GET("mlmc.sigma", 1.0f);
  const auto tol     = DSC_CONFIG_GET("mlmc.tol", 0.03f);
  const auto breaks  = DSC_CONFIG_GET("mlmc.breaks", 4u);

  // Multi level Monte Carlo estimator
  MLMC mlmc;
  Single single(log2seg,overlap,corrLen,sigma);
  Fast fast(log2seg,overlap,corrLen,sigma);
  Medium medium(log2seg,overlap,corrLen,sigma);
  Slow slow(log2seg,overlap,corrLen,sigma);

//    mlmc.addDifference(single,pSlow);

  mlmc.addDifference(fast,pFast);
  mlmc.addDifference(medium,pMedium);
  mlmc.addDifference(slow,pSlow);

  // Compute mean flux
  double t = MPI_Wtime();
  double mean = mlmc.expectation(tol,breaks,MPI_COMM_WORLD);
  t = MPI_Wtime() - t;
  DSC_LOG_INFO_0 << "Expected value: " << mean
                 << " Time: " << t << "\n";
}
#endif // 0 example code only
<|endoftext|>


<commit_before>#include "view.hpp"
#include "view-transform.hpp"
#include "output.hpp"
#include <nonstd/make_unique.hpp>
#include <linux/input.h>

static double cross (double x1, double y1, double x2, double y2) // cross product
{
    return x1 * y2 - x2 * y1;
}

static double vlen(double x1, double y1) // length of vector centered at the origin
{
    return std::sqrt(x1 * x1 + y1 * y1);
}

class wf_wrot : public wayfire_plugin_t
{
    button_callback call;

    int last_x, last_y;

    public:
        void init(wayfire_config *config)
        {
            call = [=] (uint32_t, int x, int y)
            {
                output->activate_plugin(grab_interface);
                grab_interface->grab();

                last_x = x;
                last_y = y;
            };

            auto button = (*config)["wrot"]->get_option("activate", "<alt> BTN_RIGHT");
            output->add_button(button, &call);

            grab_interface->callbacks.pointer.motion = [=] (int x, int y)
            {
                auto view = output->get_top_view();

                if (!view->get_transformer("wrot"))
                    view->add_transformer(nonstd::make_unique<wf_2D_view> (view), "wrot");

                auto tr = dynamic_cast<wf_2D_view*> (view->get_transformer("wrot").get());
                assert(tr);

                view->damage();

                auto g = view->get_wm_geometry();

                double cx = g.x + g.width / 2.0;
                double cy = g.y + g.height / 2.0;

                double x1 = last_x - cx, y1 = last_y - cy;
                double x2 = x - cx, y2 = y - cy;

                /* cross(a, b) = |a| * |b| * sin(a, b) */
                tr->angle -= std::asin(cross(x1, y1, x2, y2) / vlen(x1, y1) / vlen(x2, y2));

                view->damage();

                last_x = x;
                last_y = y;
            };

            grab_interface->callbacks.pointer.button = [=] (uint32_t, uint32_t s)
            {
                if (s == WLR_BUTTON_RELEASED)
                    input_released();
            };
        }

        void input_released()
        {
            grab_interface->ungrab();
            output->deactivate_plugin(grab_interface);
        }

        void fini()
        {
            if (grab_interface->is_grabbed())
                input_released();

            output->rem_button(&call);
        }
};

extern "C"
{
wayfire_plugin_t *newInstance()
{
    return new wf_wrot;
}
}
<commit_msg>wrot: disable the rotation if the mouse gets in the center of the view<commit_after>#include "view.hpp"
#include "view-transform.hpp"
#include "output.hpp"
#include <nonstd/make_unique.hpp>
#include <linux/input.h>

static double cross (double x1, double y1, double x2, double y2) // cross product
{
    return x1 * y2 - x2 * y1;
}

static double vlen(double x1, double y1) // length of vector centered at the origin
{
    return std::sqrt(x1 * x1 + y1 * y1);
}

class wf_wrot : public wayfire_plugin_t
{
    button_callback call;

    int last_x, last_y;

    public:
        void init(wayfire_config *config)
        {
            call = [=] (uint32_t, int x, int y)
            {
                output->activate_plugin(grab_interface);
                grab_interface->grab();

                last_x = x;
                last_y = y;
            };

            auto button = (*config)["wrot"]->get_option("activate", "<alt> BTN_RIGHT");
            output->add_button(button, &call);

            grab_interface->callbacks.pointer.motion = [=] (int x, int y)
            {
                auto view = output->get_top_view();

                if (!view->get_transformer("wrot"))
                    view->add_transformer(nonstd::make_unique<wf_2D_view> (view), "wrot");

                auto tr = dynamic_cast<wf_2D_view*> (view->get_transformer("wrot").get());
                assert(tr);

                view->damage();

                auto g = view->get_wm_geometry();

                double cx = g.x + g.width / 2.0;
                double cy = g.y + g.height / 2.0;

                double x1 = last_x - cx, y1 = last_y - cy;
                double x2 = x - cx, y2 = y - cy;

                if (vlen(x2, y2) <= 25)
                    return view->pop_transformer("wrot");

                /* cross(a, b) = |a| * |b| * sin(a, b) */
                tr->angle -= std::asin(cross(x1, y1, x2, y2) / vlen(x1, y1) / vlen(x2, y2));

                view->damage();

                last_x = x;
                last_y = y;
            };

            grab_interface->callbacks.pointer.button = [=] (uint32_t, uint32_t s)
            {
                if (s == WLR_BUTTON_RELEASED)
                    input_released();
            };
        }

        void input_released()
        {
            grab_interface->ungrab();
            output->deactivate_plugin(grab_interface);
        }

        void fini()
        {
            if (grab_interface->is_grabbed())
                input_released();

            output->rem_button(&call);
        }
};

extern "C"
{
wayfire_plugin_t *newInstance()
{
    return new wf_wrot;
}
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2013 Daniel Dyer

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

#include "types.h"
#include "dynamics.h"

DynamicsModel::~DynamicsModel() {}

/*
Runs the dynamics model and calculates the expected linear and angular
accelerations for this timestep. Eventually this will need to take control
surface inputs as a parameter.

For now, it calculates the expected acceleration as the centripetal
acceleration expected to be felt for the current velocity and angular
velocity, and doesn't attempt to calculate angular acceleration at all.
*/
AccelerationVector CentripetalModel::evaluate(
const State &in, const ControlVector &control) const {
    #pragma unused(control)

    AccelerationVector output;

    /* First convert velocity to body frame. */
    Eigen::Matrix<real_t, 3, 1> velocity_body;
    velocity_body = Quaternionr(in.attitude()) * in.velocity();

    /* Calculate centripetal acceleration. */
    output.segment<3>(0) = in.angular_velocity().cross(velocity_body);

    /* Clear angular acceleration. */
    output.segment<3>(3) << 0, 0, 0;

    return output;
}

/*
Runs a basic fixed-wing flight dynamics model, calculating:
- Lift and drag as a quartic function of alpha
- Side force (see header for details)
- Thrust as a function of prop area, prop exit velocity coefficient, forward
  velocity, and throttle
- Pitch moment as a linear function of alpha, a quadratic function of pitch
  rate, and a linear function of control surface position
- Roll moment as a linear function of roll rate and control surface position
- Yaw moment as a linear function of alpha, yaw rate, and control surface
  position
*/
AccelerationVector FixedWingFlightDynamicsModel::evaluate(
const State &in, const ControlVector &control) const {
    /* Cache state data for convenience */
    Quaternionr attitude = Quaternionr(in.attitude());
    real_t yaw_rate = in.angular_velocity()[2],
           pitch_rate = in.angular_velocity()[1],
           roll_rate = in.angular_velocity()[0];

    /* External axes */
    Vector3r airflow, lift_axis, drag_axis, side_axis;
    real_t v, v_inv;

    airflow = attitude * (in.wind_velocity() - in.velocity());
    v = airflow.norm();

    if (v < UKF_DYNAMICS_MIN_V) {
        /*
        Airflow too slow for any of this to work; just return acceleration
        due to gravity
        */
        AccelerationVector output;
        output.segment<3>(0) = attitude * Vector3r(0, 0, G_ACCEL);

        /* No angular acceleration */
        output.segment<3>(3) << 0, 0, 0;
        return output;
    }

    v_inv = (real_t)1.0 / v;

    /* Determine alpha and beta: alpha = atan(wz/wx), beta = atan(wy/|wxz|) */
    real_t alpha, beta, qbar, alpha2, beta2;
    qbar = RHO * v * v * (real_t)0.5;
    alpha = std::atan2(-airflow.z(), -airflow.x());
    beta = std::asin(airflow.y() * v_inv);

    alpha2 = alpha * alpha;
    beta2 = beta * beta;

    /*
    Set up a^4, a^3, a^2, a, 1 so that we can use dot product for the
    polynomial evaluation.
    */
    Vector5r alpha_coeffs;
    alpha_coeffs << alpha2 * alpha2, alpha2 * alpha, alpha2, alpha, 1.0;

    /* Evaluate quartics in alpha to determine lift and drag */
    real_t lift = alpha_coeffs.dot(c_lift_alpha),
           drag = alpha_coeffs.dot(c_drag_alpha);

    /*
    Assume lift is somewhat well-behaved for alpha in the range [-0.25, 0.25].
    If outside that range, clamp it to 0 so that the polynomial doesn't have
    to model the full possible range.
    */
    if (std::abs(alpha) > 1.0) {
        lift = 0.0;
    } else if (alpha > 0.25) {
        lift = std::max(lift, 0.0);
    } else if (alpha < -0.25) {
        lift = std::min(lift, 0.0);
    }

    /*
    Determine motor thrust and torque:
    https://www.grc.nasa.gov/WWW/Wright/airplane/propth.html

    Propeller thrust =
    F = 0.5 * rho * A * (Ve^2 - V0^2)
    where A = propeller disc area, Ve = exit velocity, V0 = air velocity

    In this formulation,
    F = 0.5 * rho * A * ((k * rpm)^2 - V0^2)

    Presumably the relationship between thrust and torque on airframe is
    constant? If so, they're related by prop_ct.
    */
    real_t thrust = 0.0;
    if (motor_idx < UKF_CONTROL_DIM) {
        real_t ve = prop_cve * control[motor_idx], v0 = airflow.x();
        thrust = (real_t)0.5 * RHO * prop_area * (ve * ve - v0 * v0);
        if (thrust < 0.0) {
            /* Folding prop, so assume no drag */
            thrust = 0.0;
        }
    }

    /*
    Set up the side force coefficient vector, and calculate side force
    */
    Vector4r side_coeffs;
    side_coeffs << beta2, beta, yaw_rate, roll_rate;

    real_t side_force = side_coeffs.dot(c_side_force) +
        control.dot(c_side_force_control);

    /*
    Calculate pitch moment
    */
    Vector2r pitch_coeffs;
    pitch_coeffs << alpha,
        pitch_rate * (pitch_rate < 0.0 ? -pitch_rate : pitch_rate);

    real_t pitch_moment = pitch_coeffs.dot(c_pitch_moment) +
        control.dot(c_pitch_moment_control);

    /*
    Roll moment
    */
    Vector1r roll_coeffs;
    roll_coeffs << roll_rate;
    real_t roll_moment = roll_coeffs.dot(c_roll_moment) +
        control.dot(c_roll_moment_control);

    /*
    Yaw moment
    */
    Vector2r yaw_coeffs;
    yaw_coeffs << beta, yaw_rate;
    real_t yaw_moment = yaw_coeffs.dot(c_yaw_moment) +
        control.dot(c_yaw_moment_control);

    /*
    Sum and apply forces and moments
    */
    Vector3r sum_force, sum_torque;

    sum_force = qbar * (
            (lift * std::cos(alpha) + drag * std::sin(alpha)) * Vector3r(0, 0, -1) +
            (lift * std::sin(alpha) - drag * std::cos(alpha) - side_force * std::sin(beta)) * Vector3r(1, 0, 0) +
            side_force * std::cos(beta) * Vector3r(0, 1, 0)
        ) +
        thrust * Vector3r(1, 0, 0);
    sum_torque = qbar * Vector3r(roll_moment, pitch_moment, yaw_moment);

    /* Calculate linear acceleration (F / m) */
    AccelerationVector output;
    output.segment<3>(0) = sum_force * mass_inv +
                           attitude * Vector3r(0, 0, G_ACCEL);

    /* Calculate angular acceleration (tau / inertia tensor) */
    output.segment<3>(3) = inertia_tensor_inv * sum_torque;

    return output;
}
<commit_msg>Replace pitch rate^2 with pitch rate in pitch moment equation; use qbar based on horizontal airflow<commit_after>/*
Copyright (C) 2013 Daniel Dyer

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

#include "types.h"
#include "dynamics.h"

DynamicsModel::~DynamicsModel() {}

/*
Runs the dynamics model and calculates the expected linear and angular
accelerations for this timestep. Eventually this will need to take control
surface inputs as a parameter.

For now, it calculates the expected acceleration as the centripetal
acceleration expected to be felt for the current velocity and angular
velocity, and doesn't attempt to calculate angular acceleration at all.
*/
AccelerationVector CentripetalModel::evaluate(
const State &in, const ControlVector &control) const {
    #pragma unused(control)

    AccelerationVector output;

    /* First convert velocity to body frame. */
    Eigen::Matrix<real_t, 3, 1> velocity_body;
    velocity_body = Quaternionr(in.attitude()) * in.velocity();

    /* Calculate centripetal acceleration. */
    output.segment<3>(0) = in.angular_velocity().cross(velocity_body);

    /* Clear angular acceleration. */
    output.segment<3>(3) << 0, 0, 0;

    return output;
}

/*
Runs a basic fixed-wing flight dynamics model, calculating:
- Lift and drag as a quartic function of alpha
- Side force (see header for details)
- Thrust as a function of prop area, prop exit velocity coefficient, forward
  velocity, and throttle
- Pitch moment as a linear function of alpha, a quadratic function of pitch
  rate, and a linear function of control surface position
- Roll moment as a linear function of roll rate and control surface position
- Yaw moment as a linear function of alpha, yaw rate, and control surface
  position
*/
AccelerationVector FixedWingFlightDynamicsModel::evaluate(
const State &in, const ControlVector &control) const {
    /* Cache state data for convenience */
    Quaternionr attitude = Quaternionr(in.attitude());
    real_t yaw_rate = in.angular_velocity()[2],
           pitch_rate = in.angular_velocity()[1],
           roll_rate = in.angular_velocity()[0];

    /* External axes */
    Vector3r airflow, lift_axis, drag_axis, side_axis;
    real_t v, v_inv;

    airflow = attitude * (in.wind_velocity() - in.velocity());
    v = airflow.norm();

    if (v < UKF_DYNAMICS_MIN_V) {
        /*
        Airflow too slow for any of this to work; just return acceleration
        due to gravity
        */
        AccelerationVector output;
        output.segment<3>(0) = attitude * Vector3r(0, 0, G_ACCEL);

        /* No angular acceleration */
        output.segment<3>(3) << 0, 0, 0;
        return output;
    }

    v_inv = (real_t)1.0 / v;

    /* Determine alpha and beta: alpha = atan(wz/wx), beta = atan(wy/|wxz|) */
    real_t alpha, beta, qbar, alpha2, beta2;
    qbar = RHO * (airflow.y()*airflow.y() + airflow.x()*airflow.x()) * (real_t)0.5;
    alpha = std::atan2(-airflow.z(), -airflow.x());
    beta = std::asin(airflow.y() * v_inv);

    alpha2 = alpha * alpha;
    beta2 = beta * beta;

    /*
    Set up a^4, a^3, a^2, a, 1 so that we can use dot product for the
    polynomial evaluation.
    */
    Vector5r alpha_coeffs;
    alpha_coeffs << alpha2 * alpha2, alpha2 * alpha, alpha2, alpha, 1.0;

    /* Evaluate quartics in alpha to determine lift and drag */
    real_t lift = alpha_coeffs.dot(c_lift_alpha),
           drag = alpha_coeffs.dot(c_drag_alpha);

    /*
    Assume lift is somewhat well-behaved for alpha in the range [-0.25, 0.25].
    If outside that range, clamp it to 0 so that the polynomial doesn't have
    to model the full possible range.
    */
    if (std::abs(alpha) > 1.0) {
        lift = 0.0;
    } else if (alpha > 0.25) {
        lift = std::max(lift, 0.0);
    } else if (alpha < -0.25) {
        lift = std::min(lift, 0.0);
    }

    /*
    Determine motor thrust and torque:
    https://www.grc.nasa.gov/WWW/Wright/airplane/propth.html

    Propeller thrust =
    F = 0.5 * rho * A * (Ve^2 - V0^2)
    where A = propeller disc area, Ve = exit velocity, V0 = air velocity

    In this formulation,
    F = 0.5 * rho * A * ((k * rpm)^2 - V0^2)

    Presumably the relationship between thrust and torque on airframe is
    constant? If so, they're related by prop_ct.
    */
    real_t thrust = 0.0;
    if (motor_idx < UKF_CONTROL_DIM) {
        real_t ve = prop_cve * control[motor_idx], v0 = airflow.x();
        thrust = (real_t)0.5 * RHO * prop_area * (ve * ve - v0 * v0);
        if (thrust < 0.0) {
            /* Folding prop, so assume no drag */
            thrust = 0.0;
        }
    }

    /*
    Set up the side force coefficient vector, and calculate side force
    */
    Vector4r side_coeffs;
    side_coeffs << beta2, beta, yaw_rate, roll_rate;

    real_t side_force = side_coeffs.dot(c_side_force) +
        control.dot(c_side_force_control);

    /*
    Calculate pitch moment
    */
    Vector2r pitch_coeffs;
    pitch_coeffs << alpha, pitch_rate;

    real_t pitch_moment = pitch_coeffs.dot(c_pitch_moment) +
        control.dot(c_pitch_moment_control);

    /*
    Roll moment
    */
    Vector1r roll_coeffs;
    roll_coeffs << roll_rate;
    real_t roll_moment = roll_coeffs.dot(c_roll_moment) +
        control.dot(c_roll_moment_control);

    /*
    Yaw moment
    */
    Vector2r yaw_coeffs;
    yaw_coeffs << beta, yaw_rate;
    real_t yaw_moment = yaw_coeffs.dot(c_yaw_moment) +
        control.dot(c_yaw_moment_control);

    /*
    Sum and apply forces and moments
    */
    Vector3r sum_force, sum_torque;

    sum_force = qbar * (
            (lift * std::cos(alpha) + drag * std::sin(alpha)) * Vector3r(0, 0, -1) +
            (lift * std::sin(alpha) - drag * std::cos(alpha) - side_force * std::sin(beta)) * Vector3r(1, 0, 0) +
            side_force * std::cos(beta) * Vector3r(0, 1, 0)
        ) +
        thrust * Vector3r(1, 0, 0);
    sum_torque = qbar * Vector3r(roll_moment, pitch_moment, yaw_moment);

    /* Calculate linear acceleration (F / m) */
    AccelerationVector output;
    output.segment<3>(0) = sum_force * mass_inv +
                           attitude * Vector3r(0, 0, G_ACCEL);

    /* Calculate angular acceleration (tau / inertia tensor) */
    output.segment<3>(3) = inertia_tensor_inv * sum_torque;

    return output;
}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS pb11 (1.46.104); FILE MERGED 2006/01/30 10:38:31 pb 1.46.104.3: fix: #i48648# acc children not always transient 2006/01/26 11:22:35 pb 1.46.104.2: RESYNC: (1.46-1.47); FILE MERGED 2006/01/25 08:16:08 pb 1.46.104.1: fix: #i48648# support for tablecell navigation<commit_after><|endoftext|>


<commit_before>#include "antsUtilities.h"
#include "antsAllocImage.h"
#include <algorithm>
#include "ReadWriteData.h"

#include <stdio.h>

#include "itkAffineTransform.h"
#include "itkCenteredTransformInitializer.h"
#include "itkMattesMutualInformationImageToImageMetricv4.h"
#include "itkANTSNeighborhoodCorrelationImageToImageMetricv4.h"
#include "itkResampleImageFilter.h"
#include "itkTransformFileWriter.h"

#include <string>
#include <vector>

namespace ants
{
int antsUtilitiesTesting( std::vector<std::string> args, std::ostream* itkNotUsed( out_stream ) )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "antsUtilitiesTesting" );

  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = ITK_NULLPTR;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 3 )
    {
    std::cerr << "Usage: " << argv[0] << " testImage whichMetric[CCorMI] lowerScalexUpperScalexNumberOfScaleSamples numberOfRotationSamples doPrintMatchingFileName transformName setOfTrainingImages" << std::endl;
    std::cerr << "Notes:  if transformName='none', no transform is printed" << std::endl;
    std::cerr << "Example call:  " << std::endl;
    std::cerr << "   " << argv[0] << "test.nii.gz CC 0.25x3x10 10 testTransform.txt 0 training*.nii.gz" << std::endl;

    if( argc >= 2 &&
        ( std::string( argv[1] ) == std::string("--help") || std::string( argv[1] ) == std::string("-h") ) )
      {
      return EXIT_SUCCESS;
      }
    return EXIT_FAILURE;
    }

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

  const unsigned int ImageDimension = 2;

  typedef float PixelType;

  typedef itk::Image<PixelType, ImageDimension> ImageType;

  typedef itk::MattesMutualInformationImageToImageMetricv4<ImageType, ImageType, ImageType> MIMetricType;
  typedef itk::ANTSNeighborhoodCorrelationImageToImageMetricv4<ImageType, ImageType, ImageType> CCMetricType;

  CCMetricType::RadiusType ccRadius;
  ccRadius.Fill( 4 );

  unsigned int metricType = 0;
  if( strcmp( argv[2], "CC" ) == 0 )
    {
    metricType = 1;
    }
  else if( strcmp( argv[2], "MI" ) == 0 )
    {
    metricType = 2;
    }
  else
    {
    std::cerr << "Unrecognized metric " << argv[2] << std::endl;
    return EXIT_FAILURE;
    }

  // read in test image

  ImageType::Pointer testImage = ImageType::New();
  ReadImage<ImageType>( testImage, argv[1] );

  // read in training image file names

  std::vector<std::string> trainingImageFileNames;
  for( int n = 7; n < argc; n++ )
    {
    trainingImageFileNames.push_back( std::string( argv[n] ) );
    }

//   // Get scale parameters

  std::vector<float> scaleParameters = ConvertVector<float>( std::string( argv[3] ) );
  if( scaleParameters.size() != 3 )
    {
    std::cerr << "The scale parameters were improperly specified.  See usage." << std::endl;
    return EXIT_FAILURE;
    }
  float scaleLowerBoundLog = vcl_log( scaleParameters[0] );
  float scaleUpperBoundLog = vcl_log( scaleParameters[1] );
  unsigned int scaleNumberOfSamples = static_cast<unsigned int>( scaleParameters[2] );
  float scaleDelta = ( scaleUpperBoundLog - scaleLowerBoundLog ) / static_cast<float>( scaleNumberOfSamples - 1 );

//   // Get rotation sampling resolution

  unsigned int rotationNumberOfSamples = static_cast<unsigned int>( atoi( argv[4] ) );
  float rotationDelta = ( 2.0 * vnl_math::pi - 0.0 ) / static_cast<float>( rotationNumberOfSamples - 1 );

//   // Now go through the rotations + scalings to find the optimal pose.

  typedef itk::AffineTransform<double, ImageDimension> AffineTransformType;

  float optimalMetricValue = itk::NumericTraits<float>::max();
  AffineTransformType::Pointer optimalTransform = ITK_NULLPTR;
  unsigned int optimalMetricIndex = 0;

  for( unsigned int n = 0; n < trainingImageFileNames.size(); n++ )
    {
    ImageType::Pointer trainingImage = ImageType::New();
    ReadImage<ImageType>( trainingImage, trainingImageFileNames[n].c_str() );

    // Initialize centered transform (based on the center of the image)

    AffineTransformType::Pointer initialTransform = AffineTransformType::New();

    typedef itk::CenteredTransformInitializer<AffineTransformType, ImageType, ImageType> TransformInitializerType;
    TransformInitializerType::Pointer initializer = TransformInitializerType::New();
    initializer->SetTransform( initialTransform );
    initializer->SetFixedImage( trainingImage );
    initializer->SetMovingImage( testImage );
    initializer->GeometryOn();

    initializer->InitializeTransform();

    for( float angle = 0.0; angle <= 2.0 * vnl_math::pi; angle += rotationDelta )
      {
      std::cout << "angle:  " << angle << std::endl;

      AffineTransformType::MatrixType rotationMatrix;
      rotationMatrix( 0, 0 ) = rotationMatrix( 1, 1 ) = vcl_cos( angle );
      rotationMatrix( 1, 0 ) = vcl_sin( angle );
      rotationMatrix( 0, 1 ) = -rotationMatrix( 1, 0 );

      for( float scaleLog = scaleLowerBoundLog; scaleLog <= scaleUpperBoundLog; scaleLog += scaleDelta )
        {
        float scale = vcl_exp( scaleLog );

        std::cout << "  scale:  " << scaleLog << std::endl;

        AffineTransformType::Pointer affineTransform = AffineTransformType::New();
        affineTransform->SetCenter( initialTransform->GetCenter() );
        affineTransform->SetTranslation( initialTransform->GetTranslation() );
        affineTransform->SetMatrix( initialTransform->GetMatrix() * rotationMatrix * scale );

//         typedef itk::ResampleImageFilter<ImageType, ImageType, double> ResamplerType;
//         ResamplerType::Pointer resampleFilter = ResamplerType::New();
//         resampleFilter->SetInput( testImage );
//         resampleFilter->SetOutputParametersFromImage( trainingImage );
//         resampleFilter->SetTransform( affineTransform );
//         resampleFilter->SetDefaultPixelValue( 255 );
//         resampleFilter->Update();
//         WriteImage<ImageType>( resampleFilter->GetOutput(), "test.nii.gz" );

        float metricValue = 0;

        if( metricType == 1 )
          {
          CCMetricType::Pointer metric = CCMetricType::New();
          metric->SetFixedImage( trainingImage );
          metric->SetMovingImage( testImage );
          metric->SetRadius( ccRadius );
          metric->SetMovingTransform( affineTransform );
          metric->SetVirtualDomainFromImage( trainingImage );
          metric->Initialize();

          try
            {
            metricValue = metric->GetValue();
            }
          catch(...)
            {
            continue;
            }
          }
        else if( metricType == 2 )
          {
          MIMetricType::Pointer metric = MIMetricType::New();
          metric->SetFixedImage( trainingImage );
          metric->SetMovingImage( testImage );
          metric->SetNumberOfHistogramBins( 32 );
          metric->SetMovingTransform( affineTransform );
          metric->SetVirtualDomainFromImage( trainingImage );
          metric->Initialize();

          try
            {
            metricValue = metric->GetValue();
            }
          catch(...)
            {
            continue;
            }
          }
        if( metricValue < optimalMetricValue )
          {
          optimalMetricValue = metricValue;
          optimalTransform = affineTransform;
          optimalMetricIndex = n;
          }
        }
      }
    }

  if( strcmp( argv[6], "none" ) != 0 )
    {
    typedef itk::TransformFileWriter TransformWriterType;
    TransformWriterType::Pointer transformWriter = TransformWriterType::New();
    transformWriter->SetInput( optimalTransform );
    transformWriter->SetFileName( argv[6] );
    transformWriter->Update();
    }

  if( static_cast<bool>( atoi( argv[5] ) ) )
    {
    std::cout << trainingImageFileNames[optimalMetricIndex] << std::endl;
    }
  std::cout << optimalMetricValue << std::endl;

  return EXIT_SUCCESS;
}

} // namespace ants
<commit_msg>BUG:  Remove debugging print statements..<commit_after>#include "antsUtilities.h"
#include "antsAllocImage.h"
#include <algorithm>
#include "ReadWriteData.h"

#include <stdio.h>

#include "itkAffineTransform.h"
#include "itkCenteredTransformInitializer.h"
#include "itkMattesMutualInformationImageToImageMetricv4.h"
#include "itkANTSNeighborhoodCorrelationImageToImageMetricv4.h"
#include "itkResampleImageFilter.h"
#include "itkTransformFileWriter.h"

#include <string>
#include <vector>

namespace ants
{
int antsUtilitiesTesting( std::vector<std::string> args, std::ostream* itkNotUsed( out_stream ) )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "antsUtilitiesTesting" );

  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = ITK_NULLPTR;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 3 )
    {
    std::cerr << "Usage: " << argv[0] << " testImage whichMetric[CCorMI] lowerScalexUpperScalexNumberOfScaleSamples numberOfRotationSamples doPrintMatchingFileName transformName setOfTrainingImages" << std::endl;
    std::cerr << "Notes:  if transformName='none', no transform is printed" << std::endl;
    std::cerr << "Example call:  " << std::endl;
    std::cerr << "   " << argv[0] << "test.nii.gz CC 0.25x3x10 10 testTransform.txt 0 training*.nii.gz" << std::endl;

    if( argc >= 2 &&
        ( std::string( argv[1] ) == std::string("--help") || std::string( argv[1] ) == std::string("-h") ) )
      {
      return EXIT_SUCCESS;
      }
    return EXIT_FAILURE;
    }

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

  const unsigned int ImageDimension = 2;

  typedef float PixelType;

  typedef itk::Image<PixelType, ImageDimension> ImageType;

  typedef itk::MattesMutualInformationImageToImageMetricv4<ImageType, ImageType, ImageType> MIMetricType;
  typedef itk::ANTSNeighborhoodCorrelationImageToImageMetricv4<ImageType, ImageType, ImageType> CCMetricType;

  CCMetricType::RadiusType ccRadius;
  ccRadius.Fill( 4 );

  unsigned int metricType = 0;
  if( strcmp( argv[2], "CC" ) == 0 )
    {
    metricType = 1;
    }
  else if( strcmp( argv[2], "MI" ) == 0 )
    {
    metricType = 2;
    }
  else
    {
    std::cerr << "Unrecognized metric " << argv[2] << std::endl;
    return EXIT_FAILURE;
    }

  // read in test image

  ImageType::Pointer testImage = ImageType::New();
  ReadImage<ImageType>( testImage, argv[1] );

  // read in training image file names

  std::vector<std::string> trainingImageFileNames;
  for( int n = 7; n < argc; n++ )
    {
    trainingImageFileNames.push_back( std::string( argv[n] ) );
    }

//   // Get scale parameters

  std::vector<float> scaleParameters = ConvertVector<float>( std::string( argv[3] ) );
  if( scaleParameters.size() != 3 )
    {
    std::cerr << "The scale parameters were improperly specified.  See usage." << std::endl;
    return EXIT_FAILURE;
    }
  float scaleLowerBoundLog = vcl_log( scaleParameters[0] );
  float scaleUpperBoundLog = vcl_log( scaleParameters[1] );
  unsigned int scaleNumberOfSamples = static_cast<unsigned int>( scaleParameters[2] );
  float scaleDelta = ( scaleUpperBoundLog - scaleLowerBoundLog ) / static_cast<float>( scaleNumberOfSamples - 1 );

//   // Get rotation sampling resolution

  unsigned int rotationNumberOfSamples = static_cast<unsigned int>( atoi( argv[4] ) );
  float rotationDelta = ( 2.0 * vnl_math::pi - 0.0 ) / static_cast<float>( rotationNumberOfSamples - 1 );

//   // Now go through the rotations + scalings to find the optimal pose.

  typedef itk::AffineTransform<double, ImageDimension> AffineTransformType;

  float optimalMetricValue = itk::NumericTraits<float>::max();
  AffineTransformType::Pointer optimalTransform = ITK_NULLPTR;
  unsigned int optimalMetricIndex = 0;

  for( unsigned int n = 0; n < trainingImageFileNames.size(); n++ )
    {
    ImageType::Pointer trainingImage = ImageType::New();
    ReadImage<ImageType>( trainingImage, trainingImageFileNames[n].c_str() );

    // Initialize centered transform (based on the center of the image)

    AffineTransformType::Pointer initialTransform = AffineTransformType::New();

    typedef itk::CenteredTransformInitializer<AffineTransformType, ImageType, ImageType> TransformInitializerType;
    TransformInitializerType::Pointer initializer = TransformInitializerType::New();
    initializer->SetTransform( initialTransform );
    initializer->SetFixedImage( trainingImage );
    initializer->SetMovingImage( testImage );
    initializer->GeometryOn();

    initializer->InitializeTransform();

    for( float angle = 0.0; angle <= 2.0 * vnl_math::pi; angle += rotationDelta )
      {
      AffineTransformType::MatrixType rotationMatrix;
      rotationMatrix( 0, 0 ) = rotationMatrix( 1, 1 ) = vcl_cos( angle );
      rotationMatrix( 1, 0 ) = vcl_sin( angle );
      rotationMatrix( 0, 1 ) = -rotationMatrix( 1, 0 );

      for( float scaleLog = scaleLowerBoundLog; scaleLog <= scaleUpperBoundLog; scaleLog += scaleDelta )
        {
        float scale = vcl_exp( scaleLog );

        AffineTransformType::Pointer affineTransform = AffineTransformType::New();
        affineTransform->SetCenter( initialTransform->GetCenter() );
        affineTransform->SetTranslation( initialTransform->GetTranslation() );
        affineTransform->SetMatrix( initialTransform->GetMatrix() * rotationMatrix * scale );

//         typedef itk::ResampleImageFilter<ImageType, ImageType, double> ResamplerType;
//         ResamplerType::Pointer resampleFilter = ResamplerType::New();
//         resampleFilter->SetInput( testImage );
//         resampleFilter->SetOutputParametersFromImage( trainingImage );
//         resampleFilter->SetTransform( affineTransform );
//         resampleFilter->SetDefaultPixelValue( 255 );
//         resampleFilter->Update();
//         WriteImage<ImageType>( resampleFilter->GetOutput(), "test.nii.gz" );

        float metricValue = 0;

        if( metricType == 1 )
          {
          CCMetricType::Pointer metric = CCMetricType::New();
          metric->SetFixedImage( trainingImage );
          metric->SetMovingImage( testImage );
          metric->SetRadius( ccRadius );
          metric->SetMovingTransform( affineTransform );
          metric->SetVirtualDomainFromImage( trainingImage );
          metric->Initialize();

          try
            {
            metricValue = metric->GetValue();
            }
          catch(...)
            {
            continue;
            }
          }
        else if( metricType == 2 )
          {
          MIMetricType::Pointer metric = MIMetricType::New();
          metric->SetFixedImage( trainingImage );
          metric->SetMovingImage( testImage );
          metric->SetNumberOfHistogramBins( 32 );
          metric->SetMovingTransform( affineTransform );
          metric->SetVirtualDomainFromImage( trainingImage );
          metric->Initialize();

          try
            {
            metricValue = metric->GetValue();
            }
          catch(...)
            {
            continue;
            }
          }
        if( metricValue < optimalMetricValue )
          {
          optimalMetricValue = metricValue;
          optimalTransform = affineTransform;
          optimalMetricIndex = n;
          }
        }
      }
    }

  if( strcmp( argv[6], "none" ) != 0 )
    {
    typedef itk::TransformFileWriter TransformWriterType;
    TransformWriterType::Pointer transformWriter = TransformWriterType::New();
    transformWriter->SetInput( optimalTransform );
    transformWriter->SetFileName( argv[6] );
    transformWriter->Update();
    }

  if( static_cast<bool>( atoi( argv[5] ) ) )
    {
    std::cout << trainingImageFileNames[optimalMetricIndex] << std::endl;
    }
  std::cout << optimalMetricValue << std::endl;

  return EXIT_SUCCESS;
}

} // namespace ants
<|endoftext|>


<commit_before>
#include "huffman_tables.hpp"

huffman_table::huffman_table(std::istream &stream)
{
	stream.read(reinterpret_cast<char *>(symbols_per_size), MAX_WORD_SIZE);

	unsigned int all_symbol_amount = 0;
	for (uint_fast8_t index = 0; index < MAX_WORD_SIZE; index++)
	{
		all_symbol_amount += symbols_per_size[index];
	}

	unsigned char *all_symbols = new unsigned char[all_symbol_amount];
	stream.read(reinterpret_cast<char *>(all_symbols), all_symbol_amount);

	symbols = all_symbols;
	_symbol_amount = all_symbol_amount;
}

huffman_table::~huffman_table()
{
	delete[] symbols;
}

huffman_table::symbol_count_t huffman_table::symbol_amount() const
{
	return _symbol_amount;
}

uint_fast16_t huffman_table::expected_byte_size() const
{
	return _symbol_amount + MAX_WORD_SIZE + 3;
}

huffman_table::symbol_entry_t huffman_table::start_entry_for_size(const unsigned int size) const
{
	symbol_entry_t entry = 0;
	for (unsigned int size_index = 1; size_index < size; size_index++)
	{
		const unsigned int symbols = symbols_per_size[size_index - 1];
		entry += symbols * (1 << (MAX_WORD_SIZE - size_index));
	}

	return entry;
}

bool huffman_table::find_symbol(const symbol_entry_t &entry, const unsigned int size, symbol_value_t &symbol) const
{
	const symbol_entry_t start_for_this_size = start_entry_for_size(size);
	const symbol_entry_t start_for_next_size = start_entry_for_size(size + 1);

	if (start_for_this_size > entry || start_for_next_size <= entry)
	{
		return false;
	}

	const symbols_per_size_t relative = (entry - start_for_this_size) >> (MAX_WORD_SIZE - size);
	symbol_index_t index = relative;
	for (unsigned int i = 1; i < size; i++)
	{
		index += symbols_per_size[i - 1];
	}

	symbol = symbols[index];
	return true;
}

huffman_table::symbol_value_t huffman_table::next_symbol(scan_bit_stream &bit_stream) const throw(std::invalid_argument)
{
	unsigned int size = 0;
	symbol_entry_t entry = 0;
	while (++size < MAX_WORD_SIZE)
	{
		entry |= ((unsigned int) bit_stream.next_bit()) << (MAX_WORD_SIZE - size);
		symbol_value_t symbol;
		if (find_symbol(entry, size, symbol))
		{
			return symbol;
		}
	}

	throw std::invalid_argument("Symbol not found in huffman table");
}

<commit_msg>Fixed bug in huffman tables<commit_after>
#include "huffman_tables.hpp"

huffman_table::huffman_table(std::istream &stream)
{
	stream.read(reinterpret_cast<char *>(symbols_per_size), MAX_WORD_SIZE);

	unsigned int all_symbol_amount = 0;
	for (uint_fast8_t index = 0; index < MAX_WORD_SIZE; index++)
	{
		all_symbol_amount += symbols_per_size[index];
	}

	unsigned char *all_symbols = new unsigned char[all_symbol_amount];
	stream.read(reinterpret_cast<char *>(all_symbols), all_symbol_amount);

	symbols = all_symbols;
	_symbol_amount = all_symbol_amount;
}

huffman_table::~huffman_table()
{
	delete[] symbols;
}

huffman_table::symbol_count_t huffman_table::symbol_amount() const
{
	return _symbol_amount;
}

uint_fast16_t huffman_table::expected_byte_size() const
{
	return _symbol_amount + MAX_WORD_SIZE + 3;
}

huffman_table::symbol_entry_t huffman_table::start_entry_for_size(const unsigned int size) const
{
	symbol_entry_t entry = 0;
	for (unsigned int size_index = 1; size_index < size; size_index++)
	{
		const unsigned int symbols = symbols_per_size[size_index - 1];
		entry += symbols * (1 << (MAX_WORD_SIZE - size_index));
	}

	return entry;
}

bool huffman_table::find_symbol(const symbol_entry_t &entry, const unsigned int size, symbol_value_t &symbol) const
{
	const symbol_entry_t start_for_this_size = start_entry_for_size(size);
	const symbol_entry_t start_for_next_size = start_entry_for_size(size + 1);

	if (start_for_this_size > entry || start_for_next_size <= entry)
	{
		return false;
	}

	const symbols_per_size_t relative = (entry - start_for_this_size) >> (MAX_WORD_SIZE - size);
	symbol_index_t index = relative;
	for (unsigned int i = 1; i < size; i++)
	{
		index += symbols_per_size[i - 1];
	}

	symbol = symbols[index];
	return true;
}

huffman_table::symbol_value_t huffman_table::next_symbol(scan_bit_stream &bit_stream) const throw(std::invalid_argument)
{
	unsigned int size = 0;
	symbol_entry_t entry = 0;
	while (++size <= MAX_WORD_SIZE)
	{
		entry |= ((unsigned int) bit_stream.next_bit()) << (MAX_WORD_SIZE - size);
		symbol_value_t symbol;
		if (find_symbol(entry, size, symbol))
		{
			return symbol;
		}
	}

	throw std::invalid_argument("Symbol not found in huffman table");
}

<|endoftext|>


<commit_before>#include "ev3api.h"
#include "app.h"
#include "SerialSendTask.h"
#include <string.h>
#include <syssvc/serial.h>
#include <ColorSensor.h>
#include <Port.h>
#include <Motor.h>
#include <TouchSensor.h>
#include <SonarSensor.h>
#include <GyroSensor.h>

using ev3api::Motor;
using ev3api::TouchSensor;
using ev3api::SonarSensor;
using ev3api::GyroSensor;
using ev3api::ColorSensor;

void serial_send_task(intptr_t exinf)
{

	//ポート割り当て
	static const ePortM front_motor_port = PORT_A;
	static const ePortM right_motor_port = PORT_B;
	static const ePortM left_motor_port = PORT_C;
	static const ePortM back_motor_port = PORT_D;
	static const bool front_motor_brake_mode = false;
	static const bool right_motor_brake_mode = false;
	static const bool left_motor_brake_mode = false;
	static const bool back_motor_brake_mode = false;
	static const motor_type_t front_motor_type = LARGE_MOTOR;
	static const motor_type_t right_motor_type = LARGE_MOTOR;
	static const motor_type_t left_motor_type = LARGE_MOTOR;
	static const motor_type_t back_motor_type = MEDIUM_MOTOR;
	static const ePortS touch_sensor_port = PORT_1;
	static const ePortS sonar_sensor_port = PORT_2;
	static const ePortS color_sensor_port = PORT_3;
	static const ePortS gyro_sensor_port = PORT_4;

	//インスタンス生成
	Motor* front_motor = new Motor(front_motor_port, front_motor_brake_mode, front_motor_type);
	Motor* right_motor = new Motor(right_motor_port, right_motor_brake_mode, right_motor_type);
	Motor* left_motor = new Motor(left_motor_port, left_motor_brake_mode, left_motor_type);
	Motor* back_motor = new Motor(back_motor_port, back_motor_brake_mode, back_motor_type);
	TouchSensor* touch_sensor = new TouchSensor(touch_sensor_port);
	SonarSensor* sonar_sensor = new SonarSensor(sonar_sensor_port);
	ColorSensor* color_sensor = new ColorSensor(color_sensor_port);
	GyroSensor *gyro_sensor = new GyroSensor(gyro_sensor_port);

	while(true)
	{
		if (!ev3_bluetooth_is_connected())
			continue;

		//ヘッダの作成
		Header header;
		header.Head = HEADER_HEAD_VALUE;
		header.Size = INPUT_SIGNAL_DATA_BYTE_SIZE;
		header.Command = COMMAND_INPUT_SIGNAL_DATA;

		//入力電文構造体にAPIの取得値を代入
		InputSignalData input_signal_data;
		input_signal_data.FrontMotorAngle = front_motor->getCount();
		front_motor->setCount(0);
		input_signal_data.RightMotorAngle = right_motor->getCount();
		right_motor->setCount(0);
		input_signal_data.LeftMotorAngle = left_motor->getCount();
		left_motor->setCount(0);
		input_signal_data.BackMotorAngle = back_motor->getCount();
		back_motor->setCount(0);

		input_signal_data.TouchSensor = touch_sensor->isPressed();
		input_signal_data.SonarDistance = sonar_sensor->getDistance();
		rgb_raw_t rgb;
		color_sensor->getRawColor(rgb);
		input_signal_data.ColorRed = rgb.r;
		input_signal_data.ColorGreen = rgb.g;
		input_signal_data.ColorBlue = rgb.b;
	//	input_signal_data.AmbientLight = color_sensor->getAmbient();
	//	input_signal_data.ReflectLight = color_sensor->getBrightness();
		input_signal_data.Angle = gyro_sensor->getAngle();
		input_signal_data.AnglarSpeed = gyro_sensor->getAnglerVelocity();
		input_signal_data.reserved1 = 0;
		input_signal_data.reserved2 = 0;
		input_signal_data.BatteryCurrent = ev3_battery_current_mA();
		input_signal_data.BatteryVoltage = ev3_battery_voltage_mV();

		//出力電文構造体と同サイズの出力電文バッファに出力電文をコピー
		uint8_t buff_input_signal[sizeof(InputSignalData)];
		memcpy(buff_input_signal, &input_signal_data, sizeof(InputSignalData));

		//出力電文バッファのチェックサムを計算
		uint8_t checksum = 0;
		for(uint8_t elm : buff_input_signal){
			checksum += elm;
		}

		//ヘッダ・出力電文バッファ・チェックサムを送信バッファにコピー
		char buff_send[sizeof(Header)+sizeof(InputSignalData)+sizeof(uint8_t)];
		memcpy(buff_send, &header, sizeof(Header));
		memcpy(buff_send+sizeof(Header), &input_signal_data, sizeof(InputSignalData));
		memcpy(buff_send+sizeof(Header)+sizeof(InputSignalData), &checksum, sizeof(checksum));

		//送信バッファを送信
		serial_wri_dat(SIO_PORT_BT, buff_send, sizeof(buff_send));
		tslp_tsk(100);
	}
}<commit_msg>ジャイロセンサのリセットを追加<commit_after>#include "ev3api.h"
#include "app.h"
#include "SerialSendTask.h"
#include <string.h>
#include <syssvc/serial.h>
#include <ColorSensor.h>
#include <Port.h>
#include <Motor.h>
#include <TouchSensor.h>
#include <SonarSensor.h>
#include <GyroSensor.h>

using ev3api::Motor;
using ev3api::TouchSensor;
using ev3api::SonarSensor;
using ev3api::GyroSensor;
using ev3api::ColorSensor;

void serial_send_task(intptr_t exinf)
{

	//ポート割り当て
	static const ePortM front_motor_port = PORT_A;
	static const ePortM right_motor_port = PORT_B;
	static const ePortM left_motor_port = PORT_C;
	static const ePortM back_motor_port = PORT_D;
	static const bool front_motor_brake_mode = false;
	static const bool right_motor_brake_mode = false;
	static const bool left_motor_brake_mode = false;
	static const bool back_motor_brake_mode = false;
	static const motor_type_t front_motor_type = LARGE_MOTOR;
	static const motor_type_t right_motor_type = LARGE_MOTOR;
	static const motor_type_t left_motor_type = LARGE_MOTOR;
	static const motor_type_t back_motor_type = MEDIUM_MOTOR;
	static const ePortS touch_sensor_port = PORT_1;
	static const ePortS sonar_sensor_port = PORT_2;
	static const ePortS color_sensor_port = PORT_3;
	static const ePortS gyro_sensor_port = PORT_4;

	//インスタンス生成
	Motor* front_motor = new Motor(front_motor_port, front_motor_brake_mode, front_motor_type);
	Motor* right_motor = new Motor(right_motor_port, right_motor_brake_mode, right_motor_type);
	Motor* left_motor = new Motor(left_motor_port, left_motor_brake_mode, left_motor_type);
	Motor* back_motor = new Motor(back_motor_port, back_motor_brake_mode, back_motor_type);
	TouchSensor* touch_sensor = new TouchSensor(touch_sensor_port);
	SonarSensor* sonar_sensor = new SonarSensor(sonar_sensor_port);
	ColorSensor* color_sensor = new ColorSensor(color_sensor_port);
	GyroSensor *gyro_sensor = new GyroSensor(gyro_sensor_port);

	gyro_sensor->reset();

	while(true)
	{
		if (!ev3_bluetooth_is_connected())
			continue;

		//ヘッダの作成
		Header header;
		header.Head = HEADER_HEAD_VALUE;
		header.Size = INPUT_SIGNAL_DATA_BYTE_SIZE;
		header.Command = COMMAND_INPUT_SIGNAL_DATA;

		//入力電文構造体にAPIの取得値を代入
		InputSignalData input_signal_data;
		input_signal_data.FrontMotorAngle = front_motor->getCount();
		front_motor->setCount(0);
		input_signal_data.RightMotorAngle = right_motor->getCount();
		right_motor->setCount(0);
		input_signal_data.LeftMotorAngle = left_motor->getCount();
		left_motor->setCount(0);
		input_signal_data.BackMotorAngle = back_motor->getCount();
		back_motor->setCount(0);

		input_signal_data.TouchSensor = touch_sensor->isPressed();
		input_signal_data.SonarDistance = sonar_sensor->getDistance();
		rgb_raw_t rgb;
		color_sensor->getRawColor(rgb);
		input_signal_data.ColorRed = rgb.r;
		input_signal_data.ColorGreen = rgb.g;
		input_signal_data.ColorBlue = rgb.b;
	//	input_signal_data.AmbientLight = color_sensor->getAmbient();
	//	input_signal_data.ReflectLight = color_sensor->getBrightness();
		input_signal_data.Angle = gyro_sensor->getAngle();
		input_signal_data.AnglarSpeed = gyro_sensor->getAnglerVelocity();
		input_signal_data.reserved1 = 0;
		input_signal_data.reserved2 = 0;
		input_signal_data.BatteryCurrent = ev3_battery_current_mA();
		input_signal_data.BatteryVoltage = ev3_battery_voltage_mV();

		//出力電文構造体と同サイズの出力電文バッファに出力電文をコピー
		uint8_t buff_input_signal[sizeof(InputSignalData)];
		memcpy(buff_input_signal, &input_signal_data, sizeof(InputSignalData));

		//出力電文バッファのチェックサムを計算
		uint8_t checksum = 0;
		for(uint8_t elm : buff_input_signal){
			checksum += elm;
		}

		//ヘッダ・出力電文バッファ・チェックサムを送信バッファにコピー
		char buff_send[sizeof(Header)+sizeof(InputSignalData)+sizeof(uint8_t)];
		memcpy(buff_send, &header, sizeof(Header));
		memcpy(buff_send+sizeof(Header), &input_signal_data, sizeof(InputSignalData));
		memcpy(buff_send+sizeof(Header)+sizeof(InputSignalData), &checksum, sizeof(checksum));

		//送信バッファを送信
		serial_wri_dat(SIO_PORT_BT, buff_send, sizeof(buff_send));
		tslp_tsk(100);
	}
}<|endoftext|>


<commit_before>#include "xchainer/cuda/cuda_backend.h"

#include <cuda_runtime.h>
#include <gtest/gtest.h>

#include "xchainer/array.h"
#include "xchainer/context.h"
#include "xchainer/cuda/cuda_runtime.h"
#include "xchainer/device.h"
#include "xchainer/indexable_array.h"
#include "xchainer/indexer.h"
#include "xchainer/native_backend.h"

namespace xchainer {
namespace cuda {
namespace {

template <typename T>
void ExpectDataEqual(const std::shared_ptr<void>& expected, const std::shared_ptr<void>& actual, size_t size) {
    auto expected_raw_ptr = static_cast<const T*>(expected.get());
    auto actual_raw_ptr = static_cast<const T*>(actual.get());
    for (size_t i = 0; i < size; ++i) {
        EXPECT_EQ(expected_raw_ptr[i], actual_raw_ptr[i]);
    }
}

void ExpectArraysEqual(const Array& expected, const Array& actual) {
    EXPECT_EQ(expected.dtype(), actual.dtype());
    EXPECT_EQ(expected.shape(), actual.shape());

    VisitDtype(expected.dtype(), [&expected, &actual](auto pt) {
        using T = typename decltype(pt)::type;
        IndexableArray<const T> expected_iarray{expected};
        IndexableArray<const T> actual_iarray{actual};
        Indexer<> indexer{expected.shape()};

        actual.device().Synchronize();
        expected.device().Synchronize();

        for (int64_t i = 0; i < indexer.total_size(); ++i) {
            indexer.Set(i);
            EXPECT_EQ(expected_iarray[indexer], actual_iarray[indexer]);
        }
    });
}

TEST(CudaBackendTest, GetDeviceCount) {
    Context ctx;
    int count = 0;
    CheckError(cudaGetDeviceCount(&count));
    EXPECT_EQ(count, CudaBackend(ctx).GetDeviceCount());
}

TEST(CudaBackendTest, GetDevice) {
    Context ctx;
    CudaBackend backend{ctx};
    {
        Device& device = backend.GetDevice(0);
        EXPECT_EQ(&backend, &device.backend());
        EXPECT_EQ(0, device.index());
    }
    {
        Device& device3 = backend.GetDevice(3);
        Device& device2 = backend.GetDevice(2);
        EXPECT_EQ(&backend, &device3.backend());
        EXPECT_EQ(3, device3.index());
        EXPECT_EQ(&backend, &device2.backend());
        EXPECT_EQ(2, device2.index());
    }
    {
        EXPECT_THROW(backend.GetDevice(-1), std::out_of_range);
        EXPECT_THROW(backend.GetDevice(backend.GetDeviceCount() + 1), std::out_of_range);
    }
}

TEST(CudaBackendTest, GetName) {
    Context ctx;
    EXPECT_EQ("cuda", CudaBackend(ctx).GetName());
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentContexts) {
    Context ctx0;
    Context ctx1;
    CudaBackend backend0{ctx0};
    CudaBackend backend1{ctx1};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferNativeBackends) {
    Context ctx;
    CudaBackend cuda_backend{ctx};
    NativeBackend native_backend0{ctx};
    NativeBackend native_backend1{ctx};
    Device& device0 = native_backend0.GetDevice(0);
    Device& device1 = native_backend1.GetDevice(0);
    EXPECT_FALSE(cuda_backend.SupportsTransfer(device0, device1));
}

template <int N>
class DerivedCudaBackend : public CudaBackend {
public:
    using CudaBackend::CudaBackend;
    std::string GetName() const override { return "derived" + std::to_string(N); }
};

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentCudaBackends) {
    Context ctx;
    DerivedCudaBackend<0> backend0{ctx};
    DerivedCudaBackend<1> backend1{ctx};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

// Data transfer test
class CudaBackendTransferTest : public ::testing::TestWithParam<::testing::tuple<std::string, std::string>> {};

INSTANTIATE_TEST_CASE_P(
        Devices,
        CudaBackendTransferTest,
        ::testing::Values(
                std::make_tuple("cuda:0", "cuda:0"),   // cuda:0 <-> cuda:0
                std::make_tuple("cuda:0", "cuda:1"),   // cuda:0 <-> cuda:1
                std::make_tuple("cuda:0", "native:0")  // cuda:0 <-> native:0
                ));

TEST_P(CudaBackendTransferTest, SupportsTransfer) {
    Context ctx;
    Backend& backend = ctx.GetBackend("cuda");
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));
    EXPECT_TRUE(backend.SupportsTransfer(device0, device1));
}

TEST_P(CudaBackendTransferTest, MemoryCopyFrom) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](const float* ptr) {
        (void)ptr;  // unused
    });

    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device1.FromBuffer(src_orig, bytesize);
    std::shared_ptr<void> dst = device0.Allocate(bytesize);
    device0.MemoryCopyFrom(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyTo) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](const float* ptr) {
        (void)ptr;  // unused
    });

    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device0.FromBuffer(src_orig, bytesize);
    std::shared_ptr<void> dst = device1.Allocate(bytesize);
    device0.MemoryCopyTo(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, TransferDataFrom) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device1.Allocate(bytesize);

    // Transfer
    // TODO(niboshi): Offset is fixed to 0
    std::tuple<std::shared_ptr<void>, size_t> tuple = device0.TransferDataFrom(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), std::get<0>(tuple).get(), bytesize));
    // TODO(niboshi): Test offset

    // Destination is ALWAYS CUDA device
    cudaPointerAttributes attr = {};
    CheckError(cudaPointerGetAttributes(&attr, std::get<0>(tuple).get()));
    EXPECT_TRUE(attr.isManaged);
    EXPECT_EQ(device0.index(), attr.device);
}

TEST_P(CudaBackendTransferTest, TransferDataTo) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device0.Allocate(bytesize);

    // Transfer
    // TODO(niboshi): Offset is fixed to 0
    std::tuple<std::shared_ptr<void>, size_t> tuple = device0.TransferDataTo(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), std::get<0>(tuple).get(), bytesize));
    // TODO(niboshi): Test offset

    if (nullptr != dynamic_cast<CudaBackend*>(&device1.backend())) {
        // Destination is CUDA device
        cudaPointerAttributes attr = {};
        CheckError(cudaPointerGetAttributes(&attr, std::get<0>(tuple).get()));
        EXPECT_TRUE(attr.isManaged);
        EXPECT_EQ(device1.index(), attr.device);
    } else {
        // Destination is native device
        EXPECT_FALSE(IsPointerCudaMemory(std::get<0>(tuple).get()));
    }
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceFrom) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = Array::FromBuffer({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device1);

    // Transfer
    Array b = a.ToDevice(device0);

    EXPECT_EQ(&b.device(), &device0);
    EXPECT_EQ(&a.device(), &device1);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same native device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get())
                << "Array::ToDevice() must not return alias when transferring to different native device.";
    }
    ExpectArraysEqual(a, b);
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceTo) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = Array::FromBuffer({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device0);

    // Transfer
    Array b = a.ToDevice(device1);

    EXPECT_EQ(&b.device(), &device1);
    EXPECT_EQ(&a.device(), &device0);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same CUDA device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get()) << "Array::ToDevice() must not return alias when transferring to a different device.";
    }
    ExpectArraysEqual(a, b);
}

}  // namespace
}  // namespace cuda
}  // namespace xchainer
<commit_msg>xchainer/cuda/cuda_backend_test.cc:205:  Add #include <tuple> for tuple<>  [build/include_what_you_use] [4]<commit_after>#include "xchainer/cuda/cuda_backend.h"

#include <tuple>

#include <cuda_runtime.h>
#include <gtest/gtest.h>

#include "xchainer/array.h"
#include "xchainer/context.h"
#include "xchainer/cuda/cuda_runtime.h"
#include "xchainer/device.h"
#include "xchainer/indexable_array.h"
#include "xchainer/indexer.h"
#include "xchainer/native_backend.h"

namespace xchainer {
namespace cuda {
namespace {

template <typename T>
void ExpectDataEqual(const std::shared_ptr<void>& expected, const std::shared_ptr<void>& actual, size_t size) {
    auto expected_raw_ptr = static_cast<const T*>(expected.get());
    auto actual_raw_ptr = static_cast<const T*>(actual.get());
    for (size_t i = 0; i < size; ++i) {
        EXPECT_EQ(expected_raw_ptr[i], actual_raw_ptr[i]);
    }
}

void ExpectArraysEqual(const Array& expected, const Array& actual) {
    EXPECT_EQ(expected.dtype(), actual.dtype());
    EXPECT_EQ(expected.shape(), actual.shape());

    VisitDtype(expected.dtype(), [&expected, &actual](auto pt) {
        using T = typename decltype(pt)::type;
        IndexableArray<const T> expected_iarray{expected};
        IndexableArray<const T> actual_iarray{actual};
        Indexer<> indexer{expected.shape()};

        actual.device().Synchronize();
        expected.device().Synchronize();

        for (int64_t i = 0; i < indexer.total_size(); ++i) {
            indexer.Set(i);
            EXPECT_EQ(expected_iarray[indexer], actual_iarray[indexer]);
        }
    });
}

TEST(CudaBackendTest, GetDeviceCount) {
    Context ctx;
    int count = 0;
    CheckError(cudaGetDeviceCount(&count));
    EXPECT_EQ(count, CudaBackend(ctx).GetDeviceCount());
}

TEST(CudaBackendTest, GetDevice) {
    Context ctx;
    CudaBackend backend{ctx};
    {
        Device& device = backend.GetDevice(0);
        EXPECT_EQ(&backend, &device.backend());
        EXPECT_EQ(0, device.index());
    }
    {
        Device& device3 = backend.GetDevice(3);
        Device& device2 = backend.GetDevice(2);
        EXPECT_EQ(&backend, &device3.backend());
        EXPECT_EQ(3, device3.index());
        EXPECT_EQ(&backend, &device2.backend());
        EXPECT_EQ(2, device2.index());
    }
    {
        EXPECT_THROW(backend.GetDevice(-1), std::out_of_range);
        EXPECT_THROW(backend.GetDevice(backend.GetDeviceCount() + 1), std::out_of_range);
    }
}

TEST(CudaBackendTest, GetName) {
    Context ctx;
    EXPECT_EQ("cuda", CudaBackend(ctx).GetName());
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentContexts) {
    Context ctx0;
    Context ctx1;
    CudaBackend backend0{ctx0};
    CudaBackend backend1{ctx1};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferNativeBackends) {
    Context ctx;
    CudaBackend cuda_backend{ctx};
    NativeBackend native_backend0{ctx};
    NativeBackend native_backend1{ctx};
    Device& device0 = native_backend0.GetDevice(0);
    Device& device1 = native_backend1.GetDevice(0);
    EXPECT_FALSE(cuda_backend.SupportsTransfer(device0, device1));
}

template <int N>
class DerivedCudaBackend : public CudaBackend {
public:
    using CudaBackend::CudaBackend;
    std::string GetName() const override { return "derived" + std::to_string(N); }
};

TEST(CudaBackendIncompatibleTransferTest, SupportsTransferDifferentCudaBackends) {
    Context ctx;
    DerivedCudaBackend<0> backend0{ctx};
    DerivedCudaBackend<1> backend1{ctx};
    Device& device0 = backend0.GetDevice(0);
    Device& device1 = backend1.GetDevice(0);
    EXPECT_FALSE(backend0.SupportsTransfer(device0, device1));
}

// Data transfer test
class CudaBackendTransferTest : public ::testing::TestWithParam<::testing::tuple<std::string, std::string>> {};

INSTANTIATE_TEST_CASE_P(
        Devices,
        CudaBackendTransferTest,
        ::testing::Values(
                std::make_tuple("cuda:0", "cuda:0"),   // cuda:0 <-> cuda:0
                std::make_tuple("cuda:0", "cuda:1"),   // cuda:0 <-> cuda:1
                std::make_tuple("cuda:0", "native:0")  // cuda:0 <-> native:0
                ));

TEST_P(CudaBackendTransferTest, SupportsTransfer) {
    Context ctx;
    Backend& backend = ctx.GetBackend("cuda");
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));
    EXPECT_TRUE(backend.SupportsTransfer(device0, device1));
}

TEST_P(CudaBackendTransferTest, MemoryCopyFrom) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](const float* ptr) {
        (void)ptr;  // unused
    });

    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device1.FromBuffer(src_orig, bytesize);
    std::shared_ptr<void> dst = device0.Allocate(bytesize);
    device0.MemoryCopyFrom(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, MemoryCopyTo) {
    size_t size = 3;
    size_t bytesize = size * sizeof(float);
    float raw_data[] = {0, 1, 2};
    std::shared_ptr<void> src_orig(raw_data, [](const float* ptr) {
        (void)ptr;  // unused
    });

    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    std::shared_ptr<void> src = device0.FromBuffer(src_orig, bytesize);
    std::shared_ptr<void> dst = device1.Allocate(bytesize);
    device0.MemoryCopyTo(dst.get(), src.get(), bytesize, device1);
    ExpectDataEqual<float>(src, dst, size);
}

TEST_P(CudaBackendTransferTest, TransferDataFrom) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device1.Allocate(bytesize);

    // Transfer
    // TODO(niboshi): Offset is fixed to 0
    std::tuple<std::shared_ptr<void>, size_t> tuple = device0.TransferDataFrom(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), std::get<0>(tuple).get(), bytesize));
    // TODO(niboshi): Test offset

    // Destination is ALWAYS CUDA device
    cudaPointerAttributes attr = {};
    CheckError(cudaPointerGetAttributes(&attr, std::get<0>(tuple).get()));
    EXPECT_TRUE(attr.isManaged);
    EXPECT_EQ(device0.index(), attr.device);
}

TEST_P(CudaBackendTransferTest, TransferDataTo) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    size_t bytesize = 5;
    auto data = device0.Allocate(bytesize);

    // Transfer
    // TODO(niboshi): Offset is fixed to 0
    std::tuple<std::shared_ptr<void>, size_t> tuple = device0.TransferDataTo(device1, data, 0, bytesize);

    EXPECT_EQ(0, std::memcmp(data.get(), std::get<0>(tuple).get(), bytesize));
    // TODO(niboshi): Test offset

    if (nullptr != dynamic_cast<CudaBackend*>(&device1.backend())) {
        // Destination is CUDA device
        cudaPointerAttributes attr = {};
        CheckError(cudaPointerGetAttributes(&attr, std::get<0>(tuple).get()));
        EXPECT_TRUE(attr.isManaged);
        EXPECT_EQ(device1.index(), attr.device);
    } else {
        // Destination is native device
        EXPECT_FALSE(IsPointerCudaMemory(std::get<0>(tuple).get()));
    }
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceFrom) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = Array::FromBuffer({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device1);

    // Transfer
    Array b = a.ToDevice(device0);

    EXPECT_EQ(&b.device(), &device0);
    EXPECT_EQ(&a.device(), &device1);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same native device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get())
                << "Array::ToDevice() must not return alias when transferring to different native device.";
    }
    ExpectArraysEqual(a, b);
}

TEST_P(CudaBackendTransferTest, ArrayToDeviceTo) {
    Context ctx;
    Device& device0 = ctx.GetDevice(::testing::get<0>(GetParam()));
    Device& device1 = ctx.GetDevice(::testing::get<1>(GetParam()));

    // Allocate the source array
    float data[] = {1.0f, 2.0f};
    auto nop = [](void* p) {
        (void)p;  // unused
    };
    Array a = Array::FromBuffer({2, 1}, Dtype::kFloat32, std::shared_ptr<float>(data, nop), device0);

    // Transfer
    Array b = a.ToDevice(device1);

    EXPECT_EQ(&b.device(), &device1);
    EXPECT_EQ(&a.device(), &device0);
    if (&device0 == &device1) {
        EXPECT_EQ(a.data().get(), b.data().get()) << "Array::ToDevice() must return alias when transferring to the same CUDA device.";
    } else {
        EXPECT_NE(a.data().get(), b.data().get()) << "Array::ToDevice() must not return alias when transferring to a different device.";
    }
    ExpectArraysEqual(a, b);
}

}  // namespace
}  // namespace cuda
}  // namespace xchainer
<|endoftext|>


<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

CRITICAL_SECTION cs_file_access;
json_t* run_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
const DWORD PROJECT_VERSION(void)
{
	return 0x20170215;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
json_t* runconfig_get(void)
{
	return run_cfg;
}
void runconfig_set(json_t *new_run_cfg)
{
	json_decref(run_cfg);
	run_cfg = json_incref(new_run_cfg);
}

const json_t *runconfig_title_get(void)
{
	const json_t *id = json_object_get(run_cfg, "game");
	const json_t *title = strings_get(json_string_value(id));
	if(!title) {
		title = json_object_get(run_cfg, "title");
	}
	return title ? title : (id ? id : NULL);
}
<commit_msg>Update version number<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Globals, compile-time constants and runconfig abstractions.
  */

#include "thcrap.h"

CRITICAL_SECTION cs_file_access;
json_t* run_cfg = NULL;

const char* PROJECT_NAME(void)
{
	return "Touhou Community Reliant Automatic Patcher";
}
const char* PROJECT_NAME_SHORT(void)
{
	return "thcrap";
}
const DWORD PROJECT_VERSION(void)
{
	return 0x20170217;
}
const char* PROJECT_VERSION_STRING(void)
{
	static char ver_str[11] = {0};
	if(!ver_str[0]) {
		str_hexdate_format(ver_str, PROJECT_VERSION());
	}
	return ver_str;
}
json_t* runconfig_get(void)
{
	return run_cfg;
}
void runconfig_set(json_t *new_run_cfg)
{
	json_decref(run_cfg);
	run_cfg = json_incref(new_run_cfg);
}

const json_t *runconfig_title_get(void)
{
	const json_t *id = json_object_get(run_cfg, "game");
	const json_t *title = strings_get(json_string_value(id));
	if(!title) {
		title = json_object_get(run_cfg, "title");
	}
	return title ? title : (id ? id : NULL);
}
<|endoftext|>


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

#include "ppapi/proxy/ppb_file_chooser_proxy.h"

#include <queue>

#include "ppapi/c/dev/ppb_file_chooser_dev.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_proxy_private.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppb_file_ref_proxy.h"
#include "ppapi/proxy/serialized_var.h"

namespace pp {
namespace proxy {

class FileChooser : public PluginResource {
 public:
  FileChooser(const HostResource& resource);
  virtual ~FileChooser();

  virtual FileChooser* AsFileChooser();

  PP_CompletionCallback current_show_callback_;

  // All files returned by the current show callback that haven't yet been
  // given to the plugin. The plugin will repeatedly call us to get the next
  // file, and we'll vend those out of this queue, removing them when ownership
  // has transferred to the plugin.
  std::queue<PP_Resource> file_queue_;

 private:
  DISALLOW_COPY_AND_ASSIGN(FileChooser);
};

FileChooser::FileChooser(const HostResource& resource)
    : PluginResource(resource),
      current_show_callback_(PP_MakeCompletionCallback(NULL, NULL)) {
}

FileChooser::~FileChooser() {
  // Always need to fire completion callbacks to prevent a leak in the plugin.
  if (current_show_callback_.func) {
    // TODO(brettw) the callbacks at this level should be refactored with a
    // more automatic tracking system like we have in the renderer.
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(
        current_show_callback_.func, current_show_callback_.user_data,
        static_cast<int32_t>(PP_ERROR_ABORTED)));
  }

  // Any existing files we haven't transferred ownership to the plugin need
  // to be freed.
  PluginResourceTracker* tracker = PluginResourceTracker::GetInstance();
  while (!file_queue_.empty()) {
    tracker->ReleaseResource(file_queue_.front());
    file_queue_.pop();
  }
}

FileChooser* FileChooser::AsFileChooser() {
  return this;
}

namespace {

PP_Resource Create(PP_Instance instance,
                   const PP_FileChooserOptions_Dev* options) {
  Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
  if (!dispatcher)
    return 0;

  HostResource result;
  dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Create(
      INTERFACE_ID_PPB_FILE_CHOOSER, instance,
      options->mode, options->accept_mime_types, &result));

  if (result.is_null())
    return 0;
  linked_ptr<FileChooser> object(new FileChooser(result));
  return PluginResourceTracker::GetInstance()->AddResource(object);
}

PP_Bool IsFileChooser(PP_Resource resource) {
  FileChooser* object = PluginResource::GetAs<FileChooser>(resource);
  return BoolToPPBool(!!object);
}

int32_t Show(PP_Resource chooser, struct PP_CompletionCallback callback) {
  FileChooser* object = PluginResource::GetAs<FileChooser>(chooser);
  if (!object)
    return PP_ERROR_BADRESOURCE;
  Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance());
  if (!dispatcher)
    return PP_ERROR_BADARGUMENT;

  if (object->current_show_callback_.func)
    return PP_ERROR_INPROGRESS;  // Can't show more than once.

  object->current_show_callback_ = callback;
  dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Show(
      INTERFACE_ID_PPB_FILE_CHOOSER,
      object->host_resource()));
  return PP_ERROR_WOULDBLOCK;
}

PP_Resource GetNextChosenFile(PP_Resource chooser) {
  FileChooser* object = PluginResource::GetAs<FileChooser>(chooser);
  if (!object || object->file_queue_.empty())
    return 0;

  // Return the next resource in the queue. These resource have already been
  // addrefed (they're currently owned by the FileChooser) and returning them
  // transfers ownership of that reference to the plugin.
  PP_Resource next = object->file_queue_.front();
  object->file_queue_.pop();
  return next;
}

const PPB_FileChooser_Dev file_chooser_interface = {
  &Create,
  &IsFileChooser,
  &Show,
  &GetNextChosenFile
};

InterfaceProxy* CreateFileChooserProxy(Dispatcher* dispatcher,
                                       const void* target_interface) {
  return new PPB_FileChooser_Proxy(dispatcher, target_interface);
}

}  // namespace

PPB_FileChooser_Proxy::PPB_FileChooser_Proxy(Dispatcher* dispatcher,
                                             const void* target_interface)
    : InterfaceProxy(dispatcher, target_interface),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}

PPB_FileChooser_Proxy::~PPB_FileChooser_Proxy() {
}

const InterfaceProxy::Info* PPB_FileChooser_Proxy::GetInfo() {
  static const Info info = {
    &file_chooser_interface,
    PPB_FILECHOOSER_DEV_INTERFACE,
    INTERFACE_ID_PPB_FILE_CHOOSER,
    false,
    &CreateFileChooserProxy,
  };
  return &info;
}

bool PPB_FileChooser_Proxy::OnMessageReceived(const IPC::Message& msg) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PPB_FileChooser_Proxy, msg)
    // Plugin -> host messages.
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Create, OnMsgCreate)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Show, OnMsgShow)

    // Host -> plugin messages.
    IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileChooser_ChooseComplete,
                        OnMsgChooseComplete)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void PPB_FileChooser_Proxy::OnMsgCreate(PP_Instance instance,
                                        int mode,
                                        const std::string& accept_mime_types,
                                        HostResource* result) {
  PP_FileChooserOptions_Dev options;
  options.mode = static_cast<PP_FileChooserMode_Dev>(mode);
  options.accept_mime_types = accept_mime_types.c_str();
  result->SetHostResource(
      instance, ppb_file_chooser_target()->Create(instance, &options));
}

void PPB_FileChooser_Proxy::OnMsgShow(const HostResource& chooser) {
  CompletionCallback callback = callback_factory_.NewCallback(
      &PPB_FileChooser_Proxy::OnShowCallback, chooser);

  int32_t result = ppb_file_chooser_target()->Show(
      chooser.host_resource(), callback.pp_completion_callback());
  if (result != PP_ERROR_WOULDBLOCK)
    callback.Run(result);
}

void PPB_FileChooser_Proxy::OnMsgChooseComplete(
    const HostResource& chooser,
    int32_t result_code,
    const std::vector<PPBFileRef_CreateInfo>& chosen_files) {
  PP_Resource plugin_resource =
      PluginResourceTracker::GetInstance()->PluginResourceForHostResource(
          chooser);
  if (!plugin_resource)
    return;
  FileChooser* object = PluginResource::GetAs<FileChooser>(plugin_resource);
  if (!object)
    return;

  // Convert each of the passed in file infos to resources. These will be owned
  // by the FileChooser object until they're passed to the plugin.
  DCHECK(object->file_queue_.empty());
  for (size_t i = 0; i < chosen_files.size(); i++) {
    object->file_queue_.push(
        PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i]));
  }

  // Notify the plugin of the new data. We have to swap out the callback
  // because the plugin may trigger deleting the object from the callback, and
  // the FileChooser object will attempt to call the callback in its destructor
  // with the ABORTED status.
  PP_CompletionCallback callback = object->current_show_callback_;
  object->current_show_callback_ = PP_MakeCompletionCallback(NULL, NULL);
  PP_RunCompletionCallback(&callback, result_code);
  // DANGER: May delete |object|!
}

void PPB_FileChooser_Proxy::OnShowCallback(int32_t result,
                                           const HostResource& chooser) {
  std::vector<PPBFileRef_CreateInfo> files;
  if (result == PP_OK) {
    // Jump through some hoops to get the FileRef proxy. Since we know we're
    // in the host at this point, we can ask the host dispatcher for it.
    DCHECK(!dispatcher()->IsPlugin());
    HostDispatcher* host_disp = static_cast<HostDispatcher*>(dispatcher());
    PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>(
        host_disp->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_FILE_REF));

    // Convert the returned files to the serialized info.
    while (PP_Resource cur_file_resource =
               ppb_file_chooser_target()->GetNextChosenFile(
                   chooser.host_resource())) {
      PPBFileRef_CreateInfo cur_create_info;
      file_ref_proxy->SerializeFileRef(cur_file_resource, &cur_create_info);
      files.push_back(cur_create_info);
    }
  }

  dispatcher()->Send(new PpapiMsg_PPBFileChooser_ChooseComplete(
      INTERFACE_ID_PPB_FILE_CHOOSER, chooser, result, files));
}

}  // namespace proxy
}  // namespace pp
<commit_msg>The mime type list can be NULL to allow all files. Handle this case when converting to a std::string for serialization (the backend treats empty string the same as NULL). Review URL: http://codereview.chromium.org/6824045<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/ppb_file_chooser_proxy.h"

#include <queue>

#include "ppapi/c/dev/ppb_file_chooser_dev.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_proxy_private.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppb_file_ref_proxy.h"
#include "ppapi/proxy/serialized_var.h"

namespace pp {
namespace proxy {

class FileChooser : public PluginResource {
 public:
  FileChooser(const HostResource& resource);
  virtual ~FileChooser();

  virtual FileChooser* AsFileChooser();

  PP_CompletionCallback current_show_callback_;

  // All files returned by the current show callback that haven't yet been
  // given to the plugin. The plugin will repeatedly call us to get the next
  // file, and we'll vend those out of this queue, removing them when ownership
  // has transferred to the plugin.
  std::queue<PP_Resource> file_queue_;

 private:
  DISALLOW_COPY_AND_ASSIGN(FileChooser);
};

FileChooser::FileChooser(const HostResource& resource)
    : PluginResource(resource),
      current_show_callback_(PP_MakeCompletionCallback(NULL, NULL)) {
}

FileChooser::~FileChooser() {
  // Always need to fire completion callbacks to prevent a leak in the plugin.
  if (current_show_callback_.func) {
    // TODO(brettw) the callbacks at this level should be refactored with a
    // more automatic tracking system like we have in the renderer.
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(
        current_show_callback_.func, current_show_callback_.user_data,
        static_cast<int32_t>(PP_ERROR_ABORTED)));
  }

  // Any existing files we haven't transferred ownership to the plugin need
  // to be freed.
  PluginResourceTracker* tracker = PluginResourceTracker::GetInstance();
  while (!file_queue_.empty()) {
    tracker->ReleaseResource(file_queue_.front());
    file_queue_.pop();
  }
}

FileChooser* FileChooser::AsFileChooser() {
  return this;
}

namespace {

PP_Resource Create(PP_Instance instance,
                   const PP_FileChooserOptions_Dev* options) {
  Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
  if (!dispatcher)
    return 0;

  HostResource result;
  dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Create(
      INTERFACE_ID_PPB_FILE_CHOOSER, instance,
      options->mode,
      options->accept_mime_types ? options->accept_mime_types : std::string(),
      &result));

  if (result.is_null())
    return 0;
  linked_ptr<FileChooser> object(new FileChooser(result));
  return PluginResourceTracker::GetInstance()->AddResource(object);
}

PP_Bool IsFileChooser(PP_Resource resource) {
  FileChooser* object = PluginResource::GetAs<FileChooser>(resource);
  return BoolToPPBool(!!object);
}

int32_t Show(PP_Resource chooser, struct PP_CompletionCallback callback) {
  FileChooser* object = PluginResource::GetAs<FileChooser>(chooser);
  if (!object)
    return PP_ERROR_BADRESOURCE;
  Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance());
  if (!dispatcher)
    return PP_ERROR_BADARGUMENT;

  if (object->current_show_callback_.func)
    return PP_ERROR_INPROGRESS;  // Can't show more than once.

  object->current_show_callback_ = callback;
  dispatcher->Send(new PpapiHostMsg_PPBFileChooser_Show(
      INTERFACE_ID_PPB_FILE_CHOOSER,
      object->host_resource()));
  return PP_ERROR_WOULDBLOCK;
}

PP_Resource GetNextChosenFile(PP_Resource chooser) {
  FileChooser* object = PluginResource::GetAs<FileChooser>(chooser);
  if (!object || object->file_queue_.empty())
    return 0;

  // Return the next resource in the queue. These resource have already been
  // addrefed (they're currently owned by the FileChooser) and returning them
  // transfers ownership of that reference to the plugin.
  PP_Resource next = object->file_queue_.front();
  object->file_queue_.pop();
  return next;
}

const PPB_FileChooser_Dev file_chooser_interface = {
  &Create,
  &IsFileChooser,
  &Show,
  &GetNextChosenFile
};

InterfaceProxy* CreateFileChooserProxy(Dispatcher* dispatcher,
                                       const void* target_interface) {
  return new PPB_FileChooser_Proxy(dispatcher, target_interface);
}

}  // namespace

PPB_FileChooser_Proxy::PPB_FileChooser_Proxy(Dispatcher* dispatcher,
                                             const void* target_interface)
    : InterfaceProxy(dispatcher, target_interface),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}

PPB_FileChooser_Proxy::~PPB_FileChooser_Proxy() {
}

const InterfaceProxy::Info* PPB_FileChooser_Proxy::GetInfo() {
  static const Info info = {
    &file_chooser_interface,
    PPB_FILECHOOSER_DEV_INTERFACE,
    INTERFACE_ID_PPB_FILE_CHOOSER,
    false,
    &CreateFileChooserProxy,
  };
  return &info;
}

bool PPB_FileChooser_Proxy::OnMessageReceived(const IPC::Message& msg) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PPB_FileChooser_Proxy, msg)
    // Plugin -> host messages.
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Create, OnMsgCreate)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFileChooser_Show, OnMsgShow)

    // Host -> plugin messages.
    IPC_MESSAGE_HANDLER(PpapiMsg_PPBFileChooser_ChooseComplete,
                        OnMsgChooseComplete)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void PPB_FileChooser_Proxy::OnMsgCreate(PP_Instance instance,
                                        int mode,
                                        const std::string& accept_mime_types,
                                        HostResource* result) {
  PP_FileChooserOptions_Dev options;
  options.mode = static_cast<PP_FileChooserMode_Dev>(mode);
  options.accept_mime_types = accept_mime_types.c_str();
  result->SetHostResource(
      instance, ppb_file_chooser_target()->Create(instance, &options));
}

void PPB_FileChooser_Proxy::OnMsgShow(const HostResource& chooser) {
  CompletionCallback callback = callback_factory_.NewCallback(
      &PPB_FileChooser_Proxy::OnShowCallback, chooser);

  int32_t result = ppb_file_chooser_target()->Show(
      chooser.host_resource(), callback.pp_completion_callback());
  if (result != PP_ERROR_WOULDBLOCK)
    callback.Run(result);
}

void PPB_FileChooser_Proxy::OnMsgChooseComplete(
    const HostResource& chooser,
    int32_t result_code,
    const std::vector<PPBFileRef_CreateInfo>& chosen_files) {
  PP_Resource plugin_resource =
      PluginResourceTracker::GetInstance()->PluginResourceForHostResource(
          chooser);
  if (!plugin_resource)
    return;
  FileChooser* object = PluginResource::GetAs<FileChooser>(plugin_resource);
  if (!object)
    return;

  // Convert each of the passed in file infos to resources. These will be owned
  // by the FileChooser object until they're passed to the plugin.
  DCHECK(object->file_queue_.empty());
  for (size_t i = 0; i < chosen_files.size(); i++) {
    object->file_queue_.push(
        PPB_FileRef_Proxy::DeserializeFileRef(chosen_files[i]));
  }

  // Notify the plugin of the new data. We have to swap out the callback
  // because the plugin may trigger deleting the object from the callback, and
  // the FileChooser object will attempt to call the callback in its destructor
  // with the ABORTED status.
  PP_CompletionCallback callback = object->current_show_callback_;
  object->current_show_callback_ = PP_MakeCompletionCallback(NULL, NULL);
  PP_RunCompletionCallback(&callback, result_code);
  // DANGER: May delete |object|!
}

void PPB_FileChooser_Proxy::OnShowCallback(int32_t result,
                                           const HostResource& chooser) {
  std::vector<PPBFileRef_CreateInfo> files;
  if (result == PP_OK) {
    // Jump through some hoops to get the FileRef proxy. Since we know we're
    // in the host at this point, we can ask the host dispatcher for it.
    DCHECK(!dispatcher()->IsPlugin());
    HostDispatcher* host_disp = static_cast<HostDispatcher*>(dispatcher());
    PPB_FileRef_Proxy* file_ref_proxy = static_cast<PPB_FileRef_Proxy*>(
        host_disp->GetOrCreatePPBInterfaceProxy(INTERFACE_ID_PPB_FILE_REF));

    // Convert the returned files to the serialized info.
    while (PP_Resource cur_file_resource =
               ppb_file_chooser_target()->GetNextChosenFile(
                   chooser.host_resource())) {
      PPBFileRef_CreateInfo cur_create_info;
      file_ref_proxy->SerializeFileRef(cur_file_resource, &cur_create_info);
      files.push_back(cur_create_info);
    }
  }

  dispatcher()->Send(new PpapiMsg_PPBFileChooser_ChooseComplete(
      INTERFACE_ID_PPB_FILE_CHOOSER, chooser, result, files));
}

}  // namespace proxy
}  // namespace pp
<|endoftext|>