<commit_before>#include "fast++.hpp"

extern "C" {
    #include "tinyexpr.h"
}

double expr_step(double a) {
    return (a >= 0 ? 1.0 : 0.0);
}

double expr_min(double a, double b) {
    return std::min(a, b);
}

double expr_max(double a, double b) {
    return std::max(a, b);
}

bool gridder_t::tinyexpr_wrapper::compile(const std::string& sexpr, const vec1s& params) {
    uint_t nparam = params.size();
    uint_t nfunc = 3;

    vars_glue = new te_variable[nparam+nfunc];
    for (uint_t p : range(nparam+nfunc)) {
        vars_glue[p].context = nullptr;
    }

    vars.resize(nparam);

    // Time
    vars_glue[0].name = "t";
    vars_glue[0].address = &vars[0];
    vars_glue[0].type = TE_VARIABLE;

    // Custom parameters
    for (uint_t p : range(nparam)) {
        vars_glue[p].name = params[p].c_str();
        vars_glue[p].address = &vars[p];
        vars_glue[p].type = TE_VARIABLE;
    }

    // Custom functions
    vars_glue[nparam+0].name = "step";
    vars_glue[nparam+0].address = (void*)(&expr_step);
    vars_glue[nparam+0].type = TE_FUNCTION1 | TE_FLAG_PURE;
    vars_glue[nparam+1].name = "min";
    vars_glue[nparam+1].address = (void*)(&expr_min);
    vars_glue[nparam+1].type = TE_FUNCTION2 | TE_FLAG_PURE;
    vars_glue[nparam+2].name = "max";
    vars_glue[nparam+2].address = (void*)(&expr_max);
    vars_glue[nparam+2].type = TE_FUNCTION2 | TE_FLAG_PURE;

    // Compile expression
    int err = 0;
    expr = te_compile(sexpr.c_str(), vars_glue, nparam+nfunc, &err);
    if (err > 0) {
        std::string head = "could not parse SFH expression: ";
        error(head, sexpr);
        error(std::string(head.size()+err-1, ' ')+'^');
        return false;
    }

    return true;
}

double gridder_t::tinyexpr_wrapper::eval() {
    return te_eval(expr);
}

gridder_t::tinyexpr_wrapper::~tinyexpr_wrapper() {
    if (expr != nullptr) {
        te_free(expr);
        delete[] vars_glue;
    }
}

std::string gridder_t::get_library_file_ssp(uint_t im) const {
    return opts.library_dir+"ssp"+"."+opts.resolution+"/"+
        opts.library+"_"+opts.resolution+"_"+opts.name_imf+
        "_z"+replace(to_string(output.grid[grid_id::metal][im]), "0.", "");
}

void gridder_t::evaluate_sfh_custom(const vec1u& idm, const vec1d& t, vec1d& sfh) const {
    sfh_expr.vars[1] = output.grid[grid_id::age][idm[grid_id::age]];
    for (uint_t i : range(opts.custom_params)) {
        sfh_expr.vars[i+2] = output.grid[grid_id::custom+i][idm[grid_id::custom+i]];
    }

    sfh.resize(t.size());
    double nage = e10(output.grid[grid_id::age][idm[grid_id::age]]);
    for (uint_t i : range(t)) {
        sfh_expr.vars[0] = (opts.custom_sfh_lookback ? nage - t.safe[i] : t.safe[i]);
        sfh.safe[i] = sfh_expr.eval();
    }
}

bool gridder_t::build_and_send_custom(fitter_t& fitter) {
    model_id_pair m;
    m.model.flux.resize(input.lambda.size());
    m.model.props.resize(nprop);
    m.idm.resize(nparam);

    ssp_bc03 ssp;

    const vec1f& output_metal = output.grid[grid_id::metal];
    const vec1f& output_age = output.grid[grid_id::age];
    const vec1f& output_z = output.grid[grid_id::z];
    const vec1f& output_av = output.grid[grid_id::av];

    // Compute "cosmic" time (t=0 is when the galaxy is born)
    const double dt = opts.custom_sfh_step;
    const vec1d ctime = reverse(dt*indgen<double>(uint_t(ceil(e10(max(output_age))/dt)+1.0)));
    // NB: age array is sorted from largest to smallest

    auto pg = progress_start(nmodel);
    for (uint_t im : range(output_metal)) {
        m.idm[_] = 0;
        m.idm[grid_id::metal] = im;

        // Load SSP
        std::string filename = get_library_file_ssp(im);
        if (!ssp.read(filename)) {
            return false;
        }

        // Apply velocity dispersion
        if (is_finite(opts.apply_vdisp)) {
            ssp.sed = convolve_vdisp(ssp.lambda, ssp.sed, opts.apply_vdisp);
        }

        // Pre-compute dust law & IGM absorption (they don't change with SFH)
        vec2d dust_law = build_dust_law(output_av, ssp.lambda);
        vec2d igm_abs;
        if (!opts.no_igm) {
            igm_abs = build_igm_absorption(output_z, ssp.lambda);
        }

        // Function to build a model
        auto do_model = [&](model_id_pair& tm) {
            float& model_mass  = tm.model.props[prop_id::mass];
            float& model_mform = tm.model.props[prop_id::mform];
            float& model_sfr   = tm.model.props[prop_id::sfr];
            float& model_ssfr  = tm.model.props[prop_id::ssfr];

            // Compute lookback time (t=0 is when the galaxy is observed, t>0 is in the past)
            uint_t ia = tm.idm[grid_id::age];
            vec1d ltime = e10(output_age[ia]) - ctime;

            // Build analytic SFH
            vec1d sfh; {
                auto lock = (opts.parallel == parallel_choice::generators ?
                    std::unique_lock<std::mutex>(sfh_mutex) : std::unique_lock<std::mutex>());

                evaluate_sfh_custom(tm.idm, ctime, sfh);
            }

            // Integrate SFH on local time grid
            vec1d tpl_flux(ssp.lambda.size());
            double tmodel_mass  = 0.0;
            double tformed_mass = 0.0;
            ssp.integrate(ltime, sfh, [&](uint_t it, double formed) {
                tmodel_mass  += formed*ssp.mass.safe[it];
                tformed_mass += formed*ssp.mass.safe[0];
                tpl_flux     += formed*ssp.sed.safe(it,_);
            });

            model_mass = tmodel_mass;
            model_mform = tformed_mass;

            if (opts.sfr_avg > 0) {
                // Average SFR over the past X yr
                double t1 = min(opts.sfr_avg, ltime.back());
                model_sfr = integrate(ltime, sfh, 0.0, t1)/opts.sfr_avg;
            } else {
                // Use instantaneous SFR
                model_sfr = interpolate(sfh, ltime, 0.0);
            }

            model_ssfr = model_sfr/model_mass;

            // The rest is not specific to the SFH, use generic code
            build_and_send_impl(fitter, pg, ssp.lambda, tpl_flux, dust_law, igm_abs,
                output_age[ia], tm.idm, tm.model);
        };

        thread::worker_pool<model_id_pair> pool;
        if (opts.parallel == parallel_choice::generators) {
            pool.start(opts.n_thread, do_model);
        }

        // Iterate over all models
        for (uint_t ic = 0; ic < ncustom; ++ic) {
            for (uint_t ia : range(output_age)) {
                m.idm[grid_id::age] = ia;

                if (opts.parallel == parallel_choice::generators) {
                    // Parallel
                    while (opts.max_queued_fits > 0 &&
                        pool.remaining() > opts.max_queued_fits) {
                        thread::sleep_for(1e-6);
                    }

                    pool.process(m);
                } else {
                    // Single threaded
                    do_model(m);
                }
            }

            // Go to next model
            increment_index_list(m.idm, grid_dims);
        }

        if (opts.parallel == parallel_choice::generators) {
            while (pool.remaining() != 0) {
                thread::sleep_for(1e-6);
            }

            pool.join();
        }
    }

    return true;
}

bool gridder_t::build_template_custom(uint_t iflat, vec1f& lam, vec1f& flux) const {
    vec1u idm = grid_ids(iflat);
    uint_t ia = idm[grid_id::age];
    uint_t im = idm[grid_id::metal];
    const vec1f& output_age = output.grid[grid_id::age];

    ssp_bc03* ssp = cached_ssp_bc03.get();

    {
        auto lock = (opts.n_thread > 1 ?
            std::unique_lock<std::mutex>(sed_mutex) : std::unique_lock<std::mutex>());

        if (!cached_ssp_bc03) {
            cached_ssp_bc03 = std::unique_ptr<ssp_bc03>(new ssp_bc03());
            ssp = cached_ssp_bc03.get();
        }

        // Load SSP
        std::string filename = get_library_file_ssp(im);
        if (filename != cached_library) {
            if (!ssp->read(filename)) {
                return false;
            }

            cached_library = filename;

            // Apply velocity dispersion
            if (is_finite(opts.apply_vdisp)) {
                ssp->sed = convolve_vdisp(ssp->lambda, ssp->sed, opts.apply_vdisp);
            }
        }
    }

    // Build analytic SFH
    double dt = opts.custom_sfh_step;
    vec1d ctime = reverse(dt*indgen<double>(uint_t(ceil(e10(max(output_age))/dt)+1.0)));
    // NB: age array is sorted from largest to smallest
    vec1d sfh; {
        auto lock = (opts.n_thread > 1 ?
            std::unique_lock<std::mutex>(sfh_mutex) : std::unique_lock<std::mutex>());

        evaluate_sfh_custom(idm, ctime, sfh);
    }

    // Integrate SFH on local time grid
    vec1d tpl_flux(ssp->lambda.size());
    ssp->integrate(e10(output_age[ia]) - ctime, sfh,
        [&](uint_t it, double formed) {
            tpl_flux += formed*ssp->sed.safe(it,_);
        }
    );

    lam = ssp->lambda;
    flux = tpl_flux;

    return true;
}

bool gridder_t::get_sfh_custom(uint_t iflat, const vec1d& t, vec1d& sfh,
    const std::string& type) const {

    vec1u idm = grid_ids(iflat);
    double nage = e10(output.grid[grid_id::age][idm[grid_id::age]]);
    double age_obs = e10(auniv[grid_id::z]);
    double age_born = age_obs - nage;

    // Evaluate SFH
    uint_t i0 = upper_bound(t, age_born);
    uint_t i1 = upper_bound(t, age_obs);

    if (i1 == npos) {
        i1 = t.size()-1;
    }
    if (i0 == npos) {
        i0 = 0;
    }

    sfh = replicate(0.0, t.size()); {
        vec1d tsfh;
        evaluate_sfh_custom(idm, t[i0-_] - age_born, tsfh);
        sfh[i0-_] = tsfh;
    }

    // Load SSP (only extras) to get mass
    std::string filename = get_library_file_ssp(idm[grid_id::metal]);

    ssp_bc03 ssp;
    if (!ssp.read(filename, true)) {
        return false;
    }

    if (type == "sfr") {
        // Compute total mass at epoch of observation and normalize
        double mass = 0.0;
        ssp.integrate(nage + age_born - reverse(t), reverse(sfh),
            [&](uint_t it, double formed) {
                mass += formed*ssp.mass.safe[it];
            }
        );

        sfh /= mass;
    } else if (type == "mass") {
        // Integrate mass, including mass loss
        vec1d mass(t.size());
        vec1d lsfh = reverse(sfh);

        for (uint_t i : range(t)) {
            ssp.integrate(t.safe[i] - reverse(t), lsfh,
                [&](uint_t it, double formed) {
                    mass.safe[i] += formed*ssp.mass.safe[it];
                }
            );
        }

        // Normalize to unit mass at observation
        mass /= interpolate(mass, t, nage + age_born);

        // Return mass instead of SFR
        std::swap(mass, sfh);
    } else {
        error("unknown SFH type '", type, "'");
        return false;
    }

    return true;
}
<commit_msg>Clarified time treatment in custom gridder and fixed bugs with age<commit_after>#include "fast++.hpp"

extern "C" {
    #include "tinyexpr.h"
}

double expr_step(double a) {
    return (a >= 0 ? 1.0 : 0.0);
}

double expr_min(double a, double b) {
    return std::min(a, b);
}

double expr_max(double a, double b) {
    return std::max(a, b);
}

bool gridder_t::tinyexpr_wrapper::compile(const std::string& sexpr, const vec1s& params) {
    uint_t nparam = params.size();
    uint_t nfunc = 3;

    vars_glue = new te_variable[nparam+nfunc];
    for (uint_t p : range(nparam+nfunc)) {
        vars_glue[p].context = nullptr;
    }

    vars.resize(nparam);

    // Time
    vars_glue[0].name = "t";
    vars_glue[0].address = &vars[0];
    vars_glue[0].type = TE_VARIABLE;

    // Custom parameters
    for (uint_t p : range(nparam)) {
        vars_glue[p].name = params[p].c_str();
        vars_glue[p].address = &vars[p];
        vars_glue[p].type = TE_VARIABLE;
    }

    // Custom functions
    vars_glue[nparam+0].name = "step";
    vars_glue[nparam+0].address = (void*)(&expr_step);
    vars_glue[nparam+0].type = TE_FUNCTION1 | TE_FLAG_PURE;
    vars_glue[nparam+1].name = "min";
    vars_glue[nparam+1].address = (void*)(&expr_min);
    vars_glue[nparam+1].type = TE_FUNCTION2 | TE_FLAG_PURE;
    vars_glue[nparam+2].name = "max";
    vars_glue[nparam+2].address = (void*)(&expr_max);
    vars_glue[nparam+2].type = TE_FUNCTION2 | TE_FLAG_PURE;

    // Compile expression
    int err = 0;
    expr = te_compile(sexpr.c_str(), vars_glue, nparam+nfunc, &err);
    if (err > 0) {
        std::string head = "could not parse SFH expression: ";
        error(head, sexpr);
        error(std::string(head.size()+err-1, ' ')+'^');
        return false;
    }

    return true;
}

double gridder_t::tinyexpr_wrapper::eval() {
    return te_eval(expr);
}

gridder_t::tinyexpr_wrapper::~tinyexpr_wrapper() {
    if (expr != nullptr) {
        te_free(expr);
        delete[] vars_glue;
    }
}

std::string gridder_t::get_library_file_ssp(uint_t im) const {
    return opts.library_dir+"ssp"+"."+opts.resolution+"/"+
        opts.library+"_"+opts.resolution+"_"+opts.name_imf+
        "_z"+replace(to_string(output.grid[grid_id::metal][im]), "0.", "");
}

void gridder_t::evaluate_sfh_custom(const vec1u& idm, const vec1d& t, vec1d& sfh) const {
    sfh_expr.vars[1] = output.grid[grid_id::age][idm[grid_id::age]];
    for (uint_t i : range(opts.custom_params)) {
        sfh_expr.vars[i+2] = output.grid[grid_id::custom+i][idm[grid_id::custom+i]];
    }

    sfh.resize(t.size());
    double nage = e10(output.grid[grid_id::age][idm[grid_id::age]]);
    for (uint_t i : range(t)) {
        sfh_expr.vars[0] = (opts.custom_sfh_lookback ? t.safe[i] : nage - t.safe[i]);
        sfh.safe[i] = sfh_expr.eval();
    }
}

bool gridder_t::build_and_send_custom(fitter_t& fitter) {
    model_id_pair m;
    m.model.flux.resize(input.lambda.size());
    m.model.props.resize(nprop);
    m.idm.resize(nparam);

    ssp_bc03 ssp;

    const vec1f& output_metal = output.grid[grid_id::metal];
    const vec1f& output_age = output.grid[grid_id::age];
    const vec1f& output_z = output.grid[grid_id::z];
    const vec1f& output_av = output.grid[grid_id::av];

    auto pg = progress_start(nmodel);
    for (uint_t im : range(output_metal)) {
        m.idm[_] = 0;
        m.idm[grid_id::metal] = im;

        // Load SSP
        std::string filename = get_library_file_ssp(im);
        if (!ssp.read(filename)) {
            return false;
        }

        // Apply velocity dispersion
        if (is_finite(opts.apply_vdisp)) {
            ssp.sed = convolve_vdisp(ssp.lambda, ssp.sed, opts.apply_vdisp);
        }

        // Pre-compute dust law & IGM absorption (they don't change with SFH)
        vec2d dust_law = build_dust_law(output_av, ssp.lambda);
        vec2d igm_abs;
        if (!opts.no_igm) {
            igm_abs = build_igm_absorption(output_z, ssp.lambda);
        }

        // Function to build a model
        auto do_model = [&](model_id_pair& tm) {
            float& model_mass  = tm.model.props[prop_id::mass];
            float& model_mform = tm.model.props[prop_id::mform];
            float& model_sfr   = tm.model.props[prop_id::sfr];
            float& model_ssfr  = tm.model.props[prop_id::ssfr];

            uint_t ia = tm.idm[grid_id::age];

            const double dt = opts.custom_sfh_step;
            // Compute lookback time (t=0 is when the galaxy is observed, t>0 is in the past) in [yr]
            vec1d ltime = dt*indgen<double>(uint_t(ceil(e10(output_age[ia])/dt)+1.0));

            // Build analytic SFH
            vec1d sfh; {
                auto lock = (opts.parallel == parallel_choice::generators ?
                    std::unique_lock<std::mutex>(sfh_mutex) : std::unique_lock<std::mutex>());

                evaluate_sfh_custom(tm.idm, ltime, sfh);
            }

            // Integrate SFH on local time grid
            vec1d tpl_flux(ssp.lambda.size());
            double tmodel_mass  = 0.0;
            double tformed_mass = 0.0;
            ssp.integrate(ltime, sfh, [&](uint_t it, double formed) {
                tmodel_mass  += formed*ssp.mass.safe[it];
                tformed_mass += formed*ssp.mass.safe[0];
                tpl_flux     += formed*ssp.sed.safe(it,_);
            });

            model_mass = tmodel_mass;
            model_mform = tformed_mass;

            if (opts.sfr_avg > 0) {
                // Average SFR over the past X yr
                double t1 = min(opts.sfr_avg, ltime.back());
                model_sfr = integrate(ltime, sfh, 0.0, t1)/opts.sfr_avg;
            } else {
                // Use instantaneous SFR
                model_sfr = interpolate(sfh, ltime, 0.0);
            }

            model_ssfr = model_sfr/model_mass;

            // The rest is not specific to the SFH, use generic code
            build_and_send_impl(fitter, pg, ssp.lambda, tpl_flux, dust_law, igm_abs,
                output_age[ia], tm.idm, tm.model);
        };

        thread::worker_pool<model_id_pair> pool;
        if (opts.parallel == parallel_choice::generators) {
            pool.start(opts.n_thread, do_model);
        }

        // Iterate over all models
        for (uint_t ic = 0; ic < ncustom; ++ic) {
            for (uint_t ia : range(output_age)) {
                m.idm[grid_id::age] = ia;

                if (opts.parallel == parallel_choice::generators) {
                    // Parallel
                    while (opts.max_queued_fits > 0 &&
                        pool.remaining() > opts.max_queued_fits) {
                        thread::sleep_for(1e-6);
                    }

                    pool.process(m);
                } else {
                    // Single threaded
                    do_model(m);
                }
            }

            // Go to next model
            increment_index_list(m.idm, grid_dims);
        }

        if (opts.parallel == parallel_choice::generators) {
            while (pool.remaining() != 0) {
                thread::sleep_for(1e-6);
            }

            pool.join();
        }
    }

    return true;
}

bool gridder_t::build_template_custom(uint_t iflat, vec1f& lam, vec1f& flux) const {
    vec1u idm = grid_ids(iflat);
    uint_t ia = idm[grid_id::age];
    uint_t im = idm[grid_id::metal];
    const vec1f& output_age = output.grid[grid_id::age];

    ssp_bc03* ssp = cached_ssp_bc03.get();

    {
        auto lock = (opts.n_thread > 1 ?
            std::unique_lock<std::mutex>(sed_mutex) : std::unique_lock<std::mutex>());

        if (!cached_ssp_bc03) {
            cached_ssp_bc03 = std::unique_ptr<ssp_bc03>(new ssp_bc03());
            ssp = cached_ssp_bc03.get();
        }

        // Load SSP
        std::string filename = get_library_file_ssp(im);
        if (filename != cached_library) {
            if (!ssp->read(filename)) {
                return false;
            }

            cached_library = filename;

            // Apply velocity dispersion
            if (is_finite(opts.apply_vdisp)) {
                ssp->sed = convolve_vdisp(ssp->lambda, ssp->sed, opts.apply_vdisp);
            }
        }
    }

    // Build analytic SFH
    double dt = opts.custom_sfh_step;
    vec1d ltime = dt*indgen<double>(uint_t(ceil(e10(output_age[ia])/dt)+1.0));
    vec1d sfh; {
        auto lock = (opts.n_thread > 1 ?
            std::unique_lock<std::mutex>(sfh_mutex) : std::unique_lock<std::mutex>());

        evaluate_sfh_custom(idm, ltime, sfh);
    }

    // Integrate SFH on local time grid
    vec1d tpl_flux(ssp->lambda.size());
    ssp->integrate(ltime, sfh, [&](uint_t it, double formed) {
        tpl_flux += formed*ssp->sed.safe(it,_);
    });

    lam = ssp->lambda;
    flux = tpl_flux;

    return true;
}

bool gridder_t::get_sfh_custom(uint_t iflat, const vec1d& t, vec1d& sfh,
    const std::string& type) const {

    vec1u idm = grid_ids(iflat);
    double nage = e10(output.grid[grid_id::age][idm[grid_id::age]]);
    double t_obs = e10(auniv[idm[grid_id::z]]);

    vec1d tlb = reverse(t_obs - t);

    // Evaluate SFH
    uint_t i1 = upper_bound(t, nage);
    if (i1 == npos) {
        i1 = t.size()-1;
    }

    sfh = replicate(0.0, t.size()); {
        vec1d tsfh;
        evaluate_sfh_custom(idm, t[_-i1], tsfh);
        sfh[_-i1] = tsfh;
    }

    // Load SSP (only extras) to get mass
    std::string filename = get_library_file_ssp(idm[grid_id::metal]);

    ssp_bc03 ssp;
    if (!ssp.read(filename, true)) {
        return false;
    }

    if (type == "sfr") {
        // Compute total mass at epoch of observation and normalize
        double mass = 0.0;
        ssp.integrate(tlb, sfh, [&](uint_t it, double formed) {
            mass += formed*ssp.mass.safe[it];
        });

        sfh /= mass;
    } else if (type == "mass") {
        // Integrate mass, including mass loss
        vec1d mass(t.size());

        for (uint_t i : range(t)) {
            ssp.integrate(tlb[i-_] - tlb.safe[i], sfh[i-_], [&](uint_t it, double formed) {
                mass.safe[i] += formed*ssp.mass.safe[it];
            });
        }

        // Normalize to unit mass at observation
        mass /= mass[0];

        // Return mass instead of SFR
        std::swap(mass, sfh);
    } else {
        error("unknown SFH type '", type, "'");
        return false;
    }

    sfh = reverse(sfh);

    return true;
}
<|endoftext|>


<commit_before>#include "OccupancyGridMap.hpp"
#include <boost/format.hpp>
#include <maps/tools/VoxelTraversal.hpp>

using namespace maps::grid;
using namespace maps::tools;

void OccupancyGridMap::mergePointCloud(const OccupancyGridMap::PointCloud& pc, const base::Transform3d& pc2grid)
{
    Eigen::Vector3d sensor_origin = pc.sensor_origin_.block(0,0,3,1).cast<double>();
    Eigen::Vector3d sensor_origin_in_grid = pc2grid * sensor_origin;
    Eigen::Vector3i sensor_origin_idx;
    Eigen::Vector3d origin_cell_center;
    if(!VoxelGridBase::toVoxelGrid(sensor_origin_in_grid, sensor_origin_idx) || !VoxelGridBase::fromVoxelGrid(sensor_origin_idx, origin_cell_center))
    {
        std::cerr << "Sensor origin (" << sensor_origin_in_grid.transpose() << ") is outside of the grid! Can't add corresponding point cloud to grid." << std::endl;
        return;
    }
    for(PointCloud::const_iterator it=pc.begin(); it != pc.end(); ++it)
    {
        try
        {
            Eigen::Vector3d measurement = it->getArray3fMap().cast<double>();
            mergePoint(sensor_origin_in_grid, sensor_origin_idx, origin_cell_center, pc2grid * measurement);
        }
        catch(const std::runtime_error& e)
        {
            // TODO use glog or base log for all out prints of this library
            std::cerr << e.what() << std::endl;
        }
    }
}

void OccupancyGridMap::mergePoint(const Eigen::Vector3d& sensor_origin, const Eigen::Vector3d& measurement)
{
    Eigen::Vector3i sensor_origin_idx;
    Eigen::Vector3d origin_cell_center;
    if(VoxelGridBase::toVoxelGrid(sensor_origin, sensor_origin_idx) && VoxelGridBase::fromVoxelGrid(sensor_origin_idx, origin_cell_center))
    {
        mergePoint(sensor_origin, sensor_origin_idx, origin_cell_center, measurement);
    }
    else
        throw std::runtime_error((boost::format("Sensor origin %1% is outside of the grid! Can't add to grid.") % sensor_origin.transpose()).str());
}

void OccupancyGridMap::mergePoint(const Eigen::Vector3d& sensor_origin, Eigen::Vector3i sensor_origin_idx,
                                  Eigen::Vector3d origin_cell_center, const Eigen::Vector3d& measurement)
{
    Eigen::Vector3i measurement_idx;
    if(VoxelGridBase::toVoxelGrid(measurement, measurement_idx))
    {
        std::vector<VoxelTraversal::RayElement> ray;
        VoxelTraversal::computeRay(VoxelGridBase::getVoxelResolution(), sensor_origin, sensor_origin_idx, origin_cell_center, measurement, measurement_idx, ray);

        VoxelCellType& cell = getVoxelCell(measurement_idx);
        cell.updateLogOdds(config.hit_logodds, config.min_logodds, config.max_logodds);

        for(const VoxelTraversal::RayElement& element : ray)
        {
            DiscreteTree<VoxelCellType>& tree = at(element.idx);
            for(int32_t z_idx = element.z_first; z_idx != element.z_last; z_idx += element.z_step)
            {
                tree.getCellAt(z_idx).updateLogOdds(config.miss_logodds, config.min_logodds, config.max_logodds);
            }
        }
    }
    else
        throw std::runtime_error((boost::format("Point %1% or is outside of the grid! Can't add to grid.") % measurement.transpose()).str());
}

bool OccupancyGridMap::isOccupied(const Eigen::Vector3d& point) const
{
    Index idx;
    if(GridMapBase::toGrid(point, idx))
        return isOccupied(idx, point.z());
    throw std::runtime_error((boost::format("Point %1% is outside of the grid!") % point.transpose()).str());
}

bool OccupancyGridMap::isOccupied(Index idx, float z) const
{
    const DiscreteTree<VoxelCellType>& cell_tree = at(idx);
    DiscreteTree<VoxelCellType>::const_iterator it = cell_tree.find(z);
    return it != cell_tree.end() && it->second.getLogOdds() >= config.occupied_logodds;
}

bool OccupancyGridMap::isFreeSpace(const Eigen::Vector3d& point) const
{
    Index idx;
    if(GridMapBase::toGrid(point, idx))
        return isFreeSpace(idx, point.z());
    throw std::runtime_error((boost::format("Point %1% is outside of the grid!") % point.transpose()).str());
}

bool OccupancyGridMap::isFreeSpace(Index idx, float z) const
{
    const DiscreteTree<VoxelCellType>& cell_tree = at(idx);
    DiscreteTree<VoxelCellType>::const_iterator it = cell_tree.find(z);
    return it != cell_tree.end() && it->second.getLogOdds() <= config.free_space_logodds;
}

bool OccupancyGridMap::hasSameFrame(const base::Transform3d& local_frame, const Vector2ui& num_cells, const Vector2d& resolution) const
{
     if(getResolution() == resolution && getNumCells() == num_cells && getLocalFrame().isApprox(local_frame))
         return true;
     return false;
}

BOOST_CLASS_EXPORT_IMPLEMENT(maps::grid::OccupancyGridMap);
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
template void maps::grid::OccupancyGridMap::serialize(boost::archive::text_iarchive& arch, const unsigned int version);
template void maps::grid::OccupancyGridMap::serialize(boost::archive::text_oarchive& arch, const unsigned int version);
template void maps::grid::OccupancyGridMap::serialize(boost::archive::binary_iarchive& arch, const unsigned int version);
template void maps::grid::OccupancyGridMap::serialize(boost::archive::binary_oarchive& arch, const unsigned int version);<commit_msg>fixed a bug in the iteration of z indices of a single ray<commit_after>#include "OccupancyGridMap.hpp"
#include <boost/format.hpp>
#include <maps/tools/VoxelTraversal.hpp>

using namespace maps::grid;
using namespace maps::tools;

void OccupancyGridMap::mergePointCloud(const OccupancyGridMap::PointCloud& pc, const base::Transform3d& pc2grid)
{
    Eigen::Vector3d sensor_origin = pc.sensor_origin_.block(0,0,3,1).cast<double>();
    Eigen::Vector3d sensor_origin_in_grid = pc2grid * sensor_origin;
    Eigen::Vector3i sensor_origin_idx;
    Eigen::Vector3d origin_cell_center;
    if(!VoxelGridBase::toVoxelGrid(sensor_origin_in_grid, sensor_origin_idx) || !VoxelGridBase::fromVoxelGrid(sensor_origin_idx, origin_cell_center))
    {
        std::cerr << "Sensor origin (" << sensor_origin_in_grid.transpose() << ") is outside of the grid! Can't add corresponding point cloud to grid." << std::endl;
        return;
    }
    for(PointCloud::const_iterator it=pc.begin(); it != pc.end(); ++it)
    {
        try
        {
            Eigen::Vector3d measurement = it->getArray3fMap().cast<double>();
            mergePoint(sensor_origin_in_grid, sensor_origin_idx, origin_cell_center, pc2grid * measurement);
        }
        catch(const std::runtime_error& e)
        {
            // TODO use glog or base log for all out prints of this library
            std::cerr << e.what() << std::endl;
        }
    }
}

void OccupancyGridMap::mergePoint(const Eigen::Vector3d& sensor_origin, const Eigen::Vector3d& measurement)
{
    Eigen::Vector3i sensor_origin_idx;
    Eigen::Vector3d origin_cell_center;
    if(VoxelGridBase::toVoxelGrid(sensor_origin, sensor_origin_idx) && VoxelGridBase::fromVoxelGrid(sensor_origin_idx, origin_cell_center))
    {
        mergePoint(sensor_origin, sensor_origin_idx, origin_cell_center, measurement);
    }
    else
        throw std::runtime_error((boost::format("Sensor origin %1% is outside of the grid! Can't add to grid.") % sensor_origin.transpose()).str());
}

void OccupancyGridMap::mergePoint(const Eigen::Vector3d& sensor_origin, Eigen::Vector3i sensor_origin_idx,
                                  Eigen::Vector3d origin_cell_center, const Eigen::Vector3d& measurement)
{
    Eigen::Vector3i measurement_idx;
    if(VoxelGridBase::toVoxelGrid(measurement, measurement_idx))
    {
        std::vector<VoxelTraversal::RayElement> ray;
        VoxelTraversal::computeRay(VoxelGridBase::getVoxelResolution(), sensor_origin, sensor_origin_idx, origin_cell_center, measurement, measurement_idx, ray);

        VoxelCellType& cell = getVoxelCell(measurement_idx);
        cell.updateLogOdds(config.hit_logodds, config.min_logodds, config.max_logodds);

        for(const VoxelTraversal::RayElement& element : ray)
        {
            DiscreteTree<VoxelCellType>& tree = at(element.idx);
            int32_t z_end = element.z_last + element.z_step;
            for(int32_t z_idx = element.z_first; z_idx != z_end; z_idx += element.z_step)
            {
                tree.getCellAt(z_idx).updateLogOdds(config.miss_logodds, config.min_logodds, config.max_logodds);
            }
        }
    }
    else
        throw std::runtime_error((boost::format("Point %1% or is outside of the grid! Can't add to grid.") % measurement.transpose()).str());
}

bool OccupancyGridMap::isOccupied(const Eigen::Vector3d& point) const
{
    Index idx;
    if(GridMapBase::toGrid(point, idx))
        return isOccupied(idx, point.z());
    throw std::runtime_error((boost::format("Point %1% is outside of the grid!") % point.transpose()).str());
}

bool OccupancyGridMap::isOccupied(Index idx, float z) const
{
    const DiscreteTree<VoxelCellType>& cell_tree = at(idx);
    DiscreteTree<VoxelCellType>::const_iterator it = cell_tree.find(z);
    return it != cell_tree.end() && it->second.getLogOdds() >= config.occupied_logodds;
}

bool OccupancyGridMap::isFreeSpace(const Eigen::Vector3d& point) const
{
    Index idx;
    if(GridMapBase::toGrid(point, idx))
        return isFreeSpace(idx, point.z());
    throw std::runtime_error((boost::format("Point %1% is outside of the grid!") % point.transpose()).str());
}

bool OccupancyGridMap::isFreeSpace(Index idx, float z) const
{
    const DiscreteTree<VoxelCellType>& cell_tree = at(idx);
    DiscreteTree<VoxelCellType>::const_iterator it = cell_tree.find(z);
    return it != cell_tree.end() && it->second.getLogOdds() <= config.free_space_logodds;
}

bool OccupancyGridMap::hasSameFrame(const base::Transform3d& local_frame, const Vector2ui& num_cells, const Vector2d& resolution) const
{
     if(getResolution() == resolution && getNumCells() == num_cells && getLocalFrame().isApprox(local_frame))
         return true;
     return false;
}

BOOST_CLASS_EXPORT_IMPLEMENT(maps::grid::OccupancyGridMap);
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
template void maps::grid::OccupancyGridMap::serialize(boost::archive::text_iarchive& arch, const unsigned int version);
template void maps::grid::OccupancyGridMap::serialize(boost::archive::text_oarchive& arch, const unsigned int version);
template void maps::grid::OccupancyGridMap::serialize(boost::archive::binary_iarchive& arch, const unsigned int version);
template void maps::grid::OccupancyGridMap::serialize(boost::archive::binary_oarchive& arch, const unsigned int version);<|endoftext|>


<commit_before>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2020, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

// This file is based on `imgui/examples/example_sdl_opengl3/main.cpp`
// Licensed under the MIT License (MIT)
// Copyright (c) 2014-2020 Omar Cornut

#include "vendor/imgui/examples/imgui_impl_opengl3.h"
#include "vendor/imgui/examples/imgui_impl_sdl.h"
#include "vendor/imgui/imgui.h"
#include <SDL.h>
#include <stdio.h>

// About Desktop OpenGL function loaders:
//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
#include <GL/gl3w.h> // Initialize with gl3wInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
#include <GL/glew.h> // Initialize with glewInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Initialize with gladLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
#include <glad/gl.h> // Initialize with gladLoadGL(...) or gladLoaderLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
#define GLFW_INCLUDE_NONE      // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/Binding.h> // Initialize with glbinding::Binding::initialize()
#include <glbinding/gl/gl.h>
using namespace gl;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/gl/gl.h>
#include <glbinding/glbinding.h> // Initialize with glbinding::initialize()
using namespace gl;
#else
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#endif

class ImGuiLoop {
    SDL_Window* window = nullptr;
    SDL_GLContext gl_context = nullptr;

public:
    bool done = false;
    const ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

public:
    inline void init(const char* window_title)
    {
        // Setup SDL
        // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
        // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!)
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
            printf("Error: %s\n", SDL_GetError());
            exit(EXIT_FAILURE);
        }

        // Decide GL+GLSL versions
#if __APPLE__
        // GL 3.2 Core + GLSL 150
        const char* glsl_version = "#version 150";
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
#else
        // GL 3.0 + GLSL 130
        const char* glsl_version = "#version 130";
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif

        // Create window with graphics context
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
        SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
        window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
        gl_context = SDL_GL_CreateContext(window);
        SDL_GL_MakeCurrent(window, gl_context);
        SDL_GL_SetSwapInterval(1); // Enable vsync

        // Initialize OpenGL loader
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
        bool err = gl3wInit() != 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
        bool err = glewInit() != GLEW_OK;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
        bool err = gladLoadGL() == 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
        bool err = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
        bool err = false;
        glbinding::Binding::initialize();
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
        bool err = false;
        glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)SDL_GL_GetProcAddress(name); });
#else
        bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
#endif
        if (err) {
            fprintf(stderr, "Failed to initialize OpenGL loader!\n");
            exit(EXIT_FAILURE);
        }

        // Setup Dear ImGui context
        IMGUI_CHECKVERSION();
        ImGui::CreateContext();

        // Setup Platform/Renderer bindings
        ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
        ImGui_ImplOpenGL3_Init(glsl_version);
    }

    inline void newFrame()
    {
        // Poll and handle events (inputs, window resize, etc.)
        // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
        // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
        // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
        // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            ImGui_ImplSDL2_ProcessEvent(&event);
            if (event.type == SDL_QUIT) {
                done = true;
            }
            if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) {
                done = true;
            }
        }

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplSDL2_NewFrame(window);
        ImGui::NewFrame();
    }

    inline void render()
    {
        const ImGuiIO& io = ImGui::GetIO();

        ImGui::Render();

        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        SDL_GL_SwapWindow(window);

        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        // Update and Render additional Platform Windows
        // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
        //  For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
            SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
            SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
        }

        SDL_GL_SwapWindow(window);
    }

    inline bool cleanup()
    {
        ImGui_ImplOpenGL3_Shutdown();
        ImGui_ImplSDL2_Shutdown();
        ImGui::DestroyContext();

        SDL_GL_DeleteContext(gl_context);
        SDL_DestroyWindow(window);
        SDL_Quit();

        return 0;
    }
};
<commit_msg>Fix framerate<commit_after>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2020, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

// This file is based on `imgui/examples/example_sdl_opengl3/main.cpp`
// Licensed under the MIT License (MIT)
// Copyright (c) 2014-2020 Omar Cornut

#include "vendor/imgui/examples/imgui_impl_opengl3.h"
#include "vendor/imgui/examples/imgui_impl_sdl.h"
#include "vendor/imgui/imgui.h"
#include <SDL.h>
#include <stdio.h>

// About Desktop OpenGL function loaders:
//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
#include <GL/gl3w.h> // Initialize with gl3wInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
#include <GL/glew.h> // Initialize with glewInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Initialize with gladLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
#include <glad/gl.h> // Initialize with gladLoadGL(...) or gladLoaderLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
#define GLFW_INCLUDE_NONE      // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/Binding.h> // Initialize with glbinding::Binding::initialize()
#include <glbinding/gl/gl.h>
using namespace gl;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/gl/gl.h>
#include <glbinding/glbinding.h> // Initialize with glbinding::initialize()
using namespace gl;
#else
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#endif

class ImGuiLoop {
    SDL_Window* window = nullptr;
    SDL_GLContext gl_context = nullptr;

public:
    bool done = false;
    const ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

public:
    inline void init(const char* window_title)
    {
        // Setup SDL
        // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
        // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!)
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
            printf("Error: %s\n", SDL_GetError());
            exit(EXIT_FAILURE);
        }

        // Decide GL+GLSL versions
#if __APPLE__
        // GL 3.2 Core + GLSL 150
        const char* glsl_version = "#version 150";
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
#else
        // GL 3.0 + GLSL 130
        const char* glsl_version = "#version 130";
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif

        // Create window with graphics context
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
        SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
        window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
        gl_context = SDL_GL_CreateContext(window);
        SDL_GL_MakeCurrent(window, gl_context);
        SDL_GL_SetSwapInterval(1); // Enable vsync

        // Initialize OpenGL loader
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
        bool err = gl3wInit() != 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
        bool err = glewInit() != GLEW_OK;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
        bool err = gladLoadGL() == 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
        bool err = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one.
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
        bool err = false;
        glbinding::Binding::initialize();
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
        bool err = false;
        glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)SDL_GL_GetProcAddress(name); });
#else
        bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
#endif
        if (err) {
            fprintf(stderr, "Failed to initialize OpenGL loader!\n");
            exit(EXIT_FAILURE);
        }

        // Setup Dear ImGui context
        IMGUI_CHECKVERSION();
        ImGui::CreateContext();

        // Setup Platform/Renderer bindings
        ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
        ImGui_ImplOpenGL3_Init(glsl_version);
    }

    inline void newFrame()
    {
        // Poll and handle events (inputs, window resize, etc.)
        // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
        // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
        // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
        // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            ImGui_ImplSDL2_ProcessEvent(&event);
            if (event.type == SDL_QUIT) {
                done = true;
            }
            if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) {
                done = true;
            }
        }

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplSDL2_NewFrame(window);
        ImGui::NewFrame();
    }

    inline void render()
    {
        const ImGuiIO& io = ImGui::GetIO();

        ImGui::Render();

        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);

        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        // Update and Render additional Platform Windows
        // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
        //  For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
            SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
            SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
        }

        SDL_GL_SwapWindow(window);
    }

    inline bool cleanup()
    {
        ImGui_ImplOpenGL3_Shutdown();
        ImGui_ImplSDL2_Shutdown();
        ImGui::DestroyContext();

        SDL_GL_DeleteContext(gl_context);
        SDL_DestroyWindow(window);
        SDL_Quit();

        return 0;
    }
};
<|endoftext|>


<commit_before>/*  Copyright (C) 2006 Imperial College London and others.

    Please see the AUTHORS file in the main source directory for a full list
    of copyright holders.

    Prof. C Pain
    Applied Modelling and Computation Group
    Department of Earth Science and Engineering
    Imperial College London

    C.Pain@Imperial.ac.uk

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
    USA
*/

#include <iostream>
#include <map>
#include <stdlib.h>

#include "confdefs.h"

#ifdef HAVE_MPI
#include <mpi.h>
#endif

#include "Usage.h"
#include "c++debug.h"

using namespace std;

#ifdef DOUBLEP
typedef double real_t;
#else
typedef float real_t;
#endif

extern "C"{
#define vertical_integration F77_FUNC(vertical_integration, VERTICAL_INTEGRATION)
  void vertical_integration(const char* target_basename, int* target_basename_len,
                            const char* integrated_filename, int* integrated_filename_len,
                            const char* output_basename, int* output_basename_len,
                            real_t* top, real_t* bottom, real_t* sizing, int* result_continuity, int* result_degree);

#ifdef HAVE_PYTHON
#include "python_statec.h"
#endif
}

void Usage(){
  cerr << "Usage: vertical_intergation [OPTIONS] ... TARGET INTEGRATED OUTPUT\n"
       << "\n"
       << "Performs a vertical integration of a vtu via the use of supermeshing a\n"
       << "vertical extrusion.\n"
       << "\n"
       << "Options:\n"
       << "\n"
       << "-b\t\tBottom\n"
       << "-d\t\tDiscontinuous result (default false for degree > 0, true for degree == 0)\n"
       << "-h\t\tDisplay this help\n"
       << "-p\t\tResult degree (default 1)\n"
       << "-s\t\tSizing\n"
       << "-t\t\tTop (default 0.0)\n"
       << "-v\t\tVerbose mode" << endl;
}

int main(int argc, char** argv){
#ifdef HAVE_MPI
  MPI::Init(argc, argv);
  // Undo some MPI init shenanigans
  chdir(getenv("PWD"));
#endif
  PetscInit(argc, argv);
#ifdef HAVE_PYTHON
  // Initialize the Python Interpreter
  python_init_();
#endif

  // Modified version of flredecomp argument parsing
  // Get any command line arguments
  // Reset optarg so we can detect changes
  optarg = NULL;
  char c;
  map<char, string> args;
  while((c = getopt(argc, argv, "b:dhp:s:t:v")) != -1){
    if (c != '?'){
      if(optarg == NULL){
        args[c] = "true";
      }else{
        args[c] = optarg;
      }
    }else{
      if(isprint(optopt)){
        cerr << "Unknown option " << optopt << endl;
      }else{
        cerr << "Unknown option " << hex << optopt << endl;
      }
      Usage();
      exit(-1);
    }
  }

  // Help
  if(args.count('h')){
    Usage();
    exit(0);
  }

  // Verbosity
  int verbosity = 0;
  if(args.count('v') > 0){
    verbosity = 3;
  }
  set_global_debug_level_fc(&verbosity);

  // Options
  real_t bottom, sizing, top = 0.0;
  if(args.count('b') > 0){
    bottom = atof(args['b'].c_str());
  }else{
    cerr << "Bottom required" << endl;
    Usage();
    exit(-1);
  }
  if(args.count('s') > 0){
    sizing = atof(args['s'].c_str());
  }else{
    cerr << "Sizing required" << endl;
    Usage();
    exit(-1);
  }
  if(args.count('t') > 0){
    top = atof(args['t'].c_str());
  }
  int result_degree = 0;
  if(args.count('p') > 0){
    result_degree = atoi(args['p'].c_str());
  }
  int result_continuity = args.count('d') > 0 ? -1 : (result_degree == 0 ? -1 : 0);

  // Input / output
  string target_basename, integrated_filename, integrated_fieldname, output_basename;
  if(argc > optind + 3){
    target_basename = argv[optind + 1];
    integrated_filename = argv[optind + 2];
    output_basename = argv[optind + 3];
  }else if(argc == optind + 3){
    target_basename = argv[optind];
    integrated_filename = argv[optind + 1];
    output_basename = argv[optind + 2];
  }else{
    Usage();
    exit(-1);
  }

  int target_basename_len = target_basename.size();
  int integrated_filename_len = integrated_filename.size();
  int output_basename_len = output_basename.size();
  vertical_integration(target_basename.c_str(), &target_basename_len,
                       integrated_filename.c_str(), &integrated_filename_len,
                       output_basename.c_str(), &output_basename_len,
                       &top, &bottom, &sizing, &result_continuity, &result_degree);

#ifdef HAVE_PYTHON
  // Finalize the Python Interpreter
  python_end_();
#endif

#ifdef HAVE_PETSC
  PetscFinalize();
#endif

#ifdef HAVE_MPI
  MPI::Finalize();
#endif
  return 0;
}
<commit_msg>Actually change the vertical_integration defaults<commit_after>/*  Copyright (C) 2006 Imperial College London and others.

    Please see the AUTHORS file in the main source directory for a full list
    of copyright holders.

    Prof. C Pain
    Applied Modelling and Computation Group
    Department of Earth Science and Engineering
    Imperial College London

    C.Pain@Imperial.ac.uk

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
    USA
*/

#include <iostream>
#include <map>
#include <stdlib.h>

#include "confdefs.h"

#ifdef HAVE_MPI
#include <mpi.h>
#endif

#include "Usage.h"
#include "c++debug.h"

using namespace std;

#ifdef DOUBLEP
typedef double real_t;
#else
typedef float real_t;
#endif

extern "C"{
#define vertical_integration F77_FUNC(vertical_integration, VERTICAL_INTEGRATION)
  void vertical_integration(const char* target_basename, int* target_basename_len,
                            const char* integrated_filename, int* integrated_filename_len,
                            const char* output_basename, int* output_basename_len,
                            real_t* top, real_t* bottom, real_t* sizing, int* result_continuity, int* result_degree);

#ifdef HAVE_PYTHON
#include "python_statec.h"
#endif
}

void Usage(){
  cerr << "Usage: vertical_intergation [OPTIONS] ... TARGET INTEGRATED OUTPUT\n"
       << "\n"
       << "Performs a vertical integration of a vtu via the use of supermeshing a\n"
       << "vertical extrusion.\n"
       << "\n"
       << "Options:\n"
       << "\n"
       << "-b\t\tBottom\n"
       << "-d\t\tDiscontinuous result (default false for degree > 0, true for degree == 0)\n"
       << "-h\t\tDisplay this help\n"
       << "-p\t\tResult degree (default 1)\n"
       << "-s\t\tSizing\n"
       << "-t\t\tTop (default 0.0)\n"
       << "-v\t\tVerbose mode" << endl;
}

int main(int argc, char** argv){
#ifdef HAVE_MPI
  MPI::Init(argc, argv);
  // Undo some MPI init shenanigans
  chdir(getenv("PWD"));
#endif
  PetscInit(argc, argv);
#ifdef HAVE_PYTHON
  // Initialize the Python Interpreter
  python_init_();
#endif

  // Modified version of flredecomp argument parsing
  // Get any command line arguments
  // Reset optarg so we can detect changes
  optarg = NULL;
  char c;
  map<char, string> args;
  while((c = getopt(argc, argv, "b:dhp:s:t:v")) != -1){
    if (c != '?'){
      if(optarg == NULL){
        args[c] = "true";
      }else{
        args[c] = optarg;
      }
    }else{
      if(isprint(optopt)){
        cerr << "Unknown option " << optopt << endl;
      }else{
        cerr << "Unknown option " << hex << optopt << endl;
      }
      Usage();
      exit(-1);
    }
  }

  // Help
  if(args.count('h')){
    Usage();
    exit(0);
  }

  // Verbosity
  int verbosity = 0;
  if(args.count('v') > 0){
    verbosity = 3;
  }
  set_global_debug_level_fc(&verbosity);

  // Options
  real_t bottom, sizing, top = 0.0;
  if(args.count('b') > 0){
    bottom = atof(args['b'].c_str());
  }else{
    cerr << "Bottom required" << endl;
    Usage();
    exit(-1);
  }
  if(args.count('s') > 0){
    sizing = atof(args['s'].c_str());
  }else{
    cerr << "Sizing required" << endl;
    Usage();
    exit(-1);
  }
  if(args.count('t') > 0){
    top = atof(args['t'].c_str());
  }
  int result_degree = 1;
  if(args.count('p') > 0){
    result_degree = atoi(args['p'].c_str());
  }
  int result_continuity = args.count('d') > 0 ? -1 : (result_degree == 0 ? -1 : 0);

  // Input / output
  string target_basename, integrated_filename, integrated_fieldname, output_basename;
  if(argc > optind + 3){
    target_basename = argv[optind + 1];
    integrated_filename = argv[optind + 2];
    output_basename = argv[optind + 3];
  }else if(argc == optind + 3){
    target_basename = argv[optind];
    integrated_filename = argv[optind + 1];
    output_basename = argv[optind + 2];
  }else{
    Usage();
    exit(-1);
  }

  int target_basename_len = target_basename.size();
  int integrated_filename_len = integrated_filename.size();
  int output_basename_len = output_basename.size();
  vertical_integration(target_basename.c_str(), &target_basename_len,
                       integrated_filename.c_str(), &integrated_filename_len,
                       output_basename.c_str(), &output_basename_len,
                       &top, &bottom, &sizing, &result_continuity, &result_degree);

#ifdef HAVE_PYTHON
  // Finalize the Python Interpreter
  python_end_();
#endif

#ifdef HAVE_PETSC
  PetscFinalize();
#endif

#ifdef HAVE_MPI
  MPI::Finalize();
#endif
  return 0;
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2018 Asylo authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

#include <gtest/gtest.h>
#include "absl/synchronization/mutex.h"
#include "asylo/test/util/enclave_test.h"
#include "asylo/test/util/status_matchers.h"

namespace asylo {
namespace {

// Pipe for stdout inside enclave. When the enclave finishes registering a
// signal handler, it writes to it to inform that it's ready to receive signal.
int pair_stdout[2];

// Runs the enclave, waits until it returns, and checks the returned status.
void *RunEnclave(void *arg) {
  auto client = reinterpret_cast<EnclaveClient *>(arg);
  EXPECT_THAT(client->EnterAndRun({}, nullptr), IsOk());
  return nullptr;
}

struct SendSignalThreadInput {
  pthread_t enclave_thread;
  int poll_fd;
};

// Waits till the enclave thread registers the signal handler, and sends a
// signal to the enclave thread.
void *SendSignal(void *arg) {
  SendSignalThreadInput *input = reinterpret_cast<SendSignalThreadInput *>(arg);
  pthread_t enclave_thread = input->enclave_thread;
  struct pollfd fds[1];
  memset(fds, 0, sizeof(fds));
  fds[0].fd = input->poll_fd;
  fds[0].events = POLLIN;
  // Wait till enclave thread registers signal handler and writes to pipe. Time
  // out at 30 seconds.
  EXPECT_NE(poll(fds, 1, 30000), -1);
  // Sends the signal to the enclave thread.
  pthread_kill(enclave_thread, SIGUSR1);
  return nullptr;
}

class ActiveEnclaveSignalTest : public EnclaveTest {
 public:
  void SetUp() override {
    // Create a pipe for stdout.
    pipe(pair_stdout);
    // Pass in the enclave side of the pair.
    set_stdout(pair_stdout[1]);
    SetUpBase();
  }
};

// Tests signal handling inside enclave. |enclave_thread| enters the enclave,
// registers a signal handler, and writes to pipe to inform |signal_thread| that
// it has registered the handler and is ready to receive signal. |signal_thread|
// then sends a signal to |enclave_thread| to test whether the signal is handled
// correctly in the enclave.
TEST_F(ActiveEnclaveSignalTest, SignalTest) {
  pthread_t enclave_thread;
  ASSERT_EQ(pthread_create(&enclave_thread, nullptr, RunEnclave, client_), 0);
  pthread_t signal_thread;
  SendSignalThreadInput input;
  input.enclave_thread = enclave_thread;
  input.poll_fd = pair_stdout[0];
  ASSERT_EQ(pthread_create(&signal_thread, nullptr, SendSignal, &input), 0);

  ASSERT_EQ(pthread_join(signal_thread, nullptr), 0);
  ASSERT_EQ(pthread_join(enclave_thread, nullptr), 0);
}

}  // namespace
}  // namespace asylo
<commit_msg>Check for pipe result in signal test<commit_after>/*
 *
 * Copyright 2018 Asylo authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

#include <gtest/gtest.h>
#include "absl/synchronization/mutex.h"
#include "asylo/test/util/enclave_test.h"
#include "asylo/test/util/status_matchers.h"

namespace asylo {
namespace {

// Pipe for stdout inside enclave. When the enclave finishes registering a
// signal handler, it writes to it to inform that it's ready to receive signal.
int pair_stdout[2];

// Runs the enclave, waits until it returns, and checks the returned status.
void *RunEnclave(void *arg) {
  auto client = reinterpret_cast<EnclaveClient *>(arg);
  EXPECT_THAT(client->EnterAndRun({}, nullptr), IsOk());
  return nullptr;
}

struct SendSignalThreadInput {
  pthread_t enclave_thread;
  int poll_fd;
};

// Waits till the enclave thread registers the signal handler, and sends a
// signal to the enclave thread.
void *SendSignal(void *arg) {
  SendSignalThreadInput *input = reinterpret_cast<SendSignalThreadInput *>(arg);
  pthread_t enclave_thread = input->enclave_thread;
  struct pollfd fds[1];
  memset(fds, 0, sizeof(fds));
  fds[0].fd = input->poll_fd;
  fds[0].events = POLLIN;
  // Wait till enclave thread registers signal handler and writes to pipe. Time
  // out at 30 seconds.
  EXPECT_NE(poll(fds, 1, 30000), -1);
  // Sends the signal to the enclave thread.
  pthread_kill(enclave_thread, SIGUSR1);
  return nullptr;
}

class ActiveEnclaveSignalTest : public EnclaveTest {
 public:
  void SetUp() override {
    // Create a pipe for stdout.
    CHECK_EQ(pipe(pair_stdout), 0);
    // Pass in the enclave side of the pair.
    set_stdout(pair_stdout[1]);
    SetUpBase();
  }
};

// Tests signal handling inside enclave. |enclave_thread| enters the enclave,
// registers a signal handler, and writes to pipe to inform |signal_thread| that
// it has registered the handler and is ready to receive signal. |signal_thread|
// then sends a signal to |enclave_thread| to test whether the signal is handled
// correctly in the enclave.
TEST_F(ActiveEnclaveSignalTest, SignalTest) {
  pthread_t enclave_thread;
  ASSERT_EQ(pthread_create(&enclave_thread, nullptr, RunEnclave, client_), 0);
  pthread_t signal_thread;
  SendSignalThreadInput input;
  input.enclave_thread = enclave_thread;
  input.poll_fd = pair_stdout[0];
  ASSERT_EQ(pthread_create(&signal_thread, nullptr, SendSignal, &input), 0);

  ASSERT_EQ(pthread_join(signal_thread, nullptr), 0);
  ASSERT_EQ(pthread_join(enclave_thread, nullptr), 0);
}

}  // namespace
}  // namespace asylo
<|endoftext|>


<commit_before>
// Bindings
#include "CPyCppyy.h"
#include "PyROOTPythonize.h"
#include "CPPInstance.h"
#include "ProxyWrappers.h"
#include "Converters.h"
#include "Utility.h"

// ROOT
#include "TClass.h"
#include "TTree.h"
#include "TBranch.h"
#include "TBranchElement.h"
#include "TBranchObject.h"
#include "TLeaf.h"
#include "TLeafElement.h"
#include "TLeafObject.h"
#include "TStreamerElement.h"
#include "TStreamerInfo.h"

using namespace CPyCppyy;

static TClass *GetClass(const CPPInstance *pyobj)
{
   return TClass::GetClass(Cppyy::GetFinalName(pyobj->ObjectIsA()).c_str());
}

static TBranch *SearchForBranch(TTree *tree, const char *name)
{
   TBranch *branch = tree->GetBranch(name);
   if (!branch) {
      // for benefit of naming of sub-branches, the actual name may have a trailing '.'
      branch = tree->GetBranch((std::string(name) + '.').c_str());
   }
   return branch;
}

static TLeaf *SearchForLeaf(TTree *tree, const char *name, TBranch *branch)
{
   TLeaf *leaf = tree->GetLeaf(name);
   if (branch && !leaf) {
      leaf = branch->GetLeaf(name);
      if (!leaf) {
         TObjArray *leaves = branch->GetListOfLeaves();
         if (leaves->GetSize() && (leaves->First() == leaves->Last())) {
            // i.e., if unambiguously only this one
            leaf = (TLeaf *)leaves->At(0);
         }
      }
   }
   return leaf;
}

static PyObject *BindBranchToProxy(TTree *tree, const char *name, TBranch *branch)
{
   // for partial return of a split object
   if (branch->InheritsFrom(TBranchElement::Class())) {
      TBranchElement *be = (TBranchElement *)branch;
      if (be->GetCurrentClass() && (be->GetCurrentClass() != be->GetTargetClass()) && (0 <= be->GetID())) {
         Long_t offset = ((TStreamerElement *)be->GetInfo()->GetElements()->At(be->GetID()))->GetOffset();
         return BindCppObjectNoCast(be->GetObject() + offset, Cppyy::GetScope(be->GetCurrentClass()->GetName()));
      }
   }

   // for return of a full object
   if (branch->IsA() == TBranchElement::Class() || branch->IsA() == TBranchObject::Class()) {
      TClass *klass = TClass::GetClass(branch->GetClassName());
      if (klass && branch->GetAddress())
         return BindCppObjectNoCast(*(void **)branch->GetAddress(), Cppyy::GetScope(branch->GetClassName()));

      // try leaf, otherwise indicate failure by returning a typed null-object
      TObjArray *leaves = branch->GetListOfLeaves();
      if (klass && !tree->GetLeaf(name) && !(leaves->GetSize() && (leaves->First() == leaves->Last())))
         return BindCppObjectNoCast(nullptr, Cppyy::GetScope(branch->GetClassName()));
   }

   return nullptr;
}

static PyObject *WrapLeaf(TLeaf *leaf)
{
   if (1 < leaf->GetLenStatic() || leaf->GetLeafCount()) {
      // array types
      std::string typeName = leaf->GetTypeName();
      Converter *pcnv = CreateConverter(typeName + '*', leaf->GetNdata());

      void *address = 0;
      if (leaf->GetBranch())
         address = (void *)leaf->GetBranch()->GetAddress();
      if (!address)
         address = (void *)leaf->GetValuePointer();

      PyObject *value = pcnv->FromMemory(&address);
      delete pcnv;

      return value;
   } else if (leaf->GetValuePointer()) {
      // value types
      Converter *pcnv = CreateConverter(leaf->GetTypeName());
      PyObject *value = 0;
      if (leaf->IsA() == TLeafElement::Class() || leaf->IsA() == TLeafObject::Class())
         value = pcnv->FromMemory((void *)*(void **)leaf->GetValuePointer());
      else
         value = pcnv->FromMemory((void *)leaf->GetValuePointer());
      delete pcnv;

      return value;
   }

   return nullptr;
}

// Allow access to branches/leaves as if they were data members
PyObject *GetAttr(const CPPInstance *self, PyObject *pyname)
{
   const char *name_possibly_alias = CPyCppyy_PyUnicode_AsString(pyname);
   if (!name_possibly_alias)
      return 0;

   // get hold of actual tree
   TTree *tree = (TTree *)GetClass(self)->DynamicCast(TTree::Class(), self->GetObject());

   if (!tree) {
      PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer");
      return 0;
   }

   // deal with possible aliasing
   const char *name = tree->GetAlias(name_possibly_alias);
   if (!name)
      name = name_possibly_alias;

   // search for branch first (typical for objects)
   TBranch *branch = SearchForBranch(tree, name);

   if (branch) {
      // found a branched object, wrap its address for the object it represents
      auto proxy = BindBranchToProxy(tree, name, branch);
      if (proxy != nullptr)
         return proxy;
   }

   // if not, try leaf
   TLeaf *leaf = SearchForLeaf(tree, name, branch);

   if (leaf) {
      // found a leaf, extract value and wrap with a Python object according to its type
      auto wrapper = WrapLeaf(leaf);
      if (wrapper != nullptr)
         return wrapper;
   }

   // confused
   PyErr_Format(PyExc_AttributeError, "\'%s\' object has no attribute \'%s\'", tree->IsA()->GetName(), name);
   return 0;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Allow branches to be accessed as attributes of a tree.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Allow access to branches/leaves as if they were Python data attributes of the tree
/// (e.g. mytree.branch)
PyObject *PyROOT::AddBranchAttrSyntax(PyObject * /* self */, PyObject *args)
{
   PyObject *pyclass = PyTuple_GetItem(args, 0);
   Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)GetAttr, METH_O);
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::SetBranchAddress.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of SetBranchAddress so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.SetBranchAddress("my_vector_branch", v)
/// ~~~
PyObject *PyROOT::SetBranchAddressPyz(PyObject * /* self */, PyObject *args)
{
   PyObject *treeObj = nullptr, *name = nullptr, *address = nullptr;

   int argc = PyTuple_GET_SIZE(args);

// Look for the (const char*, void*) overload
#if PY_VERSION_HEX < 0x03000000
   auto argParseStr = "OSO:SetBranchAddress";
#else
   auto argParseStr = "OUO:SetBranchAddress";
#endif
   if (argc == 3 && PyArg_ParseTuple(args, const_cast<char *>(argParseStr), &treeObj, &name, &address)) {

      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());

      if (!tree) {
         PyErr_SetString(PyExc_TypeError,
                         "TTree::SetBranchAddress must be called with a TTree instance as first argument");
         return nullptr;
      }

      auto branchName = CPyCppyy_PyUnicode_AsString(name);
      auto branch = tree->GetBranch(branchName);
      if (!branch) {
         PyErr_SetString(PyExc_TypeError, "TTree::SetBranchAddress must be called with a valid branch name");
         return nullptr;
      }

      bool isLeafList = branch->IsA() == TBranch::Class();

      void *buf = 0;
      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference || isLeafList)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;
      } else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf != nullptr) {
         auto res = tree->SetBranchAddress(CPyCppyy_PyUnicode_AsString(name), buf);
         return PyInt_FromLong(res);
      }
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// Try to match the arguments of TTree::Branch to the following overload:
/// - ( const char*, void*, const char*, Int_t = 32000 )
/// If the match succeeds, invoke Branch on the C++ tree with the right
/// arguments.
PyObject *TryBranchLeafListOverload(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *address = nullptr, *leaflist = nullptr, *bufsize = nullptr;

   if (PyArg_ParseTuple(args, const_cast<char *>("OO!OO!|O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &address,
                        &CPyCppyy_PyUnicode_Type, &leaflist,
                        &PyInt_Type, &bufsize)) {

      auto treeProxy = (CPPInstance *)treeObj;
      auto tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      void *buf = nullptr;
      if (CPPInstance_Check(address))
         buf = (void *)((CPPInstance *)address)->GetObject();
      else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf) {
         TBranch *branch = nullptr;
         if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist),
                                  PyInt_AS_LONG(bufsize));
         } else {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }
   PyErr_Clear();

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// Try to match the arguments of TTree::Branch to one of the following
/// overloads:
/// - ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
/// - ( const char*,              T**, Int_t = 32000, Int_t = 99 )
/// If the match succeeds, invoke Branch on the C++ tree with the right
/// arguments.
PyObject *TryBranchPtrToPtrOverloads(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *clName = nullptr, *address = nullptr, *bufsize = nullptr, *splitlevel = nullptr;

   auto bIsMatch = false;
   if (PyArg_ParseTuple(args, const_cast<char *>("OO!O!O|O!O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &CPyCppyy_PyUnicode_Type, &clName,
                        &address,
                        &PyInt_Type, &bufsize,
                        &PyInt_Type, &splitlevel)) {
      bIsMatch = true;
   } else {
      PyErr_Clear();
      if (PyArg_ParseTuple(args, const_cast<char *>("OO!O|O!O!"),
                           &treeObj,
                           &CPyCppyy_PyUnicode_Type, &name,
                           &address,
                           &PyInt_Type, &bufsize,
                           &PyInt_Type, &splitlevel)) {
         bIsMatch = true;
      } else {
         PyErr_Clear();
      }
   }

   if (bIsMatch) {
      auto treeProxy = (CPPInstance *)treeObj;
      auto tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      std::string klName = clName ? CPyCppyy_PyUnicode_AsString(clName) : "";
      void *buf = nullptr;

      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;

         if (!clName) {
            klName = GetClass((CPPInstance *)address)->GetName();
            argc += 1;
         }
      } else {
         Utility::GetBuffer(address, '*', 1, buf, false);
      }

      if (buf && !klName.empty()) {
         TBranch *branch = nullptr;
         if (argc == 4) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf);
         } else if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize));
         } else if (argc == 6) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize),
                                  PyInt_AS_LONG(splitlevel));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::Branch.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of Branch so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.Branch('my_vector_branch', v)
/// ~~~
PyObject *PyROOT::BranchPyz(PyObject * /* self */, PyObject *args)
{
   // Acceptable signatures:
   // ( const char*, void*, const char*, Int_t = 32000 )
   // ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
   // ( const char*, T**, Int_t = 32000, Int_t = 99 )

   int argc = PyTuple_GET_SIZE(args);

   if (argc >= 3) { // We count the TTree proxy object too
      auto branch = TryBranchLeafListOverload(argc, args);
      if (branch != Py_None)
         return branch;

      branch = TryBranchPtrToPtrOverloads(argc, args);
      if (branch != Py_None)
         return branch;
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}
<commit_msg>[Exp PyROOT] Move comment into doxygen documentation<commit_after>
// Bindings
#include "CPyCppyy.h"
#include "PyROOTPythonize.h"
#include "CPPInstance.h"
#include "ProxyWrappers.h"
#include "Converters.h"
#include "Utility.h"

// ROOT
#include "TClass.h"
#include "TTree.h"
#include "TBranch.h"
#include "TBranchElement.h"
#include "TBranchObject.h"
#include "TLeaf.h"
#include "TLeafElement.h"
#include "TLeafObject.h"
#include "TStreamerElement.h"
#include "TStreamerInfo.h"

using namespace CPyCppyy;

static TClass *GetClass(const CPPInstance *pyobj)
{
   return TClass::GetClass(Cppyy::GetFinalName(pyobj->ObjectIsA()).c_str());
}

static TBranch *SearchForBranch(TTree *tree, const char *name)
{
   TBranch *branch = tree->GetBranch(name);
   if (!branch) {
      // for benefit of naming of sub-branches, the actual name may have a trailing '.'
      branch = tree->GetBranch((std::string(name) + '.').c_str());
   }
   return branch;
}

static TLeaf *SearchForLeaf(TTree *tree, const char *name, TBranch *branch)
{
   TLeaf *leaf = tree->GetLeaf(name);
   if (branch && !leaf) {
      leaf = branch->GetLeaf(name);
      if (!leaf) {
         TObjArray *leaves = branch->GetListOfLeaves();
         if (leaves->GetSize() && (leaves->First() == leaves->Last())) {
            // i.e., if unambiguously only this one
            leaf = (TLeaf *)leaves->At(0);
         }
      }
   }
   return leaf;
}

static PyObject *BindBranchToProxy(TTree *tree, const char *name, TBranch *branch)
{
   // for partial return of a split object
   if (branch->InheritsFrom(TBranchElement::Class())) {
      TBranchElement *be = (TBranchElement *)branch;
      if (be->GetCurrentClass() && (be->GetCurrentClass() != be->GetTargetClass()) && (0 <= be->GetID())) {
         Long_t offset = ((TStreamerElement *)be->GetInfo()->GetElements()->At(be->GetID()))->GetOffset();
         return BindCppObjectNoCast(be->GetObject() + offset, Cppyy::GetScope(be->GetCurrentClass()->GetName()));
      }
   }

   // for return of a full object
   if (branch->IsA() == TBranchElement::Class() || branch->IsA() == TBranchObject::Class()) {
      TClass *klass = TClass::GetClass(branch->GetClassName());
      if (klass && branch->GetAddress())
         return BindCppObjectNoCast(*(void **)branch->GetAddress(), Cppyy::GetScope(branch->GetClassName()));

      // try leaf, otherwise indicate failure by returning a typed null-object
      TObjArray *leaves = branch->GetListOfLeaves();
      if (klass && !tree->GetLeaf(name) && !(leaves->GetSize() && (leaves->First() == leaves->Last())))
         return BindCppObjectNoCast(nullptr, Cppyy::GetScope(branch->GetClassName()));
   }

   return nullptr;
}

static PyObject *WrapLeaf(TLeaf *leaf)
{
   if (1 < leaf->GetLenStatic() || leaf->GetLeafCount()) {
      // array types
      std::string typeName = leaf->GetTypeName();
      Converter *pcnv = CreateConverter(typeName + '*', leaf->GetNdata());

      void *address = 0;
      if (leaf->GetBranch())
         address = (void *)leaf->GetBranch()->GetAddress();
      if (!address)
         address = (void *)leaf->GetValuePointer();

      PyObject *value = pcnv->FromMemory(&address);
      delete pcnv;

      return value;
   } else if (leaf->GetValuePointer()) {
      // value types
      Converter *pcnv = CreateConverter(leaf->GetTypeName());
      PyObject *value = 0;
      if (leaf->IsA() == TLeafElement::Class() || leaf->IsA() == TLeafObject::Class())
         value = pcnv->FromMemory((void *)*(void **)leaf->GetValuePointer());
      else
         value = pcnv->FromMemory((void *)leaf->GetValuePointer());
      delete pcnv;

      return value;
   }

   return nullptr;
}

// Allow access to branches/leaves as if they were data members
PyObject *GetAttr(const CPPInstance *self, PyObject *pyname)
{
   const char *name_possibly_alias = CPyCppyy_PyUnicode_AsString(pyname);
   if (!name_possibly_alias)
      return 0;

   // get hold of actual tree
   TTree *tree = (TTree *)GetClass(self)->DynamicCast(TTree::Class(), self->GetObject());

   if (!tree) {
      PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer");
      return 0;
   }

   // deal with possible aliasing
   const char *name = tree->GetAlias(name_possibly_alias);
   if (!name)
      name = name_possibly_alias;

   // search for branch first (typical for objects)
   TBranch *branch = SearchForBranch(tree, name);

   if (branch) {
      // found a branched object, wrap its address for the object it represents
      auto proxy = BindBranchToProxy(tree, name, branch);
      if (proxy != nullptr)
         return proxy;
   }

   // if not, try leaf
   TLeaf *leaf = SearchForLeaf(tree, name, branch);

   if (leaf) {
      // found a leaf, extract value and wrap with a Python object according to its type
      auto wrapper = WrapLeaf(leaf);
      if (wrapper != nullptr)
         return wrapper;
   }

   // confused
   PyErr_Format(PyExc_AttributeError, "\'%s\' object has no attribute \'%s\'", tree->IsA()->GetName(), name);
   return 0;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Allow branches to be accessed as attributes of a tree.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Allow access to branches/leaves as if they were Python data attributes of the tree
/// (e.g. mytree.branch)
PyObject *PyROOT::AddBranchAttrSyntax(PyObject * /* self */, PyObject *args)
{
   PyObject *pyclass = PyTuple_GetItem(args, 0);
   Utility::AddToClass(pyclass, "__getattr__", (PyCFunction)GetAttr, METH_O);
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::SetBranchAddress.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of SetBranchAddress so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.SetBranchAddress("my_vector_branch", v)
/// ~~~
PyObject *PyROOT::SetBranchAddressPyz(PyObject * /* self */, PyObject *args)
{
   PyObject *treeObj = nullptr, *name = nullptr, *address = nullptr;

   int argc = PyTuple_GET_SIZE(args);

// Look for the (const char*, void*) overload
#if PY_VERSION_HEX < 0x03000000
   auto argParseStr = "OSO:SetBranchAddress";
#else
   auto argParseStr = "OUO:SetBranchAddress";
#endif
   if (argc == 3 && PyArg_ParseTuple(args, const_cast<char *>(argParseStr), &treeObj, &name, &address)) {

      auto treeProxy = (CPPInstance *)treeObj;
      TTree *tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());

      if (!tree) {
         PyErr_SetString(PyExc_TypeError,
                         "TTree::SetBranchAddress must be called with a TTree instance as first argument");
         return nullptr;
      }

      auto branchName = CPyCppyy_PyUnicode_AsString(name);
      auto branch = tree->GetBranch(branchName);
      if (!branch) {
         PyErr_SetString(PyExc_TypeError, "TTree::SetBranchAddress must be called with a valid branch name");
         return nullptr;
      }

      bool isLeafList = branch->IsA() == TBranch::Class();

      void *buf = 0;
      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference || isLeafList)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;
      } else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf != nullptr) {
         auto res = tree->SetBranchAddress(CPyCppyy_PyUnicode_AsString(name), buf);
         return PyInt_FromLong(res);
      }
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// Try to match the arguments of TTree::Branch to the following overload:
/// - ( const char*, void*, const char*, Int_t = 32000 )
/// If the match succeeds, invoke Branch on the C++ tree with the right
/// arguments.
PyObject *TryBranchLeafListOverload(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *address = nullptr, *leaflist = nullptr, *bufsize = nullptr;

   if (PyArg_ParseTuple(args, const_cast<char *>("OO!OO!|O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &address,
                        &CPyCppyy_PyUnicode_Type, &leaflist,
                        &PyInt_Type, &bufsize)) {

      auto treeProxy = (CPPInstance *)treeObj;
      auto tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      void *buf = nullptr;
      if (CPPInstance_Check(address))
         buf = (void *)((CPPInstance *)address)->GetObject();
      else
         Utility::GetBuffer(address, '*', 1, buf, false);

      if (buf) {
         TBranch *branch = nullptr;
         if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist),
                                  PyInt_AS_LONG(bufsize));
         } else {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), buf, CPyCppyy_PyUnicode_AsString(leaflist));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }
   PyErr_Clear();

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// Try to match the arguments of TTree::Branch to one of the following
/// overloads:
/// - ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
/// - ( const char*,              T**, Int_t = 32000, Int_t = 99 )
/// If the match succeeds, invoke Branch on the C++ tree with the right
/// arguments.
PyObject *TryBranchPtrToPtrOverloads(int argc, PyObject *args)
{
   PyObject *treeObj = nullptr;
   PyObject *name = nullptr, *clName = nullptr, *address = nullptr, *bufsize = nullptr, *splitlevel = nullptr;

   auto bIsMatch = false;
   if (PyArg_ParseTuple(args, const_cast<char *>("OO!O!O|O!O!:Branch"),
                        &treeObj,
                        &CPyCppyy_PyUnicode_Type, &name,
                        &CPyCppyy_PyUnicode_Type, &clName,
                        &address,
                        &PyInt_Type, &bufsize,
                        &PyInt_Type, &splitlevel)) {
      bIsMatch = true;
   } else {
      PyErr_Clear();
      if (PyArg_ParseTuple(args, const_cast<char *>("OO!O|O!O!"),
                           &treeObj,
                           &CPyCppyy_PyUnicode_Type, &name,
                           &address,
                           &PyInt_Type, &bufsize,
                           &PyInt_Type, &splitlevel)) {
         bIsMatch = true;
      } else {
         PyErr_Clear();
      }
   }

   if (bIsMatch) {
      auto treeProxy = (CPPInstance *)treeObj;
      auto tree = (TTree *)GetClass(treeProxy)->DynamicCast(TTree::Class(), treeProxy->GetObject());
      if (!tree) {
         PyErr_SetString(PyExc_TypeError, "TTree::Branch must be called with a TTree instance as first argument");
         return nullptr;
      }

      std::string klName = clName ? CPyCppyy_PyUnicode_AsString(clName) : "";
      void *buf = nullptr;

      if (CPPInstance_Check(address)) {
         if (((CPPInstance *)address)->fFlags & CPPInstance::kIsReference)
            buf = (void *)((CPPInstance *)address)->fObject;
         else
            buf = (void *)&((CPPInstance *)address)->fObject;

         if (!clName) {
            klName = GetClass((CPPInstance *)address)->GetName();
            argc += 1;
         }
      } else {
         Utility::GetBuffer(address, '*', 1, buf, false);
      }

      if (buf && !klName.empty()) {
         TBranch *branch = nullptr;
         if (argc == 4) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf);
         } else if (argc == 5) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize));
         } else if (argc == 6) {
            branch = tree->Branch(CPyCppyy_PyUnicode_AsString(name), klName.c_str(), buf, PyInt_AS_LONG(bufsize),
                                  PyInt_AS_LONG(splitlevel));
         }

         return BindCppObject(branch, Cppyy::GetScope("TBranch"));
      }
   }

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TTree::Branch.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// Modify the behaviour of Branch so that proxy references can be passed
/// as arguments from the Python side, more precisely in cases where the C++
/// implementation of the method expects the address of a pointer.
///
/// For example:
/// ~~~{.python}
/// v = ROOT.std.vector('int')()
/// t.Branch('my_vector_branch', v)
/// ~~~
///
/// The following signatures are treated in this pythonization:
/// - ( const char*, void*, const char*, Int_t = 32000 )
/// - ( const char*, const char*, T**, Int_t = 32000, Int_t = 99 )
/// - ( const char*, T**, Int_t = 32000, Int_t = 99 )
PyObject *PyROOT::BranchPyz(PyObject * /* self */, PyObject *args)
{
   int argc = PyTuple_GET_SIZE(args);

   if (argc >= 3) { // We count the TTree proxy object too
      auto branch = TryBranchLeafListOverload(argc, args);
      if (branch != Py_None)
         return branch;

      branch = TryBranchPtrToPtrOverloads(argc, args);
      if (branch != Py_None)
         return branch;
   }

   // Not the overload we wanted to pythonize, return None
   Py_RETURN_NONE;
}
<|endoftext|>


<commit_before>#include <cxxabi.h>

void __cxxabiv1::__cxa_pure_virtual() {
  while (true);
}
<commit_msg>k/cxxabi: add memset for ctors.<commit_after>#include <cxxabi.h>
#include <cstdint>
#include <cstring>

void __cxxabiv1::__cxa_pure_virtual() {
  while (true);
}

void * memset(void * s, int c, size_t n) {
  auto s8 = static_cast<uint8_t *>(s);
  for (size_t i = 0; i < n; ++i) {
    s8[i] = uint8_t(c);
  }
  return s;
}
<|endoftext|>