<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

Bohrium 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 General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#include <bh.h>
#include <bh_dag.h>
#include <bh_fuse_cache.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/range/adaptors.hpp>
#include <vector>
#include <map>
#include <iterator>
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>

#define VERBOSE

using namespace std;
using namespace boost;
using namespace bohrium;
using namespace bohrium::dag;

/* Help function that fuses the edges in 'edges2explore' where the 'mask' is true */
pair<int64_t,bool> fuse_mask(int64_t best_cost, const vector<EdgeW> &edges2explore,
                             const GraphDW &graph, const vector<bool> &mask, bh_ir &bhir,
                             GraphD &dag)
{
    bool fusibility=true;
    vector<EdgeW> edges2merge;
    unsigned int i=0;
    BOOST_FOREACH(const EdgeW &e, edges2explore)
    {
        if(mask[i++])
            edges2merge.push_back(e);
    }

    //Help function to find the new location
    struct find_new_location
    {
        Vertex operator()(const map<Vertex, Vertex> &loc_map, Vertex v)
        {
            Vertex v_mapped = loc_map.at(v);
            if(v_mapped == v)
                return v;
            else
                return (*this)(loc_map, v_mapped);
        }
    }find_loc;

    //'loc_map' maps a vertex before the merge to the corresponding vertex after the merge
    map<Vertex, Vertex> loc_map;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        loc_map[v] = v;
    }

    //Lets record the merges into 'loc_map'
    BOOST_FOREACH(const EdgeW &e, edges2merge)
    {
        Vertex v1 = find_loc(loc_map, source(e, graph.bglW()));
        Vertex v2 = find_loc(loc_map, target(e, graph.bglW()));
        loc_map[v1] = v2;
    }

    //Pack 'loc_map' such that all keys maps directly to a new vertex thus after
    //this point there is no need to call find_loc().
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        Vertex v_mapped = find_loc(loc_map, loc_map.at(v));
        if(v_mapped != v)
            loc_map[v] = v_mapped;
    }

    //Create the new vertices and insert instruction topologically
    map<Vertex, bh_ir_kernel> new_vertices;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map.at(v) == v)
            new_vertices[v] = bh_ir_kernel(bhir);
    }
    vector<Vertex> topological_order;
    topological_sort(dag, back_inserter(topological_order));
    BOOST_REVERSE_FOREACH(Vertex vertex, topological_order)
    {
        Vertex v = loc_map.at(vertex);
        bh_ir_kernel &k = new_vertices.at(v);
        BOOST_FOREACH(uint64_t idx, dag[vertex].instr_indexes)
        {
            if(not k.fusible(idx))
                fusibility = false;
            k.add_instr(idx);
        }
    }

    //TODO: Remove this assert check
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map.at(v) == v)
            assert(new_vertices[v].instr_indexes.size() > 0);
    }

    //Find the total cost
    int64_t cost=0;
    BOOST_FOREACH(const bh_ir_kernel &k, new_vertices | adaptors::map_values)
    {
        cost += k.cost();
    }

    //Check if we need to continue
    if(cost >= best_cost or not fusibility)
        return make_pair(cost,false);

    //Merge the vertice in the DAG
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        Vertex loc_v = loc_map.at(v);
        if(loc_v == v)
        {
            dag[v] = new_vertices.at(v);
            assert(dag[v].instr_indexes.size() > 0);
        }
        else//Lets merge 'v' into 'loc_v'
        {
            BOOST_FOREACH(Vertex a, adjacent_vertices(v, dag))
            {
                a = loc_map.at(a);
                if(a != loc_v)
                    add_edge(loc_v, a, dag);
            }
            BOOST_FOREACH(Vertex a, inv_adjacent_vertices(v, dag))
            {
                a = loc_map.at(a);
                if(a != loc_v)
                    add_edge(a, loc_v, dag);
            }
            clear_vertex(v, dag);
            dag[v] = bh_ir_kernel(bhir);
        }
    }

    //TODO: remove assert check
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(dag[loc_map.at(v)].instr_indexes.size() == 0)
        {
            cout << v << endl;
            cout << loc_map.at(v) << endl;
            assert(1 == 2);
        }
    }

    //Check for cycles
    if(cycles(dag))
    {
        return make_pair(cost,false);
    }

    assert(cost == (int64_t)dag_cost(dag));
    return make_pair(cost,true);
}

#ifdef VERBOSE
int fuser_count=0;
#endif

/* Private class to find the optimal solution through branch and bound */
class Solver
{
public:
    bh_ir &bhir;
    const GraphDW &dag;
    const vector<EdgeW> &edges2explore;
    int64_t best_cost;
    int64_t one_cost;
    GraphD best_dag;
    FuseCache cache;

    #ifdef VERBOSE
        double  purge_count;
        uint64_t explore_count;
    #endif

    /* The constructor */
    Solver(bh_ir &b, const GraphDW &d, const vector<EdgeW> &e, FuseCache &cache):
           bhir(b),dag(d),edges2explore(e), cache(cache)
    {
        //Wwe use the greedy algorithm to find a good initial guess
        GraphDW new_dag(dag);
        fuse_greedy(new_dag);
        best_dag = new_dag.bglD();
        best_cost = dag_cost(best_dag);

        #ifdef VERBOSE
            purge_count=0;
            explore_count=0;
        #endif
    }

    /* Find the optimal solution through branch and bound */
    void branch_n_bound(vector<bool> mask, unsigned int offset, bool merge_next)
    {
        if(not merge_next)
        {
            GraphD new_dag(dag.bglD());
            mask[offset] = merge_next;
            bool fusibility;
            int64_t cost;
            tie(cost, fusibility) = fuse_mask(best_cost, edges2explore, dag, mask, bhir, new_dag);

            #ifdef VERBOSE
                if(explore_count%1000 == 0)
                {
                    cout << "[" << explore_count << "] " << "purge count: ";
                    cout << purge_count << " / " << pow(2.0,mask.size()) << endl;
                    cout << "cost: " << cost << ", best_cost: " << best_cost;
                    cout << ", fusibility: " << fusibility << endl;
                }
                ++explore_count;
            #endif

            if(cost >= best_cost)
            {
                #ifdef VERBOSE
                    purge_count += pow(2.0, mask.size()-offset-1);
                #endif
                return;
            }
            if(fusibility)
            {
                //Lets save the new best dag
                best_cost = cost;
                best_dag = new_dag;
                assert(dag_validate(best_dag));

                //Lets write the current best to file
                vector<bh_ir_kernel> kernel_list;
                fill_kernel_list(best_dag, kernel_list);
                const InstrIndexesList &i = cache.insert(bhir.instr_list, kernel_list);
                cache.write_to_files();

                #ifdef VERBOSE
                    stringstream ss;
                    string filename;
                    i.get_filename(filename);
                    ss << "new_best_dag-" << filename << ".dot";
                    cout << "write file: " << ss.str() << endl;
                    pprint(GraphDW(new_dag), ss.str().c_str());
                    purge_count += pow(2.0, mask.size()-offset-1);
                #endif
                return;
            }
        }
        if(offset+1 < mask.size())
        {
            branch_n_bound(mask, offset+1, false);
            branch_n_bound(mask, offset+1, true);
        }
    }
};

/* Fuse the 'dag' optimally */
void fuse_optimal(bh_ir &bhir, const GraphDW &dag, GraphD &output, FuseCache &cache)
{
    //The list of edges that we should try to merge
    vector<EdgeW> edges2explore;
    BOOST_FOREACH(const EdgeW &e, edges(dag.bglW()))
    {
        edges2explore.push_back(e);
    }
    sort_weights(dag.bglW(), edges2explore);
    //reverse(edges2explore.begin(), edges2explore.end());

    if(edges2explore.size() == 0)
    {
        return;
    }

    //First we check the trivial case where all kernels are merged
    vector<bool> mask(edges2explore.size(), true);
    {
        GraphD new_dag(dag.bglD());
        bool fuse = fuse_mask(numeric_limits<int64_t>::max(), edges2explore,
                                        dag, mask, bhir, new_dag).second;
        if(fuse)
        {
            output = new_dag;
            return;
        }
    }

    Solver solver(bhir, dag, edges2explore, cache);
    if(mask.size() > 100)
    {
        cout << "FUSER-OPTIMAL: ABORT the size of the search space is too large: 2^";
        cout << mask.size() << "!" << endl;
    }
    else
    {
        cout << "FUSER-OPTIMAL: the size of the search space is 2^" << mask.size() << "!" << endl;
        solver.branch_n_bound(mask, 0, false);
        solver.branch_n_bound(mask, 0, true);
    }
    output = solver.best_dag;
}

void timer_handler(int signum)
{
    cout << "ABORT! - timeout" << endl;
    exit(-1);
}
void set_abort_timer()
{
    const char *bh_fuser_timeout = getenv("BH_FUSER_TIMEOUT");
    if(bh_fuser_timeout == NULL)
        return;
    long int timeout = strtol(bh_fuser_timeout, NULL, 10);
    cout << "[ABORT] Fuse-Abort timeout is " << timeout << " sec" << endl;

    struct sigaction sa;
    struct itimerval timer;

    memset(&sa, 0, sizeof(sa));

    sa.sa_handler = &timer_handler;
    sigaction(SIGALRM, &sa, NULL);

    timer.it_value.tv_sec = timeout;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 100000;

    setitimer (ITIMER_REAL, &timer, NULL);
}

void do_fusion(bh_ir &bhir, FuseCache &cache)
{
#ifdef VERBOSE
    ++fuser_count;
#endif
    set_abort_timer();

    GraphDW dag;
    from_bhir(bhir, dag);
    fuse_gentle(dag);
    dag.transitive_reduction();
    assert(dag_validate(dag.bglD()));

    GraphD output;
    fuse_optimal(bhir, dag, output, cache);
    if(num_vertices(output) == 0)
        output = dag.bglD();

    assert(dag_validate(output));
    fill_kernel_list(output, bhir.kernel_list);
}

void fuser(bh_ir &bhir, FuseCache &cache)
{
    if(bhir.kernel_list.size() != 0)
        throw logic_error("The kernel_list is not empty!");

    BatchHash batch(bhir.instr_list);
    if(not cache.lookup(batch, bhir, bhir.kernel_list))
    {
        do_fusion(bhir, cache);
        cache.insert(batch, bhir.kernel_list);
    }
}

<commit_msg>optimal-fuser: now accepts BH_FUSER_OPTIMAL_ORDER<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

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

Bohrium 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 General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/
#include <bh.h>
#include <bh_dag.h>
#include <bh_fuse_cache.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/algorithm/string/predicate.hpp> //For iequals()
#include <boost/range/adaptors.hpp>
#include <vector>
#include <map>
#include <iterator>
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>

#define VERBOSE

using namespace std;
using namespace boost;
using namespace bohrium;
using namespace bohrium::dag;

/* Help function that fuses the edges in 'edges2explore' where the 'mask' is true */
pair<int64_t,bool> fuse_mask(int64_t best_cost, const vector<EdgeW> &edges2explore,
                             const GraphDW &graph, const vector<bool> &mask, bh_ir &bhir,
                             GraphD &dag)
{
    bool fusibility=true;
    vector<EdgeW> edges2merge;
    unsigned int i=0;
    BOOST_FOREACH(const EdgeW &e, edges2explore)
    {
        if(mask[i++])
            edges2merge.push_back(e);
    }

    //Help function to find the new location
    struct find_new_location
    {
        Vertex operator()(const map<Vertex, Vertex> &loc_map, Vertex v)
        {
            Vertex v_mapped = loc_map.at(v);
            if(v_mapped == v)
                return v;
            else
                return (*this)(loc_map, v_mapped);
        }
    }find_loc;

    //'loc_map' maps a vertex before the merge to the corresponding vertex after the merge
    map<Vertex, Vertex> loc_map;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        loc_map[v] = v;
    }

    //Lets record the merges into 'loc_map'
    BOOST_FOREACH(const EdgeW &e, edges2merge)
    {
        Vertex v1 = find_loc(loc_map, source(e, graph.bglW()));
        Vertex v2 = find_loc(loc_map, target(e, graph.bglW()));
        loc_map[v1] = v2;
    }

    //Pack 'loc_map' such that all keys maps directly to a new vertex thus after
    //this point there is no need to call find_loc().
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        Vertex v_mapped = find_loc(loc_map, loc_map.at(v));
        if(v_mapped != v)
            loc_map[v] = v_mapped;
    }

    //Create the new vertices and insert instruction topologically
    map<Vertex, bh_ir_kernel> new_vertices;
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map.at(v) == v)
            new_vertices[v] = bh_ir_kernel(bhir);
    }
    vector<Vertex> topological_order;
    topological_sort(dag, back_inserter(topological_order));
    BOOST_REVERSE_FOREACH(Vertex vertex, topological_order)
    {
        Vertex v = loc_map.at(vertex);
        bh_ir_kernel &k = new_vertices.at(v);
        BOOST_FOREACH(uint64_t idx, dag[vertex].instr_indexes)
        {
            if(not k.fusible(idx))
                fusibility = false;
            k.add_instr(idx);
        }
    }

    //TODO: Remove this assert check
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(loc_map.at(v) == v)
            assert(new_vertices[v].instr_indexes.size() > 0);
    }

    //Find the total cost
    int64_t cost=0;
    BOOST_FOREACH(const bh_ir_kernel &k, new_vertices | adaptors::map_values)
    {
        cost += k.cost();
    }

    //Check if we need to continue
    if(cost >= best_cost or not fusibility)
        return make_pair(cost,false);

    //Merge the vertice in the DAG
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        Vertex loc_v = loc_map.at(v);
        if(loc_v == v)
        {
            dag[v] = new_vertices.at(v);
            assert(dag[v].instr_indexes.size() > 0);
        }
        else//Lets merge 'v' into 'loc_v'
        {
            BOOST_FOREACH(Vertex a, adjacent_vertices(v, dag))
            {
                a = loc_map.at(a);
                if(a != loc_v)
                    add_edge(loc_v, a, dag);
            }
            BOOST_FOREACH(Vertex a, inv_adjacent_vertices(v, dag))
            {
                a = loc_map.at(a);
                if(a != loc_v)
                    add_edge(a, loc_v, dag);
            }
            clear_vertex(v, dag);
            dag[v] = bh_ir_kernel(bhir);
        }
    }

    //TODO: remove assert check
    BOOST_FOREACH(Vertex v, vertices(dag))
    {
        if(dag[loc_map.at(v)].instr_indexes.size() == 0)
        {
            cout << v << endl;
            cout << loc_map.at(v) << endl;
            assert(1 == 2);
        }
    }

    //Check for cycles
    if(cycles(dag))
    {
        return make_pair(cost,false);
    }

    assert(cost == (int64_t)dag_cost(dag));
    return make_pair(cost,true);
}

#ifdef VERBOSE
int fuser_count=0;
#endif

/* Private class to find the optimal solution through branch and bound */
class Solver
{
public:
    bh_ir &bhir;
    const GraphDW &dag;
    const vector<EdgeW> &edges2explore;
    int64_t best_cost;
    int64_t one_cost;
    GraphD best_dag;
    FuseCache cache;

    #ifdef VERBOSE
        double  purge_count;
        uint64_t explore_count;
    #endif

    /* The constructor */
    Solver(bh_ir &b, const GraphDW &d, const vector<EdgeW> &e, FuseCache &cache):
           bhir(b),dag(d),edges2explore(e), cache(cache)
    {
        //Wwe use the greedy algorithm to find a good initial guess
        GraphDW new_dag(dag);
        fuse_greedy(new_dag);
        best_dag = new_dag.bglD();
        best_cost = dag_cost(best_dag);

        #ifdef VERBOSE
            purge_count=0;
            explore_count=0;
        #endif
    }

    /* Find the optimal solution through branch and bound */
    void branch_n_bound(vector<bool> mask, unsigned int offset, bool merge_next)
    {
        if(not merge_next)
        {
            GraphD new_dag(dag.bglD());
            mask[offset] = merge_next;
            bool fusibility;
            int64_t cost;
            tie(cost, fusibility) = fuse_mask(best_cost, edges2explore, dag, mask, bhir, new_dag);

            #ifdef VERBOSE
                if(explore_count%1000 == 0)
                {
                    cout << "[" << explore_count << "] " << "purge count: ";
                    cout << purge_count << " / " << pow(2.0,mask.size()) << endl;
                    cout << "cost: " << cost << ", best_cost: " << best_cost;
                    cout << ", fusibility: " << fusibility << endl;
                }
                ++explore_count;
            #endif

            if(cost >= best_cost)
            {
                #ifdef VERBOSE
                    purge_count += pow(2.0, mask.size()-offset-1);
                #endif
                return;
            }
            if(fusibility)
            {
                //Lets save the new best dag
                best_cost = cost;
                best_dag = new_dag;
                assert(dag_validate(best_dag));

                //Lets write the current best to file
                vector<bh_ir_kernel> kernel_list;
                fill_kernel_list(best_dag, kernel_list);
                const InstrIndexesList &i = cache.insert(bhir.instr_list, kernel_list);
                cache.write_to_files();

                #ifdef VERBOSE
                    stringstream ss;
                    string filename;
                    i.get_filename(filename);
                    ss << "new_best_dag-" << filename << ".dot";
                    cout << "write file: " << ss.str() << endl;
                    pprint(GraphDW(new_dag), ss.str().c_str());
                    purge_count += pow(2.0, mask.size()-offset-1);
                #endif
                return;
            }
        }
        if(offset+1 < mask.size())
        {
            branch_n_bound(mask, offset+1, false);
            branch_n_bound(mask, offset+1, true);
        }
    }
};

void get_edges2explore(const GraphDW &dag, vector<EdgeW> &edges2explore)
{
    BOOST_FOREACH(const EdgeW &e, edges(dag.bglW()))
    {
        edges2explore.push_back(e);
    }
    sort_weights(dag.bglW(), edges2explore);
    string order;
    {
        const char *t = getenv("BH_FUSER_OPTIMAL_ORDER");
        if(t == NULL)
            order ="regular";
        else
            order = t;
    }
    if(not iequals(order, "regular"))
    {
        if(iequals(order, "reverse"))
        {
            reverse(edges2explore.begin(), edges2explore.end());
        }
        else if(iequals(order, "random"))
        {
            random_shuffle(edges2explore.begin(), edges2explore.end());
        }
        else
        {
            cerr << "FUSER-OPTIMAL: unknown BH_FUSER_OPTIMAL_ORDER: " << order << endl;
            order = "regular";
        }
    }
    cout << "BH_FUSER_OPTIMAL_ORDER: " << order << endl;
}

/* Fuse the 'dag' optimally */
void fuse_optimal(bh_ir &bhir, const GraphDW &dag, GraphD &output, FuseCache &cache)
{
    //The list of edges that we should try to merge
    vector<EdgeW> edges2explore;
    get_edges2explore(dag, edges2explore);
    if(edges2explore.size() == 0)
        return;

    //First we check the trivial case where all kernels are merged
    vector<bool> mask(edges2explore.size(), true);
    {
        GraphD new_dag(dag.bglD());
        bool fuse = fuse_mask(numeric_limits<int64_t>::max(), edges2explore,
                                        dag, mask, bhir, new_dag).second;
        if(fuse)
        {
            output = new_dag;
            return;
        }
    }

    Solver solver(bhir, dag, edges2explore, cache);
    if(mask.size() > 100)
    {
        cout << "FUSER-OPTIMAL: ABORT the size of the search space is too large: 2^";
        cout << mask.size() << "!" << endl;
    }
    else
    {
        cout << "FUSER-OPTIMAL: the size of the search space is 2^" << mask.size() << "!" << endl;
        solver.branch_n_bound(mask, 0, false);
        solver.branch_n_bound(mask, 0, true);
    }
    output = solver.best_dag;
}

void timer_handler(int signum)
{
    cout << "ABORT! - timeout" << endl;
    exit(-1);
}
void set_abort_timer()
{
    const char *bh_fuser_timeout = getenv("BH_FUSER_TIMEOUT");
    if(bh_fuser_timeout == NULL)
        return;
    long int timeout = strtol(bh_fuser_timeout, NULL, 10);
    cout << "[ABORT] Fuse-Abort timeout is " << timeout << " sec" << endl;

    struct sigaction sa;
    struct itimerval timer;

    memset(&sa, 0, sizeof(sa));

    sa.sa_handler = &timer_handler;
    sigaction(SIGALRM, &sa, NULL);

    timer.it_value.tv_sec = timeout;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 100000;

    setitimer (ITIMER_REAL, &timer, NULL);
}

void do_fusion(bh_ir &bhir, FuseCache &cache)
{
#ifdef VERBOSE
    ++fuser_count;
#endif
    set_abort_timer();

    GraphDW dag;
    from_bhir(bhir, dag);
    fuse_gentle(dag);
    dag.transitive_reduction();
    assert(dag_validate(dag.bglD()));

    GraphD output;
    fuse_optimal(bhir, dag, output, cache);
    if(num_vertices(output) == 0)
        output = dag.bglD();

    assert(dag_validate(output));
    fill_kernel_list(output, bhir.kernel_list);
}

void fuser(bh_ir &bhir, FuseCache &cache)
{
    if(bhir.kernel_list.size() != 0)
        throw logic_error("The kernel_list is not empty!");

    BatchHash batch(bhir.instr_list);
    if(not cache.lookup(batch, bhir, bhir.kernel_list))
    {
        do_fusion(bhir, cache);
        cache.insert(batch, bhir.kernel_list);
    }
}

<|endoftext|>


<commit_before>#include "Slider.h"
#include "Game.h"

namespace gameplay
{

// Fraction of slider to scroll when mouse scrollwheel is used.
static const float SCROLLWHEEL_FRACTION = 0.1f;
// Fraction of slider to scroll for a delta of 1.0f when a gamepad or keyboard is used.
static const float MOVE_FRACTION = 0.005f;

Slider::Slider() : _min(0.0f), _max(0.0f), _step(0.0f), _value(0.0f), _delta(0.0f), _minImage(NULL),
    _maxImage(NULL), _trackImage(NULL), _markerImage(NULL), _valueTextVisible(false),
    _valueTextAlignment(Font::ALIGN_BOTTOM_HCENTER), _valueTextPrecision(0), _valueText(L""),
    _trackHeight(0.0f), _gamepadValue(0.0f)
{
    _canFocus = true;
}

Slider::~Slider()
{
}

Slider* Slider::create(const char* id, Theme::Style* style)
{
    Slider* slider = new Slider();
    slider->_id = id ? id : "";
    slider->initialize("Slider", style, NULL);
    return slider;
}

Control* Slider::create(Theme::Style* style, Properties* properties)
{
    Slider* slider = new Slider();
    slider->initialize("Slider", style, properties);
    return slider;
}

void Slider::initialize(const char* typeName, Theme::Style* style, Properties* properties)
{
    Label::initialize(typeName, style, properties);

    if (properties)
    {
        _min = properties->getFloat("min");
        _max = properties->getFloat("max");
        _value = properties->getFloat("value");
        _step = properties->getFloat("step");
        _valueTextVisible = properties->getBool("valueTextVisible");
        _valueTextPrecision = properties->getInt("valueTextPrecision");

        if (properties->exists("valueTextAlignment"))
        {
            _valueTextAlignment = Font::getJustify(properties->getString("valueTextAlignment"));
        }
    }

    // Force value text to be updated
    setValue(_value);
}

void Slider::setMin(float min)
{
    _min = min;
}

float Slider::getMin() const
{
    return _min;
}

void Slider::setMax(float max)
{
    _max = max;
}

float Slider::getMax() const
{
    return _max;
}

void Slider::setStep(float step)
{
    _step = step;
}

float Slider::getStep() const
{
    return _step;
}

float Slider::getValue() const
{
    return _value;
}

void Slider::setValue(float value)
{
    value = MATH_CLAMP(value, _min, _max);

    if (value != _value)
    {
        _value = value;
        notifyListeners(Control::Listener::VALUE_CHANGED);
    }

    // Always update value text if it's visible
    if (_valueTextVisible)
    {
        wchar_t s[32];
        swprintf(s, 32, L"%.*f", _valueTextPrecision, _value);
        _valueText = s;
    }
}

void Slider::setValueTextVisible(bool valueTextVisible)
{
    if (valueTextVisible != _valueTextVisible)
    {
        _valueTextVisible = valueTextVisible;
        if (_autoSize & AUTO_SIZE_HEIGHT)
            setDirty(DIRTY_BOUNDS);
    }
}

bool Slider::isValueTextVisible() const
{
    return _valueTextVisible;
}

void Slider::setValueTextAlignment(Font::Justify alignment)
{
    _valueTextAlignment = alignment;
}

Font::Justify Slider::getValueTextAlignment() const
{
    return _valueTextAlignment;
}

void Slider::setValueTextPrecision(unsigned int precision)
{
    _valueTextPrecision = precision;
}

unsigned int Slider::getValueTextPrecision() const
{
    return _valueTextPrecision;
}

void Slider::addListener(Control::Listener* listener, int eventFlags)
{
    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
    {
        GP_ERROR("TEXT_CHANGED event is not applicable to Slider.");
    }

    Control::addListener(listener, eventFlags);
}

void Slider::updateValue(int x, int y)
{
    State state = getState();

    // Horizontal case.
    const Theme::Border& border = getBorder(state);
    const Theme::Padding& padding = getPadding();
    const Rectangle& minCapRegion = _minImage->getRegion();
    const Rectangle& maxCapRegion = _maxImage->getRegion();
    const Rectangle& markerRegion = _markerImage->getRegion();

    float markerPosition = (x - markerRegion.width * 0.5f) / (_viewportBounds.width - markerRegion.width);

    if (markerPosition > 1.0f)
    {
        markerPosition = 1.0f;
    }
    else if (markerPosition < 0.0f)
    {
        markerPosition = 0.0f;
    }

    float value = (markerPosition * (_max - _min)) + _min;
    if (_step > 0.0f)
    {
        int numSteps = round(value / _step);
        value = _step * numSteps;
    }

    setValue(value);
}

bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
{
    State state = getState();

    switch (evt)
    {
    case Touch::TOUCH_PRESS:
        updateValue(x, y);
        return true;

    case Touch::TOUCH_MOVE:
        if (state == ACTIVE)
        {
            updateValue(x, y);
            return true;
        }
        break;
    }

    return Control::touchEvent(evt, x, y, contactIndex);
}

static bool isScrollable(Container* container)
{
    if (container->getScroll() != Container::SCROLL_NONE)
        return true;

    Container* parent = static_cast<Container*>(container->getParent());
    return parent ? isScrollable(parent) : false;
}

bool Slider::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
{
    switch (evt)
    {
        case Mouse::MOUSE_WHEEL:
        {
            if (hasFocus() && !isScrollable(_parent))
            {
                float total = _max - _min;
                float value = _value + (total * SCROLLWHEEL_FRACTION) * wheelDelta;

                if (_step > 0.0f)
                {
                    int numSteps = round(value / _step);
                    value = _step * numSteps;
                }

                setValue(value);
                return true;
            }
            break;
        }

        default:
            break;
    }

    // Return false to fall through to touch handling
    return false;
}

bool Slider::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
{
    switch (evt)
    {
        case Gamepad::JOYSTICK_EVENT:
        {
            // The right analog stick can be used to change a slider's value.
            if (analogIndex == 1)
            {
                Vector2 joy;
                gamepad->getJoystickValues(analogIndex, &joy);
                _gamepadValue = _value;
                _delta = joy.x;
                return true;
            }
            break;
        }
    }

    return Label::gamepadEvent(evt, gamepad, analogIndex);
}

bool Slider::keyEvent(Keyboard::KeyEvent evt, int key)
{
    switch (evt)
    {
    case Keyboard::KEY_PRESS:
        switch (key)
        {
        case Keyboard::KEY_LEFT_ARROW:
            if (_step > 0.0f)
            {
                setValue(std::max(_value - _step, _min));
            }
            else
            {
                setValue(std::max(_value - (_max - _min) * MOVE_FRACTION, _min));
            }
            return true;

        case Keyboard::KEY_RIGHT_ARROW:
            if (_step > 0.0f)
            {
                setValue(std::min(_value + _step, _max));
            }
            else
            {
                setValue(std::min(_value + (_max - _min) * MOVE_FRACTION, _max));
            }
            return true;
        }
        break;
    }

    return Control::keyEvent(evt, key);
}

void Slider::update(float elapsedTime)
{
    Label::update(elapsedTime);

    if (_delta != 0.0f)
    {
        float total = _max - _min;

        if (_step > 0.0f)
        {
            _gamepadValue += (total * MOVE_FRACTION) * _delta;
            int numSteps = round(_gamepadValue / _step);
            setValue(_step * numSteps);
        }
        else
        {
            setValue(_value + (total * MOVE_FRACTION) * _delta);
        }
    }
}

void Slider::updateState(State state)
{
    Label::updateState(state);

    _minImage = getImage("minCap", state);
    _maxImage = getImage("maxCap", state);
    _markerImage = getImage("marker", state);
    _trackImage = getImage("track", state);
}

void Slider::updateBounds()
{
    Label::updateBounds();

    // Compute height of track (max of track, min/max and marker
    _trackHeight = _minImage->getRegion().height;
    _trackHeight = std::max(_trackHeight, _maxImage->getRegion().height);
    _trackHeight = std::max(_trackHeight, _markerImage->getRegion().height);
    _trackHeight = std::max(_trackHeight, _trackImage->getRegion().height);

    if (_autoSize & AUTO_SIZE_HEIGHT)
    {
        float height = _bounds.height + _trackHeight;
        if (_valueTextVisible)
            height += getFontSize(NORMAL);
        setHeightInternal(height);
    }
}

unsigned int Slider::drawImages(Form* form, const Rectangle& clip)
{
    if (!(_minImage && _maxImage && _markerImage && _trackImage))
        return 0;

    // TODO: Vertical slider.

    // The slider is drawn in the center of the control (perpendicular to orientation).
    // The track is stretched according to orientation.
    // Caps and marker are not stretched.
    const Rectangle& minCapRegion = _minImage->getRegion();
    const Rectangle& maxCapRegion = _maxImage->getRegion();
    const Rectangle& markerRegion = _markerImage->getRegion();
    const Rectangle& trackRegion = _trackImage->getRegion();

    const Theme::UVs& minCap = _minImage->getUVs();
    const Theme::UVs& maxCap = _maxImage->getUVs();
    const Theme::UVs& marker = _markerImage->getUVs();
    const Theme::UVs& track = _trackImage->getUVs();

    Vector4 minCapColor = _minImage->getColor();
    Vector4 maxCapColor = _maxImage->getColor();
    Vector4 markerColor = _markerImage->getColor();
    Vector4 trackColor = _trackImage->getColor();

    Control::State state = getState();

    minCapColor.w *= _opacity;
    maxCapColor.w *= _opacity;
    markerColor.w *= _opacity;
    trackColor.w *= _opacity;

    SpriteBatch* batch = _style->getTheme()->getSpriteBatch();
    startBatch(form, batch);

    // Compute area to draw the slider track
    unsigned int fontSize = getFontSize(state);
    float startY, endY;
    if (_text.length() > 0)
    {
        if (_valueTextVisible)
        {
            // Both label and value text are visible.
            // Draw slider in the middle.
            startY = fontSize;
            endY = _viewportBounds.height - fontSize;
        }
        else
        {
            // Only label is visible
            if (getTextAlignment(state) & ALIGN_BOTTOM)
            {
                // Draw slider above label
                startY = 0;
                endY = _viewportBounds.height - fontSize;
            }
            else
            {
                // Draw slider below label
                startY = fontSize;
                endY = _viewportBounds.height;
            }
        }
    }
    else if (_valueTextVisible)
    {
        // Only value text is visible.
        if (_valueTextAlignment & ALIGN_BOTTOM)
        {
            // Draw slider above value text
            startY = 0;
            endY = _viewportBounds.height - fontSize;
        }
        else
        {
            // Draw slider below value text
            startY = fontSize;
            endY = _viewportBounds.height;
        }
    }
    else
    {
        // Only the slider track is visible
        startY = 0;
        endY = _viewportBounds.height;
    }

    // Compute midpoint of track location
    float midY = _viewportBounds.y + startY + (endY - startY) * 0.5f;

    // Draw track below the slider text
    Vector2 pos(_viewportBounds.x + minCapRegion.width, midY - trackRegion.height * 0.5f);
    batch->draw(pos.x, pos.y, _viewportBounds.width - minCapRegion.width - maxCapRegion.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _viewportClipBounds);

    // Draw min cap to the left of the track
    pos.y = midY - minCapRegion.height * 0.5f;
    pos.x = _viewportBounds.x;
    batch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _viewportClipBounds);

    // Draw max cap to the right of the track
    pos.x = _viewportBounds.right() - maxCapRegion.width;
    batch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _viewportClipBounds);

    // Draw the marker at the correct position
    float markerPosition = (_value - _min) / (_max - _min);
    markerPosition *= _viewportBounds.width - markerRegion.width;
    pos.x = _viewportBounds.x + markerPosition;
    pos.y = midY - markerRegion.height * 0.5f;
    batch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _viewportClipBounds);

    finishBatch(form, batch);

    return 4;
}

unsigned int Slider::drawText(Form* form, const Rectangle& clip)
{
    unsigned int drawCalls = Label::drawText(form, clip);

    if (_valueTextVisible && _font)
    {
        Control::State state = getState();
        unsigned int fontSize = getFontSize(state);

        SpriteBatch* batch = _font->getSpriteBatch(fontSize);
        startBatch(form, batch);
        _font->drawText(_valueText.c_str(), _textBounds, _textColor, fontSize, _valueTextAlignment, true, getTextRightToLeft(state), &_viewportClipBounds);
        finishBatch(form, batch);

        ++drawCalls;
    }

    return drawCalls;
}

const char* Slider::getType() const
{
    return "slider";
}

}
<commit_msg>fixed slider's value updating<commit_after>#include "Slider.h"
#include "Game.h"

namespace gameplay
{

// Fraction of slider to scroll when mouse scrollwheel is used.
static const float SCROLLWHEEL_FRACTION = 0.1f;
// Fraction of slider to scroll for a delta of 1.0f when a gamepad or keyboard is used.
static const float MOVE_FRACTION = 0.005f;

Slider::Slider() : _min(0.0f), _max(0.0f), _step(0.0f), _value(0.0f), _delta(0.0f), _minImage(NULL),
    _maxImage(NULL), _trackImage(NULL), _markerImage(NULL), _valueTextVisible(false),
    _valueTextAlignment(Font::ALIGN_BOTTOM_HCENTER), _valueTextPrecision(0), _valueText(L""),
    _trackHeight(0.0f), _gamepadValue(0.0f)
{
    _canFocus = true;
}

Slider::~Slider()
{
}

Slider* Slider::create(const char* id, Theme::Style* style)
{
    Slider* slider = new Slider();
    slider->_id = id ? id : "";
    slider->initialize("Slider", style, NULL);
    return slider;
}

Control* Slider::create(Theme::Style* style, Properties* properties)
{
    Slider* slider = new Slider();
    slider->initialize("Slider", style, properties);
    return slider;
}

void Slider::initialize(const char* typeName, Theme::Style* style, Properties* properties)
{
    Label::initialize(typeName, style, properties);

    if (properties)
    {
        _min = properties->getFloat("min");
        _max = properties->getFloat("max");
        _value = properties->getFloat("value");
        _step = properties->getFloat("step");
        _valueTextVisible = properties->getBool("valueTextVisible");
        _valueTextPrecision = properties->getInt("valueTextPrecision");

        if (properties->exists("valueTextAlignment"))
        {
            _valueTextAlignment = Font::getJustify(properties->getString("valueTextAlignment"));
        }
    }

    // Force value text to be updated
    setValue(_value);
}

void Slider::setMin(float min)
{
    _min = min;
}

float Slider::getMin() const
{
    return _min;
}

void Slider::setMax(float max)
{
    _max = max;
}

float Slider::getMax() const
{
    return _max;
}

void Slider::setStep(float step)
{
    _step = step;
}

float Slider::getStep() const
{
    return _step;
}

float Slider::getValue() const
{
    return _value;
}

void Slider::setValue(float value)
{
    value = MATH_CLAMP(value, _min, _max);

    if (value != _value)
    {
        _value = value;
        notifyListeners(Control::Listener::VALUE_CHANGED);
    }

    // Always update value text if it's visible
    if (_valueTextVisible)
    {
        char s[32];
        sprintf(s, "%.*f", _valueTextPrecision, _value);
        _valueText.clear();

        const char * p = s;
        while (*p)
            _valueText.push_back(*p++);
    }
}

void Slider::setValueTextVisible(bool valueTextVisible)
{
    if (valueTextVisible != _valueTextVisible)
    {
        _valueTextVisible = valueTextVisible;
        if (_autoSize & AUTO_SIZE_HEIGHT)
            setDirty(DIRTY_BOUNDS);
    }
}

bool Slider::isValueTextVisible() const
{
    return _valueTextVisible;
}

void Slider::setValueTextAlignment(Font::Justify alignment)
{
    _valueTextAlignment = alignment;
}

Font::Justify Slider::getValueTextAlignment() const
{
    return _valueTextAlignment;
}

void Slider::setValueTextPrecision(unsigned int precision)
{
    _valueTextPrecision = precision;
}

unsigned int Slider::getValueTextPrecision() const
{
    return _valueTextPrecision;
}

void Slider::addListener(Control::Listener* listener, int eventFlags)
{
    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
    {
        GP_ERROR("TEXT_CHANGED event is not applicable to Slider.");
    }

    Control::addListener(listener, eventFlags);
}

void Slider::updateValue(int x, int y)
{
    State state = getState();

    // Horizontal case.
    const Theme::Border& border = getBorder(state);
    const Theme::Padding& padding = getPadding();
    const Rectangle& minCapRegion = _minImage->getRegion();
    const Rectangle& maxCapRegion = _maxImage->getRegion();
    const Rectangle& markerRegion = _markerImage->getRegion();

    float markerPosition = (x - markerRegion.width * 0.5f) / (_viewportBounds.width - markerRegion.width);

    if (markerPosition > 1.0f)
    {
        markerPosition = 1.0f;
    }
    else if (markerPosition < 0.0f)
    {
        markerPosition = 0.0f;
    }

    float value = (markerPosition * (_max - _min)) + _min;
    if (_step > 0.0f)
    {
        int numSteps = round(value / _step);
        value = _step * numSteps;
    }

    setValue(value);
}

bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
{
    State state = getState();

    switch (evt)
    {
    case Touch::TOUCH_PRESS:
        updateValue(x, y);
        return true;

    case Touch::TOUCH_MOVE:
        if (state == ACTIVE)
        {
            updateValue(x, y);
            return true;
        }
        break;
    }

    return Control::touchEvent(evt, x, y, contactIndex);
}

static bool isScrollable(Container* container)
{
    if (container->getScroll() != Container::SCROLL_NONE)
        return true;

    Container* parent = static_cast<Container*>(container->getParent());
    return parent ? isScrollable(parent) : false;
}

bool Slider::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
{
    switch (evt)
    {
        case Mouse::MOUSE_WHEEL:
        {
            if (hasFocus() && !isScrollable(_parent))
            {
                float total = _max - _min;
                float value = _value + (total * SCROLLWHEEL_FRACTION) * wheelDelta;

                if (_step > 0.0f)
                {
                    int numSteps = round(value / _step);
                    value = _step * numSteps;
                }

                setValue(value);
                return true;
            }
            break;
        }

        default:
            break;
    }

    // Return false to fall through to touch handling
    return false;
}

bool Slider::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
{
    switch (evt)
    {
        case Gamepad::JOYSTICK_EVENT:
        {
            // The right analog stick can be used to change a slider's value.
            if (analogIndex == 1)
            {
                Vector2 joy;
                gamepad->getJoystickValues(analogIndex, &joy);
                _gamepadValue = _value;
                _delta = joy.x;
                return true;
            }
            break;
        }
    }

    return Label::gamepadEvent(evt, gamepad, analogIndex);
}

bool Slider::keyEvent(Keyboard::KeyEvent evt, int key)
{
    switch (evt)
    {
    case Keyboard::KEY_PRESS:
        switch (key)
        {
        case Keyboard::KEY_LEFT_ARROW:
            if (_step > 0.0f)
            {
                setValue(std::max(_value - _step, _min));
            }
            else
            {
                setValue(std::max(_value - (_max - _min) * MOVE_FRACTION, _min));
            }
            return true;

        case Keyboard::KEY_RIGHT_ARROW:
            if (_step > 0.0f)
            {
                setValue(std::min(_value + _step, _max));
            }
            else
            {
                setValue(std::min(_value + (_max - _min) * MOVE_FRACTION, _max));
            }
            return true;
        }
        break;
    }

    return Control::keyEvent(evt, key);
}

void Slider::update(float elapsedTime)
{
    Label::update(elapsedTime);

    if (_delta != 0.0f)
    {
        float total = _max - _min;

        if (_step > 0.0f)
        {
            _gamepadValue += (total * MOVE_FRACTION) * _delta;
            int numSteps = round(_gamepadValue / _step);
            setValue(_step * numSteps);
        }
        else
        {
            setValue(_value + (total * MOVE_FRACTION) * _delta);
        }
    }
}

void Slider::updateState(State state)
{
    Label::updateState(state);

    _minImage = getImage("minCap", state);
    _maxImage = getImage("maxCap", state);
    _markerImage = getImage("marker", state);
    _trackImage = getImage("track", state);
}

void Slider::updateBounds()
{
    Label::updateBounds();

    // Compute height of track (max of track, min/max and marker
    _trackHeight = _minImage->getRegion().height;
    _trackHeight = std::max(_trackHeight, _maxImage->getRegion().height);
    _trackHeight = std::max(_trackHeight, _markerImage->getRegion().height);
    _trackHeight = std::max(_trackHeight, _trackImage->getRegion().height);

    if (_autoSize & AUTO_SIZE_HEIGHT)
    {
        float height = _bounds.height + _trackHeight;
        if (_valueTextVisible)
            height += getFontSize(NORMAL);
        setHeightInternal(height);
    }
}

unsigned int Slider::drawImages(Form* form, const Rectangle& clip)
{
    if (!(_minImage && _maxImage && _markerImage && _trackImage))
        return 0;

    // TODO: Vertical slider.

    // The slider is drawn in the center of the control (perpendicular to orientation).
    // The track is stretched according to orientation.
    // Caps and marker are not stretched.
    const Rectangle& minCapRegion = _minImage->getRegion();
    const Rectangle& maxCapRegion = _maxImage->getRegion();
    const Rectangle& markerRegion = _markerImage->getRegion();
    const Rectangle& trackRegion = _trackImage->getRegion();

    const Theme::UVs& minCap = _minImage->getUVs();
    const Theme::UVs& maxCap = _maxImage->getUVs();
    const Theme::UVs& marker = _markerImage->getUVs();
    const Theme::UVs& track = _trackImage->getUVs();

    Vector4 minCapColor = _minImage->getColor();
    Vector4 maxCapColor = _maxImage->getColor();
    Vector4 markerColor = _markerImage->getColor();
    Vector4 trackColor = _trackImage->getColor();

    Control::State state = getState();

    minCapColor.w *= _opacity;
    maxCapColor.w *= _opacity;
    markerColor.w *= _opacity;
    trackColor.w *= _opacity;

    SpriteBatch* batch = _style->getTheme()->getSpriteBatch();
    startBatch(form, batch);

    // Compute area to draw the slider track
    unsigned int fontSize = getFontSize(state);
    float startY, endY;
    if (_text.length() > 0)
    {
        if (_valueTextVisible)
        {
            // Both label and value text are visible.
            // Draw slider in the middle.
            startY = fontSize;
            endY = _viewportBounds.height - fontSize;
        }
        else
        {
            // Only label is visible
            if (getTextAlignment(state) & ALIGN_BOTTOM)
            {
                // Draw slider above label
                startY = 0;
                endY = _viewportBounds.height - fontSize;
            }
            else
            {
                // Draw slider below label
                startY = fontSize;
                endY = _viewportBounds.height;
            }
        }
    }
    else if (_valueTextVisible)
    {
        // Only value text is visible.
        if (_valueTextAlignment & ALIGN_BOTTOM)
        {
            // Draw slider above value text
            startY = 0;
            endY = _viewportBounds.height - fontSize;
        }
        else
        {
            // Draw slider below value text
            startY = fontSize;
            endY = _viewportBounds.height;
        }
    }
    else
    {
        // Only the slider track is visible
        startY = 0;
        endY = _viewportBounds.height;
    }

    // Compute midpoint of track location
    float midY = _viewportBounds.y + startY + (endY - startY) * 0.5f;

    // Draw track below the slider text
    Vector2 pos(_viewportBounds.x + minCapRegion.width, midY - trackRegion.height * 0.5f);
    batch->draw(pos.x, pos.y, _viewportBounds.width - minCapRegion.width - maxCapRegion.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _viewportClipBounds);

    // Draw min cap to the left of the track
    pos.y = midY - minCapRegion.height * 0.5f;
    pos.x = _viewportBounds.x;
    batch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _viewportClipBounds);

    // Draw max cap to the right of the track
    pos.x = _viewportBounds.right() - maxCapRegion.width;
    batch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _viewportClipBounds);

    // Draw the marker at the correct position
    float markerPosition = (_value - _min) / (_max - _min);
    markerPosition *= _viewportBounds.width - markerRegion.width;
    pos.x = _viewportBounds.x + markerPosition;
    pos.y = midY - markerRegion.height * 0.5f;
    batch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _viewportClipBounds);

    finishBatch(form, batch);

    return 4;
}

unsigned int Slider::drawText(Form* form, const Rectangle& clip)
{
    unsigned int drawCalls = Label::drawText(form, clip);

    if (_valueTextVisible && _font)
    {
        Control::State state = getState();
        unsigned int fontSize = getFontSize(state);

        SpriteBatch* batch = _font->getSpriteBatch(fontSize);
        startBatch(form, batch);
        _font->drawText(_valueText.c_str(), _textBounds, _textColor, fontSize, _valueTextAlignment, true, getTextRightToLeft(state), &_viewportClipBounds);
        finishBatch(form, batch);

        ++drawCalls;
    }

    return drawCalls;
}

const char* Slider::getType() const
{
    return "slider";
}

}
<|endoftext|>


<commit_before>
#include <iostream>
#include <map>
#include <functional>

#include <platform/sdl/system.h>

#include <layout/form_layout.h>
#include <layout/box_layout.h>
#include <layout/grid_layout.h>
#include <layout/tree_layout.h>

namespace {

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

std::shared_ptr<layout> test_box( std::shared_ptr<container> c )
{
	auto l =  std::make_shared<box_layout>( c, direction::DOWN );
	for ( size_t i = 0; i < 5; ++i )
	{
		auto a = l->new_area( i == 2 ? 1.0 : 0.0 );
		a->set_minimum( 100, 24 );
	}
	return l;
}

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

std::shared_ptr<layout> test_tree( std::shared_ptr<container> c )
{
	auto l = std::make_shared<tree_layout>( c, 24.0 );
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	auto b1 = l->new_branch();
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = b1->new_area();
		a->set_minimum( 100, 24 );
	}
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	l->new_area( 1.0 );

	return l;
}

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

std::shared_ptr<layout> test_form( std::shared_ptr<container> c )
{
	std::shared_ptr<area> a, b;

	auto l = std::make_shared<form_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
	{
		std::tie( a, b ) = l->new_row();
		a->set_minimum( 100, 24 );
		b->set_minimum( 100, 24 );
	}

	return l;
}

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

std::shared_ptr<layout> test_grid( std::shared_ptr<container> c )
{
	auto l = std::make_shared<grid_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
		auto tmp = l->new_column( i == 2 ? 1.0 : 0.0 );

	for ( size_t i = 0; i < 5; ++i )
	{
		auto tmp = l->new_row( i == 2 ? 1.0 : 0.0 );
		for ( auto a: tmp )
			a->set_minimum( 50, 24 );
	}

	return l;
}

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

std::map<std::string,std::function<std::shared_ptr<layout>(std::shared_ptr<container>)>> tests =
{
	{ "grid", test_grid },
	{ "box", test_box },
	{ "form", test_form },
	{ "tree", test_tree },
};

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

int safemain( int argc, char **argv )
{
	precondition( argc > 1, "expected argument" );

	auto sys = std::make_shared<sdl::system>();
	auto win = sys->new_window();
	win->resize( 640, 480 );
	win->set_title( "Hello World" );

	std::shared_ptr<container> c = std::make_shared<container>();

	auto layout = tests[argv[1]]( c );

	auto recompute_layout = [&] ( double w, double h ) {
		layout->recompute_minimum();
		std::shared_ptr<area> b = c->bounds();
		win->set_minimum_size( b->minimum_width(), b->minimum_height() );

		if ( w < b->minimum_width() )
			w = b->minimum_width();
		if ( h < b->minimum_height() )
			h = b->minimum_height();
		b->set_horizontal( 0, w );
		b->set_vertical( 0, h );

		layout->recompute_layout();
	};

	recompute_layout( 640, 480 );

	std::shared_ptr<platform::dispatcher> dispatcher = sys->dispatch();

//	std::shared_ptr<sdl::timer> timer = sys->new_timer( 1.0 );
//	timer->start();

	/*
	bool done = false;
	do
	{
		allegro::event ev;
		queue.wait( ev );
		switch ( ev.type() )
		{
			case allegro::EVENT_KEY_DOWN:
			case allegro::EVENT_DISPLAY_CLOSE:
				done = true;
				break;

			case allegro::EVENT_DISPLAY_RESIZE:
				recompute_layout( ev.width(), ev.height() );
				ev.acknowledge_resize();
				break;

			case allegro::EVENT_TIMER:
			{
				allegro::target t( win );
				t.clear( white );
				for ( auto a: *c )
					t.draw_rect( a->x1() + 0.5, a->y1() + 0.5, a->x2() - 0.5, a->y2() - 0.5, black, 1.F );
				t.draw( "Hello World", font, 0, 0, black );
				t.flip();
				break;
			}

			default:
				break;
		}
	} while ( !done );
	*/

	return dispatcher->execute();
}
}

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

int main( int argc, char *argv[] )
{
	int ret = -1;
	try
	{
		ret = safemain( argc, argv );
	}
	catch ( std::exception &e )
	{
		print_exception( std::cerr, e );
	}
	return ret;
}

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

<commit_msg>Show window and process events.<commit_after>
#include <iostream>
#include <map>
#include <functional>

#include <platform/sdl/system.h>

#include <layout/form_layout.h>
#include <layout/box_layout.h>
#include <layout/grid_layout.h>
#include <layout/tree_layout.h>

namespace {

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

std::shared_ptr<layout> test_box( std::shared_ptr<container> c )
{
	auto l =  std::make_shared<box_layout>( c, direction::DOWN );
	for ( size_t i = 0; i < 5; ++i )
	{
		auto a = l->new_area( i == 2 ? 1.0 : 0.0 );
		a->set_minimum( 100, 24 );
	}
	return l;
}

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

std::shared_ptr<layout> test_tree( std::shared_ptr<container> c )
{
	auto l = std::make_shared<tree_layout>( c, 24.0 );
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	auto b1 = l->new_branch();
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = b1->new_area();
		a->set_minimum( 100, 24 );
	}
	for ( size_t i = 0; i < 2; ++i )
	{
		auto a = l->new_area( 0.0 );
		a->set_minimum( 100, 24 );
	}
	l->new_area( 1.0 );

	return l;
}

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

std::shared_ptr<layout> test_form( std::shared_ptr<container> c )
{
	std::shared_ptr<area> a, b;

	auto l = std::make_shared<form_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
	{
		std::tie( a, b ) = l->new_row();
		a->set_minimum( 100, 24 );
		b->set_minimum( 100, 24 );
	}

	return l;
}

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

std::shared_ptr<layout> test_grid( std::shared_ptr<container> c )
{
	auto l = std::make_shared<grid_layout>( c );

	for ( size_t i = 0; i < 5; ++i )
		auto tmp = l->new_column( i == 2 ? 1.0 : 0.0 );

	for ( size_t i = 0; i < 5; ++i )
	{
		auto tmp = l->new_row( i == 2 ? 1.0 : 0.0 );
		for ( auto a: tmp )
			a->set_minimum( 50, 24 );
	}

	return l;
}

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

std::map<std::string,std::function<std::shared_ptr<layout>(std::shared_ptr<container>)>> tests =
{
	{ "grid", test_grid },
	{ "box", test_box },
	{ "form", test_form },
	{ "tree", test_tree },
};

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

int safemain( int argc, char **argv )
{
	precondition( argc > 1, "expected argument" );

	auto sys = std::make_shared<sdl::system>();
	auto win = sys->new_window();
	win->resize( 640, 480 );
	win->set_title( "Hello World" );
	win->show();

	std::shared_ptr<container> c = std::make_shared<container>();

	auto layout = tests[argv[1]]( c );

	auto recompute_layout = [&] ( double w, double h ) {
		layout->recompute_minimum();
		std::shared_ptr<area> b = c->bounds();
		win->set_minimum_size( b->minimum_width(), b->minimum_height() );

		if ( w < b->minimum_width() )
			w = b->minimum_width();
		if ( h < b->minimum_height() )
			h = b->minimum_height();
		b->set_horizontal( 0, w );
		b->set_vertical( 0, h );

		layout->recompute_layout();
	};

	recompute_layout( 640, 480 );

	std::shared_ptr<platform::dispatcher> dispatcher = sys->dispatch();

//	std::shared_ptr<sdl::timer> timer = sys->new_timer( 1.0 );
//	timer->start();

	/*
	bool done = false;
	do
	{
		allegro::event ev;
		queue.wait( ev );
		switch ( ev.type() )
		{
			case allegro::EVENT_KEY_DOWN:
			case allegro::EVENT_DISPLAY_CLOSE:
				done = true;
				break;

			case allegro::EVENT_DISPLAY_RESIZE:
				recompute_layout( ev.width(), ev.height() );
				ev.acknowledge_resize();
				break;

			case allegro::EVENT_TIMER:
			{
				allegro::target t( win );
				t.clear( white );
				for ( auto a: *c )
					t.draw_rect( a->x1() + 0.5, a->y1() + 0.5, a->x2() - 0.5, a->y2() - 0.5, black, 1.F );
				t.draw( "Hello World", font, 0, 0, black );
				t.flip();
				break;
			}

			default:
				break;
		}
	} while ( !done );
	*/

	return dispatcher->execute();
}
}

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

int main( int argc, char *argv[] )
{
	int ret = -1;
	try
	{
		ret = safemain( argc, argv );
	}
	catch ( std::exception &e )
	{
		print_exception( std::cerr, e );
	}
	return ret;
}

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

<|endoftext|>


<commit_before>#include "data-id.hpp"

ID::ID() {
	init(Department(), 0, "");
}
ID::ID(const ID& c) {
	copy(c);
}
ID& ID::operator= (const ID &c) {
	if (this == &c) return *this;
	copy(c);
	return *this;
}

ID::ID(string str) {
	string d, d1, d2, n, s;
	int num;
	long firstSpace, firstDigit, lastDigit, lastChar;
	// cout << "Called ID::ID() with string '" << str << "'" << endl;

	// Make sure everything is uppercase
	std::transform(str.begin(), str.end(), str.begin(), ::toupper);

	// Remove extraneous spaces
	if (str.at(0) == ' ')
		str.erase(0, 1);
	if (str.at(str.length()-1) == ' ')
		str = str.substr(0, str.length()-1);

	firstSpace = str.find_first_of(" ");

	firstDigit = str.find_first_of("0123456789");
	lastDigit  =  str.find_last_of("0123456789");

	lastChar   =  str.find_last_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

	// Split into Department, Number, and Section

	// pull out the department string
	if (firstSpace == string::npos) // if there is no space
		d = str.substr(0, firstDigit);
	else
		d = str.substr(0, firstSpace); // there is a space

	// check for one of those dastardly split departments
	if (d.find('/') != string::npos) {
		d1 = d.substr(0,2);
		d2 = d.substr(3,2);
	}

	n = str.substr(firstDigit, str.length());

	if (!isdigit(n[n.length()-1]))
		n = str.substr(firstDigit, n.length()-1);

	num = stringToInt(n);

	if (lastChar > lastDigit) // there is a section
		s = str[lastChar];

	// cout << "Parsed '" << str << "' to get '";
	// cout << d << " ";
	// if (!d1.empty() && !d2.empty())
		// cout << "(" << d1 << " " << d2 << ") ";
	// cout << n << s << "'." << endl;

	init(Department(d), num, s);
	if (!d1.empty() && !d2.empty()) {
		departments.clear();
		departments.push_back(Department(d1));
		departments.push_back(Department(d2));
	}
	// cout << *this << endl;
}
ID::ID(string dn, string s) {
	ID(dn+s);
}
ID::ID(string d, string n, string s) {
	ID(d + n + s);
}
ID::ID(Department d, int n, string s) {
	init(d, n, s);
}

void ID::init(Department d, int n, string s) {
	departments.push_back(d);
	number = n;
	section = s;
}

void ID::copy(const ID& c) {
	departments = c.departments;
	number = c.number;
	section = c.section;
}

Department ID::getDepartment(int i = 0) {
	return departments.at(i);
}

const Department ID::getDepartment_const(int i = 0) {
	return departments.at(i);
}

int ID::getNumber() {
	return number;
}

string ID::getSection() {
	return section;
}

bool operator== (const ID &i1, const ID &i2) {
    return ((i1.departments[0] == i2.departments[0]) && (i1.number == i2.number) && (i1.section == i2.section));
}

bool operator!= (ID &i1, ID &i2) {
    return !(i1 == i2);
}

bool operator< (const ID &i1, const ID &i2) {
	return (i1.departments.at(0) < i2.departments.at(0));
}

ostream& ID::getData(ostream& os) {
	for (vector<Department>::iterator i = departments.begin(); i != departments.end(); ++i) {
		if (departments.size() == 1)
			os << i->getName();
		else {
			os << i->getName();
			if (i != departments.end()-1)
				os << "/";
		}
	}
	os << " ";
	os << number;
	if (!section.empty())
		os << "[" << section << "]";
	return os;
}

ostream& operator<<(ostream& os, ID& item) {
	return item.getData(os);
}

void ID::display() {
	cout << *this << endl;
}
<commit_msg>Add another cout to data-id<commit_after>#include "data-id.hpp"

ID::ID() {
	init(Department(), 0, "");
}
ID::ID(const ID& c) {
	copy(c);
}
ID& ID::operator= (const ID &c) {
	if (this == &c) return *this;
	copy(c);
	return *this;
}

ID::ID(string str) {
	string d, d1, d2, n, s;
	int num;
	long firstSpace, firstDigit, lastDigit, lastChar;
	// cout << "Parsed '" << str << "' to get '";
	// cout << "Called ID::ID() with string '" << str << "'" << endl;

	// Make sure everything is uppercase
	std::transform(str.begin(), str.end(), str.begin(), ::toupper);

	// Remove extraneous spaces
	if (str.at(0) == ' ')
		str.erase(0, 1);
	if (str.at(str.length()-1) == ' ')
		str = str.substr(0, str.length()-1);

	firstSpace = str.find_first_of(" ");

	firstDigit = str.find_first_of("0123456789");
	lastDigit  =  str.find_last_of("0123456789");

	lastChar   =  str.find_last_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

	// Split into Department, Number, and Section

	// pull out the department string
	if (firstSpace == string::npos) // if there is no space
		d = str.substr(0, firstDigit);
	else
		d = str.substr(0, firstSpace); // there is a space

	// check for one of those dastardly split departments
	if (d.find('/') != string::npos) {
		d1 = d.substr(0,2);
		d2 = d.substr(3,2);
	}

	n = str.substr(firstDigit, str.length());

	if (!isdigit(n[n.length()-1]))
		n = str.substr(firstDigit, n.length()-1);

	num = stringToInt(n);

	if (lastChar > lastDigit) // there is a section
		s = str[lastChar];

	// cout << "Parsed '" << str << "' to get '";
	// cout << d << " ";
	// if (!d1.empty() && !d2.empty())
		// cout << "(" << d1 << " " << d2 << ") ";
	// cout << n << s << "'." << endl;

	init(Department(d), num, s);
	if (!d1.empty() && !d2.empty()) {
		departments.clear();
		departments.push_back(Department(d1));
		departments.push_back(Department(d2));
	}
	// cout << *this << endl;
}
ID::ID(string dn, string s) {
	ID(dn+s);
}
ID::ID(string d, string n, string s) {
	ID(d + n + s);
}
ID::ID(Department d, int n, string s) {
	init(d, n, s);
}

void ID::init(Department d, int n, string s) {
	departments.push_back(d);
	number = n;
	section = s;
}

void ID::copy(const ID& c) {
	departments = c.departments;
	number = c.number;
	section = c.section;
}

Department ID::getDepartment(int i = 0) {
	return departments.at(i);
}

const Department ID::getDepartment_const(int i = 0) {
	return departments.at(i);
}

int ID::getNumber() {
	return number;
}

string ID::getSection() {
	return section;
}

bool operator== (const ID &i1, const ID &i2) {
    return ((i1.departments[0] == i2.departments[0]) && (i1.number == i2.number) && (i1.section == i2.section));
}

bool operator!= (ID &i1, ID &i2) {
    return !(i1 == i2);
}

bool operator< (const ID &i1, const ID &i2) {
	return (i1.departments.at(0) < i2.departments.at(0));
}

ostream& ID::getData(ostream& os) {
	for (vector<Department>::iterator i = departments.begin(); i != departments.end(); ++i) {
		if (departments.size() == 1)
			os << i->getName();
		else {
			os << i->getName();
			if (i != departments.end()-1)
				os << "/";
		}
	}
	os << " ";
	os << number;
	if (!section.empty())
		os << "[" << section << "]";
	return os;
}

ostream& operator<<(ostream& os, ID& item) {
	return item.getData(os);
}

void ID::display() {
	cout << *this << endl;
}
<|endoftext|>


<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

/// One implementation of GUPS. This does no load-balancing, and may
/// suffer from some load imbalance.

#include <memory>
#include <algorithm>

#include <Grappa.hpp>
#include "ForkJoin.hpp"
#include "GlobalAllocator.hpp"
#include "GlobalTaskJoiner.hpp"
#include "Array.hpp"
#include "Message.hpp"
#include "CompletionEvent.hpp"
#include "Statistics.hpp"

#include "LocaleSharedMemory.hpp"

#include <boost/test/unit_test.hpp>

DEFINE_int64( repeats, 1, "Repeats" );
DEFINE_int64( iterations, 1 << 30, "Iterations" );
DEFINE_int64( sizeA, 1024, "Size of array that gups increments" );
DEFINE_int64( outstanding, 1 << 10, "Number of outstanding requests" );
DEFINE_bool( validate, true, "Validate result" );
DEFINE_bool( rdma, false, "Use RDMA aggregator" );

DECLARE_string( load_balance );

//const int outstanding = 1 << 4;
//const int outstanding = 1 << 13;

template< typename T >
class ReuseMessage : public Grappa::Message<T> {
public:
  Grappa::impl::ReuseList< ReuseMessage > * list_;
  virtual ReuseMessage * get_next() {
    // we know this is safe since the list only holds this message type.
    return static_cast<ReuseMessage*>(this->next_);
  }
  virtual void set_next( ReuseMessage * next ) { this->next_ = next; }
protected:
  virtual void mark_sent() {
    DVLOG(5) << __func__ << ": " << this << " Marking sent with is_enqueued_=" << this->is_enqueued_
             << " is_delivered_=" << this->is_delivered_
             << " is_sent_=" << this->is_sent_;

    if( Grappa::mycore() == this->source_ ) {
      CHECK_EQ( Grappa::mycore(), this->source_ );
      list_->push(this);
    }

    Grappa::Message<T>::mark_sent();
  }
};

// completion message handler
struct C {
  GlobalAddress< Grappa::CompletionEvent > ce;
  void operator()() {
    DVLOG(5) << "Received completion at node " << Grappa::mycore()
             << " with target " << ce.node()
             << " address " << ce.pointer();
    ce.pointer()->complete();
  }
};

// list of free completion messages
Grappa::impl::ReuseList< ReuseMessage<C> > completion_list;
void completion_list_push( ReuseMessage<C> * c ) {
  completion_list.push(c);
}

// GUPS request message handler
struct M {
  // address to increment
  GlobalAddress< int64_t > addr;
  // address of completion counter
  GlobalAddress< Grappa::CompletionEvent > ce;

  // once we have a message to use, do this
  static void complete( ReuseMessage<C> * message, GlobalAddress< Grappa::CompletionEvent > event ) {
    message->reset();
    (*message)->ce = event;
    message->enqueue( event.node() );
  }

  void operator()() {
    DVLOG(5) << "Received GUP at node " << Grappa::mycore()
             << " with target " << addr.node()
             << " address " << addr.pointer()
             << " reply to " << ce.node()
             << " with address " << ce.pointer();

    // increment address
    int64_t * ptr = addr.pointer();
    *ptr++;

    // now send completion
    // is the completion local?
    if (ce.node() == Grappa::mycore()) {
      // yes, so just do it.
      ce.pointer()->complete();
    } else {
      // we need to send a message
      // try to grab a message
      ReuseMessage<C> * c = NULL;
      if( (c = completion_list.try_pop()) != NULL ) {
        // got one; send completion
        M::complete( c, ce );
      } else {
        // we need to block, so spawn a task
        auto my_ce = ce;
        Grappa::privateTask( [this, my_ce] { // this actually unused
            ReuseMessage<C> * c = completion_list.block_until_pop();
            M::complete( c, my_ce );
          });
      }
    }
  }
};

// list of free request messages
Grappa::impl::ReuseList< ReuseMessage<M> > message_list;
void message_list_push( ReuseMessage<M> * m ) {
  message_list.push(m);
}

// keep track of this core's completions
Grappa::CompletionEvent ce;

double wall_clock_time() {
  const double nano = 1.0e-9;
  timespec t;
  clock_gettime( CLOCK_MONOTONIC, &t );
  return nano * t.tv_nsec + t.tv_sec;
}

BOOST_AUTO_TEST_SUITE( Gups_tests );

LOOP_FUNCTION( func_start_profiling, index ) {
  Grappa_start_profiling();
}

LOOP_FUNCTION( func_stop_profiling, index ) {
  Grappa_stop_profiling();
  //Grappa::Statistics::print();
}

/// Functor to execute one GUP.
static GlobalAddress<int64_t> Array;
static int64_t * base;
LOOP_FUNCTOR( func_gups, index, ((GlobalAddress<int64_t>, _Array)) ) {
  Array = _Array;
  base = Array.localize();
}

void func_gups_x(int64_t * p) {
  const uint64_t LARGE_PRIME = 18446744073709551557UL;
  /* across all nodes and all calls, each instance of index in [0.. iterations)
  ** must be encounted exactly once */
  //uint64_t index = random() + Grappa_mynode();//(p - base) * Grappa_nodes() + Grappa_mynode();
  //uint64_t b = (index*LARGE_PRIME) % FLAGS_sizeA;

  static uint64_t index = 1;
  //uint64_t b = ((Grappa_mynode() + index++) *LARGE_PRIME) & 1023;
  uint64_t b = ((Grappa_mynode() + index++) *LARGE_PRIME) % FLAGS_sizeA;

  //fprintf(stderr, "%d ", b);
  ff_delegate_add( Array + b, (const int64_t &) 1 );
}
void validate(GlobalAddress<uint64_t> A, size_t n) {
  int total = 0, max = 0, min = INT_MAX;
  double sum_sqr = 0.0;
  for (int i = 0; i < n; i++) {
    //int tmp = Grappa_delegate_read_word(A+i);
    int tmp = Grappa::delegate::read(A+i);
    total += tmp;
    sum_sqr += tmp*tmp;
    max = tmp > max ? tmp : max;
    min = tmp < min ? tmp : min;
  }
  // fprintf(stderr, "Validation:  total updates %d; min %d; max %d; avg value %g; std dev %g\n",
  //         total, min, max, total/((double)n), sqrt(sum_sqr/n - ((total/n)*total/n)));
}

LOOP_FUNCTION( func_gups_rdma, index ) {
  //void func_gups_x(int64_t * p) {
  const uint64_t LARGE_PRIME = 18446744073709551557UL;
  const uint64_t each_iters = FLAGS_iterations / Grappa::cores();
  const uint64_t my_start = each_iters * Grappa::mycore();

  DVLOG(1) << "Initializing RDMA GUPS....";

  // record how many messages we plan to send
  ce.enroll( each_iters );

  DVLOG(1) << "Starting RDMA GUPS";
  for( uint64_t index = my_start; index < my_start + each_iters; ++index ) {
    DCHECK_LT( index, FLAGS_iterations ) << "index exploded!";

    // compute address to increment
    uint64_t b = (index * LARGE_PRIME) % FLAGS_sizeA;
    auto a = Array + b;

    // get a message to use to send
    ReuseMessage<M> * m = message_list.block_until_pop();

    // send
    m->reset();
    (*m)->addr = a;
    (*m)->ce = make_global( &ce );
    m->enqueue( a.node() );
    DVLOG(5) << "Sent GUP from node " << Grappa::mycore()
             << " to " << a.node()
             << " address " << a.pointer()
             << " reply to address " << &ce;

  }

  DVLOG(1) << "Done sending; now waiting for replies";
  ce.wait();

  DVLOG(1) << "Got all replies";
}

void user_main( int * args ) {

  //fprintf(stderr, "Entering user_main\n");
  func_start_profiling start_profiling;
  func_stop_profiling stop_profiling;

  //CHECK_EQ( FLAGS_sizeA, 1024 ) << "sizeA must be 1024 unless you switch back to mods";
  CHECK_EQ( FLAGS_load_balance, "none" ) << "load balancing must be disabled unless you change the iteration approach";

  GlobalAddress<int64_t> A = Grappa_typed_malloc<int64_t>(FLAGS_sizeA);

  //fprintf(stderr, "user_main: Allocated global array of %d integers\n", FLAGS_sizeA);
  //fprintf(stderr, "user_main: Will run %d iterations\n", FLAGS_iterations);

  func_gups gups( A );

  func_gups_rdma gups_rdma;

    double runtime = 0.0;
    double throughput = 0.0;
    int nnodes = atoi(getenv("SLURM_NNODES"));
    double throughput_per_node = 0.0;

    Grappa_add_profiling_value( &runtime, "runtime", "s", false, 0.0 );
    Grappa_add_profiling_integer( &FLAGS_iterations, "iterations", "it", false, 0 );
    Grappa_add_profiling_integer( &FLAGS_sizeA, "sizeA", "entries", false, 0 );
    Grappa_add_profiling_value( &throughput, "updates_per_s", "up/s", false, 0.0 );
    Grappa_add_profiling_value( &throughput_per_node, "updates_per_s_per_node", "up/s", false, 0.0 );

  do {

    LOG(INFO) << "Starting";
    Grappa_memset_local(A, 0, FLAGS_sizeA);
    LOG(INFO) << "Start profiling";
    fork_join_custom( &start_profiling );

    LOG(INFO) << "Do something";
    double start = wall_clock_time();
    fork_join_custom( &gups );
    //printf ("Yeahoow!\n");
    if( FLAGS_rdma ) {
      LOG(INFO) << "Starting RDMA";
      fork_join_custom( &gups_rdma );
    } else {
      forall_local <int64_t, func_gups_x> (A, FLAGS_iterations);
    }
    double end = wall_clock_time();

    fork_join_custom( &stop_profiling );

    runtime = end - start;
    throughput = FLAGS_iterations / runtime;

    throughput_per_node = throughput/nnodes;
    Grappa::Statistics::merge_and_print();

    if( FLAGS_validate ) {
      LOG(INFO) << "Validating....";
      validate(A, FLAGS_sizeA);
    }

    // LOG(INFO) << "GUPS: "
    //         << FLAGS_iterations << " updates at "
    //         << throughput << "updates/s ("
    //         << throughput/nnodes << " updates/s/node).";
   } while (FLAGS_repeats-- > 1);
  LOG(INFO) << "Done. ";
}

BOOST_AUTO_TEST_CASE( test1 ) {
    Grappa_init( &(boost::unit_test::framework::master_test_suite().argc),
		  &(boost::unit_test::framework::master_test_suite().argv) );
    Grappa_activate();

    // prepare pools of messages
    auto msgs = Grappa::impl::locale_shared_memory.segment.construct< ReuseMessage<M> >(boost::interprocess::anonymous_instance)[ FLAGS_outstanding ]();
    auto completions = Grappa::impl::locale_shared_memory.segment.construct< ReuseMessage<C> >(boost::interprocess::anonymous_instance)[ FLAGS_outstanding ]();
    for( int i; i < FLAGS_outstanding; ++i ) {
      msgs[i].list_ = &message_list;
      message_list.push( &msgs[i] );
      completions[i].list_ = &completion_list;
      completion_list.push( &completions[i] );
    }

    Grappa_run_user_main( &user_main, (int*)NULL );

    Grappa_finish( 0 );
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Whoops, didn't initialize message pools properly….<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

/// One implementation of GUPS. This does no load-balancing, and may
/// suffer from some load imbalance.

#include <memory>
#include <algorithm>

#include <Grappa.hpp>
#include "ForkJoin.hpp"
#include "GlobalAllocator.hpp"
#include "GlobalTaskJoiner.hpp"
#include "Array.hpp"
#include "Message.hpp"
#include "CompletionEvent.hpp"
#include "Statistics.hpp"

#include "LocaleSharedMemory.hpp"

#include <boost/test/unit_test.hpp>

DEFINE_int64( repeats, 1, "Repeats" );
DEFINE_int64( iterations, 1 << 30, "Iterations" );
DEFINE_int64( sizeA, 1024, "Size of array that gups increments" );
DEFINE_int64( outstanding, 1 << 10, "Number of outstanding requests" );
DEFINE_bool( validate, true, "Validate result" );
DEFINE_bool( rdma, false, "Use RDMA aggregator" );

DECLARE_string( load_balance );

GRAPPA_DEFINE_STAT( SimpleStatistic<int64_t>, gups_requests_sent, 0 );
GRAPPA_DEFINE_STAT( SimpleStatistic<int64_t>, gups_completions_sent, 0 );
GRAPPA_DEFINE_STAT( SimpleStatistic<int64_t>, gups_requests_received, 0 );
GRAPPA_DEFINE_STAT( SimpleStatistic<int64_t>, gups_completions_received, 0 );
GRAPPA_DEFINE_STAT( SimpleStatistic<int64_t>, gups_completions_blocked, 0 );

uint64_t * requests_sent = NULL;
uint64_t * completions_sent = NULL;

//const int outstanding = 1 << 4;
//const int outstanding = 1 << 13;

template< typename T >
class ReuseMessage : public Grappa::Message<T> {
public:
  Grappa::impl::ReuseList< ReuseMessage > * list_;
  virtual ReuseMessage * get_next() {
    // we know this is safe since the list only holds this message type.
    return static_cast<ReuseMessage*>(this->next_);
  }
  virtual void set_next( ReuseMessage * next ) { this->next_ = next; }
protected:
  virtual void mark_sent() {
    DVLOG(5) << __func__ << ": " << this << " Marking sent with is_enqueued_=" << this->is_enqueued_
             << " is_delivered_=" << this->is_delivered_
             << " is_sent_=" << this->is_sent_;

    if( Grappa::mycore() == this->source_ ) {
      CHECK_EQ( Grappa::mycore(), this->source_ );
      list_->push(this);
    }

    Grappa::Message<T>::mark_sent();
  }
};

// completion message handler
struct C {
  GlobalAddress< Grappa::CompletionEvent > ce;
  void operator()() {
    DVLOG(5) << "Received completion at node " << Grappa::mycore()
             << " with target " << ce.node()
             << " address " << ce.pointer();
    ce.pointer()->complete();
    gups_completions_received++;
  }
};

// list of free completion messages
Grappa::impl::ReuseList< ReuseMessage<C> > completion_list;
void completion_list_push( ReuseMessage<C> * c ) {
  completion_list.push(c);
}

// GUPS request message handler
struct M {
  // address to increment
  GlobalAddress< int64_t > addr;
  // address of completion counter
  GlobalAddress< Grappa::CompletionEvent > ce;

  // once we have a message to use, do this
  static void complete( ReuseMessage<C> * message, GlobalAddress< Grappa::CompletionEvent > event ) {
    gups_completions_sent++;
    message->reset();
    (*message)->ce = event;
    message->enqueue( event.node() );
    completions_sent[ event.node() ];
  }

  void operator()() {
    DVLOG(5) << "Received GUP at node " << Grappa::mycore()
             << " with target " << addr.node()
             << " address " << addr.pointer()
             << " reply to " << ce.node()
             << " with address " << ce.pointer();
    gups_requests_received++;

    // increment address
    int64_t * ptr = addr.pointer();
    *ptr++;

    // now send completion
    // is the completion local?
    if (ce.node() == Grappa::mycore()) {
      // yes, so just do it.
      ce.pointer()->complete();
      gups_completions_sent++;
      completions_sent[ ce.node() ];
    } else {
      // we need to send a message
      // try to grab a message
      ReuseMessage<C> * c = NULL;
      if( (c = completion_list.try_pop()) != NULL ) {
        // got one; send completion
        M::complete( c, ce );
      } else {
        gups_completions_blocked++;
        // we need to block, so spawn a task
        auto my_ce = ce;
        Grappa::privateTask( [this, my_ce] { // this actually unused
            ReuseMessage<C> * c = completion_list.block_until_pop();
            M::complete( c, my_ce );
          });
      }
    }
  }
};

// list of free request messages
Grappa::impl::ReuseList< ReuseMessage<M> > message_list;
void message_list_push( ReuseMessage<M> * m ) {
  message_list.push(m);
}

// keep track of this core's completions
Grappa::CompletionEvent ce;

double wall_clock_time() {
  const double nano = 1.0e-9;
  timespec t;
  clock_gettime( CLOCK_MONOTONIC, &t );
  return nano * t.tv_nsec + t.tv_sec;
}

BOOST_AUTO_TEST_SUITE( Gups_tests );

LOOP_FUNCTION( func_start_profiling, index ) {
  Grappa_start_profiling();
}

LOOP_FUNCTION( func_stop_profiling, index ) {
  Grappa_stop_profiling();
  //Grappa::Statistics::print();
}

/// Functor to execute one GUP.
static GlobalAddress<int64_t> Array;
static int64_t * base;
LOOP_FUNCTOR( func_gups, index, ((GlobalAddress<int64_t>, _Array)) ) {
  Array = _Array;
  base = Array.localize();
}

void func_gups_x(int64_t * p) {
  const uint64_t LARGE_PRIME = 18446744073709551557UL;
  /* across all nodes and all calls, each instance of index in [0.. iterations)
  ** must be encounted exactly once */
  //uint64_t index = random() + Grappa_mynode();//(p - base) * Grappa_nodes() + Grappa_mynode();
  //uint64_t b = (index*LARGE_PRIME) % FLAGS_sizeA;

  static uint64_t index = 1;
  //uint64_t b = ((Grappa_mynode() + index++) *LARGE_PRIME) & 1023;
  uint64_t b = ((Grappa_mynode() + index++) *LARGE_PRIME) % FLAGS_sizeA;

  //fprintf(stderr, "%d ", b);
  ff_delegate_add( Array + b, (const int64_t &) 1 );
}
void validate(GlobalAddress<uint64_t> A, size_t n) {
  int total = 0, max = 0, min = INT_MAX;
  double sum_sqr = 0.0;
  for (int i = 0; i < n; i++) {
    //int tmp = Grappa_delegate_read_word(A+i);
    int tmp = Grappa::delegate::read(A+i);
    total += tmp;
    sum_sqr += tmp*tmp;
    max = tmp > max ? tmp : max;
    min = tmp < min ? tmp : min;
  }
  // fprintf(stderr, "Validation:  total updates %d; min %d; max %d; avg value %g; std dev %g\n",
  //         total, min, max, total/((double)n), sqrt(sum_sqr/n - ((total/n)*total/n)));
}

LOOP_FUNCTION( func_gups_rdma, index ) {
  //void func_gups_x(int64_t * p) {
  const uint64_t LARGE_PRIME = 18446744073709551557UL;
  const uint64_t each_iters = FLAGS_iterations / Grappa::cores();
  const uint64_t my_start = each_iters * Grappa::mycore();

  //exit(123);

  DVLOG(1) << "Initializing RDMA GUPS....";

  // record how many messages we plan to send
  ce.enroll( each_iters );

  DVLOG(1) << "Starting RDMA GUPS";
  for( uint64_t index = my_start; index < my_start + each_iters; ++index ) {
    DCHECK_LT( index, FLAGS_iterations ) << "index exploded!";

    // compute address to increment
    uint64_t b = (index * LARGE_PRIME) % FLAGS_sizeA;
    auto a = Array + b;

    // get a message to use to send
    ReuseMessage<M> * m = message_list.block_until_pop();

    // send
    m->reset();
    (*m)->addr = a;
    (*m)->ce = make_global( &ce );
    m->enqueue( a.node() );
    gups_requests_sent++;
    requests_sent[a.node()]++;
    DVLOG(5) << "Sent GUP from node " << Grappa::mycore()
             << " to " << a.node()
             << " address " << a.pointer()
             << " reply to address " << &ce;

  }

  DVLOG(1) << "Done sending; now waiting for replies";
  ce.wait();

  DVLOG(1) << "Got all replies";
}

void user_main( int * args ) {

  //fprintf(stderr, "Entering user_main\n");
  func_start_profiling start_profiling;
  func_stop_profiling stop_profiling;

  //CHECK_EQ( FLAGS_sizeA, 1024 ) << "sizeA must be 1024 unless you switch back to mods";
  CHECK_EQ( FLAGS_load_balance, "none" ) << "load balancing must be disabled unless you change the iteration approach";

  GlobalAddress<int64_t> A = Grappa_typed_malloc<int64_t>(FLAGS_sizeA);

  //fprintf(stderr, "user_main: Allocated global array of %d integers\n", FLAGS_sizeA);
  //fprintf(stderr, "user_main: Will run %d iterations\n", FLAGS_iterations);

  func_gups gups( A );

  func_gups_rdma gups_rdma;

    double runtime = 0.0;
    double throughput = 0.0;
    int nnodes = atoi(getenv("SLURM_NNODES"));
    double throughput_per_node = 0.0;

    Grappa_add_profiling_value( &runtime, "runtime", "s", false, 0.0 );
    Grappa_add_profiling_integer( &FLAGS_iterations, "iterations", "it", false, 0 );
    Grappa_add_profiling_integer( &FLAGS_sizeA, "sizeA", "entries", false, 0 );
    Grappa_add_profiling_value( &throughput, "updates_per_s", "up/s", false, 0.0 );
    Grappa_add_profiling_value( &throughput_per_node, "updates_per_s_per_node", "up/s", false, 0.0 );

  do {

    LOG(INFO) << "Starting";
    Grappa_memset_local(A, 0, FLAGS_sizeA);
    LOG(INFO) << "Start profiling";
    fork_join_custom( &start_profiling );

    LOG(INFO) << "Do something";
    double start = wall_clock_time();
    fork_join_custom( &gups );
    //printf ("Yeahoow!\n");
    if( FLAGS_rdma ) {
      LOG(INFO) << "Starting RDMA";
      fork_join_custom( &gups_rdma );
    } else {
      forall_local <int64_t, func_gups_x> (A, FLAGS_iterations);
    }
    double end = wall_clock_time();

    fork_join_custom( &stop_profiling );

    runtime = end - start;
    throughput = FLAGS_iterations / runtime;

    throughput_per_node = throughput/nnodes;
    Grappa::Statistics::merge_and_print();

    if( FLAGS_validate ) {
      LOG(INFO) << "Validating....";
      validate(A, FLAGS_sizeA);
    }

    // LOG(INFO) << "GUPS: "
    //         << FLAGS_iterations << " updates at "
    //         << throughput << "updates/s ("
    //         << throughput/nnodes << " updates/s/node).";
   } while (FLAGS_repeats-- > 1);
  LOG(INFO) << "Done. ";
}

BOOST_AUTO_TEST_CASE( test1 ) {
    Grappa_init( &(boost::unit_test::framework::master_test_suite().argc),
		  &(boost::unit_test::framework::master_test_suite().argv) );
    Grappa_activate();

    requests_sent = new uint64_t[ Grappa::cores() ];
    completions_sent = new uint64_t[ Grappa::cores() ];
    for( int i = 0; i < Grappa::cores(); ++i ) {
      requests_sent[i] = 0;
      completions_sent[i] = 0;
    }

    // prepare pools of messages
    auto msgs = Grappa::impl::locale_shared_memory.segment.construct< ReuseMessage<M> >(boost::interprocess::anonymous_instance)[ FLAGS_outstanding ]();
    auto completions = Grappa::impl::locale_shared_memory.segment.construct< ReuseMessage<C> >(boost::interprocess::anonymous_instance)[ FLAGS_outstanding ]();
    for( int i = 0; i < FLAGS_outstanding; ++i ) {
      msgs[i].list_ = &message_list;
      message_list.push( &msgs[i] );
      completions[i].list_ = &completion_list;
      completion_list.push( &completions[i] );
    }

    Grappa_run_user_main( &user_main, (int*)NULL );

    Grappa_finish( 0 );
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>#include "entityx/entityx.h"
#include "game.hpp"
#include "events.hpp"
#include "component_orb.hpp"
#include "component_position.hpp"
#include "component_drawable.hpp"
#include "component_player.hpp"
#include "component_collectable.hpp"
#include "component_collidable.hpp"
#include "component_light.hpp"
#include "anim_template.hpp"
#include "game_config.hpp"

#ifdef __EMSCRIPTEN__
#include <SDL/SDL_mixer.h>
#else
#include <SDL_mixer.h>
#endif

#include <iostream>
#include <vector>
#include <cstdlib>

#include <glm/gtc/random.hpp>

class OrbSpawnSystem : public entityx::System<OrbSpawnSystem>,
                       public entityx::Receiver<OrbSpawnSystem> {
  public:
    OrbSpawnSystem(Game *game, entityx::EntityManager &entities, float min_dist, float max_dist)
        : m_min_dist(min_dist), m_max_dist(max_dist), m_game(game), m_entities(entities) {
    }

    ~OrbSpawnSystem() {
    }

    void configure(entityx::EventManager &event_manager) override {
        event_manager.subscribe<CollisionEvent>(*this);

        // Add initial orbs
        for (int i = 0; i < MAX_ORBS; ++i) {
            spawn_next(0.01667f);
        }
    }

    void update(entityx::EntityManager &es, entityx::EventManager &events,
                entityx::TimeDelta dt) override {
        (void)events;

        // Figure out whether we have to spawn a new orb

        auto count_orbs = 0;
        entityx::ComponentHandle<Orb> orb;
        for (entityx::Entity entity : es.entities_with_components(orb)) {
            (void)entity;
            count_orbs += 1;
        }

        if (count_orbs < MAX_ORBS) {
            spawn_next(dt);
        }

        // Deletion logic below
        std::vector<entityx::Entity> new_vec;
        for (auto e : orbs_to_delete) {
            // If there are orbs to delete, remove them gently with a nice animation
            auto o = e.component<Orb>();
            if (o) {
                e.remove<Collidable>();
                e.remove<Light>();
                e.remove<Orb>();
                e.remove<Collectable>();
                Mix_PlayChannel(1, m_game->res_manager().sound("sound2"), 0);
                m_game->m_orbs_collected += 1;
            }
            auto pos = e.component<Position>();
            auto np = pos->position();
            np.x -= 80.f / glm::sqrt(np.x);
            pos->set_position(np);

            if (pos->position().x < 30) {
                // If they are very close to the fire, actually remove them
                e.destroy();
            } else {
                new_vec.push_back(e);
            }
        }
        orbs_to_delete.clear();
        orbs_to_delete.insert(orbs_to_delete.end(), new_vec.begin(), new_vec.end());
    }

    void receive(const CollisionEvent &event) {
        auto copy = event;
        auto e = copy.m_first.component<Orb>();
        auto p = copy.m_second.component<Player>();
        if (e && p) {
            orbs_to_delete.push_back(copy.m_first);
        }
    }

  private:
    void spawn_next(float dt) {
        // auto radius = (RING_OUTER + RING_INNER) / 2.f;
        auto radius = glm::linearRand(RING_OUTER, RING_INNER + 50.f);
        glm::vec2 new_pos{radius, m_last_pos[1] - 50.f * dt};
        m_last_pos = new_pos;
        AnimTemplate anim(12, 12, 6, 0, 10);
        entityx::Entity orb = m_entities.create();
        orb.assign<Position>(new_pos);
        orb.assign<Drawable>("orb", 16, 16, 8, anim);
        orb.assign<Collectable>();
        orb.assign<Collidable>(10);
        orb.assign<Light>("gradient", 0.30f, glm::vec3{100, 100, 255});
        orb.assign<Orb>();
        //std::cout << "spawning at " << dt << " " << glm::to_string(new_pos) << std::endl;
    }

    float m_min_dist;
    float m_max_dist;

    glm::vec2 m_last_pos{0, -1.f};

    Game *m_game;
    std::vector<entityx::Entity> orbs_to_delete;
    entityx::EntityManager &m_entities;
};
<commit_msg>voided some vars<commit_after>#include "entityx/entityx.h"
#include "game.hpp"
#include "events.hpp"
#include "component_orb.hpp"
#include "component_position.hpp"
#include "component_drawable.hpp"
#include "component_player.hpp"
#include "component_collectable.hpp"
#include "component_collidable.hpp"
#include "component_light.hpp"
#include "anim_template.hpp"
#include "game_config.hpp"

#ifdef __EMSCRIPTEN__
#include <SDL/SDL_mixer.h>
#else
#include <SDL_mixer.h>
#endif

#include <iostream>
#include <vector>
#include <cstdlib>

#include <glm/gtc/random.hpp>

class OrbSpawnSystem : public entityx::System<OrbSpawnSystem>,
                       public entityx::Receiver<OrbSpawnSystem> {
  public:
    OrbSpawnSystem(Game *game, entityx::EntityManager &entities, float min_dist, float max_dist)
        : m_min_dist(min_dist), m_max_dist(max_dist), m_game(game), m_entities(entities) {
        (void)m_min_dist;
        (void)m_max_dist;
    }

    ~OrbSpawnSystem() {
    }

    void configure(entityx::EventManager &event_manager) override {
        event_manager.subscribe<CollisionEvent>(*this);

        // Add initial orbs
        for (int i = 0; i < MAX_ORBS; ++i) {
            spawn_next(0.01667f);
        }
    }

    void update(entityx::EntityManager &es, entityx::EventManager &events,
                entityx::TimeDelta dt) override {
        (void)events;

        // Figure out whether we have to spawn a new orb

        auto count_orbs = 0;
        entityx::ComponentHandle<Orb> orb;
        for (entityx::Entity entity : es.entities_with_components(orb)) {
            (void)entity;
            count_orbs += 1;
        }

        if (count_orbs < MAX_ORBS) {
            spawn_next(dt);
        }

        // Deletion logic below
        std::vector<entityx::Entity> new_vec;
        for (auto e : orbs_to_delete) {
            // If there are orbs to delete, remove them gently with a nice animation
            auto o = e.component<Orb>();
            if (o) {
                e.remove<Collidable>();
                e.remove<Light>();
                e.remove<Orb>();
                e.remove<Collectable>();
                Mix_PlayChannel(1, m_game->res_manager().sound("sound2"), 0);
                m_game->m_orbs_collected += 1;
            }
            auto pos = e.component<Position>();
            auto np = pos->position();
            np.x -= 80.f / glm::sqrt(np.x);
            pos->set_position(np);

            if (pos->position().x < 30) {
                // If they are very close to the fire, actually remove them
                e.destroy();
            } else {
                new_vec.push_back(e);
            }
        }
        orbs_to_delete.clear();
        orbs_to_delete.insert(orbs_to_delete.end(), new_vec.begin(), new_vec.end());
    }

    void receive(const CollisionEvent &event) {
        auto copy = event;
        auto e = copy.m_first.component<Orb>();
        auto p = copy.m_second.component<Player>();
        if (e && p) {
            orbs_to_delete.push_back(copy.m_first);
        }
    }

  private:
    void spawn_next(float dt) {
        // auto radius = (RING_OUTER + RING_INNER) / 2.f;
        auto radius = glm::linearRand(RING_OUTER, RING_INNER + 50.f);
        glm::vec2 new_pos{radius, m_last_pos[1] - 50.f * dt};
        m_last_pos = new_pos;
        AnimTemplate anim(12, 12, 6, 0, 10);
        entityx::Entity orb = m_entities.create();
        orb.assign<Position>(new_pos);
        orb.assign<Drawable>("orb", 16, 16, 8, anim);
        orb.assign<Collectable>();
        orb.assign<Collidable>(10);
        orb.assign<Light>("gradient", 0.30f, glm::vec3{100, 100, 255});
        orb.assign<Orb>();
        //std::cout << "spawning at " << dt << " " << glm::to_string(new_pos) << std::endl;
    }

    float m_min_dist;
    float m_max_dist;

    glm::vec2 m_last_pos{0, -1.f};

    Game *m_game;
    std::vector<entityx::Entity> orbs_to_delete;
    entityx::EntityManager &m_entities;
};
<|endoftext|>


<commit_before>#include <vector>

struct code_stream {
    public:
        code_stream(unsigned char* buf, unsigned long len)
                :buf_(buf)
                ,byte_pos_(0)
                ,bit_pos_(0)
                ,len_(len)
        { }
        unsigned short getbit() {
            unsigned char val = buf_[byte_pos_];
            unsigned short res = (val & (1 << (8-bit_pos_)));
            ++bit_pos_;
            if (bit_pos_ == 8) {
                bit_pos_ = 0;
                ++byte_pos_;
                if (byte_pos_ > len_) {
                    throw "overboard";
                }
            }
            return res;
        }
        unsigned short get(int nbits) {
            unsigned short res = 0;
            for (int i = 0; i != nbits; ++i) {
                res <<= 1;
                res |= getbit();
            }
            return res;
        }
    private:
        const unsigned char* buf_;
        int byte_pos_;
        int bit_pos_;
        const int len_;
};

std::string table_at(const std::vector<std::string> table, unsigned short index) {
    if (index < 256) {
        std::string res = "0";
        res[0] = (char)index;
        return res;
    }
    return table.at(index - 258);
}

void write_string(std::vector<unsigned char>& output, std::string s) {
    output.insert(output.end(), s.begin(), s.end());
}

std::vector<unsigned char> lzw_decode(void* buf, unsigned long len) {
    std::vector<std::string> table;
    std::vector<unsigned char> output;
    code_stream st(static_cast<unsigned char*>(buf), len);

    int nbits = 9;
    unsigned short old_code = 0;
    const short ClearCode = 256;
    const short EoiCode = 257;
    while (true) {
        const short code = st.get(nbits);
        if (code == EoiCode) break;
        if (code == ClearCode) {
            table.clear();
            nbits = 9;
            const short next_code = st.get(nbits);
            if (next_code == EoiCode) break;
            write_string(output, table[next_code]);
            old_code = next_code;
        } else if (code < 256 || (code - 258) < table.size()) {
            write_string(output, table_at(table,code));
            table.push_back(
                    table_at(table,old_code) + table_at(table,code)[0]
                    );
            old_code = code;
        } else {
            std::string out_string = table_at(table, old_code) + table_at(table, old_code)[0];
            write_string(output, out_string);
            table.push_back(out_string);
            if (table.size() == ( 512-258)) nbits = 10;
            if (table.size() == (1024-258)) nbits = 11;
            if (table.size() == (2048-258)) nbits = 12;
            old_code = code;
        }
   }
   return output;
}
<commit_msg>DOC This is MIT licensed<commit_after>// Copyright 2012 Luis Pedro Coelho
// This is an implementation of TIFF LZW compression coded from the spec.
// License: MIT

#include <vector>

struct code_stream {
    public:
        code_stream(unsigned char* buf, unsigned long len)
                :buf_(buf)
                ,byte_pos_(0)
                ,bit_pos_(0)
                ,len_(len)
        { }
        unsigned short getbit() {
            unsigned char val = buf_[byte_pos_];
            unsigned short res = (val & (1 << (8-bit_pos_)));
            ++bit_pos_;
            if (bit_pos_ == 8) {
                bit_pos_ = 0;
                ++byte_pos_;
                if (byte_pos_ > len_) {
                    throw "overboard";
                }
            }
            return res;
        }
        unsigned short get(int nbits) {
            unsigned short res = 0;
            for (int i = 0; i != nbits; ++i) {
                res <<= 1;
                res |= getbit();
            }
            return res;
        }
    private:
        const unsigned char* buf_;
        int byte_pos_;
        int bit_pos_;
        const int len_;
};

std::string table_at(const std::vector<std::string> table, unsigned short index) {
    if (index < 256) {
        std::string res = "0";
        res[0] = (char)index;
        return res;
    }
    return table.at(index - 258);
}

void write_string(std::vector<unsigned char>& output, std::string s) {
    output.insert(output.end(), s.begin(), s.end());
}

std::vector<unsigned char> lzw_decode(void* buf, unsigned long len) {
    std::vector<std::string> table;
    std::vector<unsigned char> output;
    code_stream st(static_cast<unsigned char*>(buf), len);

    int nbits = 9;
    unsigned short old_code = 0;
    const short ClearCode = 256;
    const short EoiCode = 257;
    while (true) {
        const short code = st.get(nbits);
        if (code == EoiCode) break;
        if (code == ClearCode) {
            table.clear();
            nbits = 9;
            const short next_code = st.get(nbits);
            if (next_code == EoiCode) break;
            write_string(output, table[next_code]);
            old_code = next_code;
        } else if (code < 256 || (code - 258) < table.size()) {
            write_string(output, table_at(table,code));
            table.push_back(
                    table_at(table,old_code) + table_at(table,code)[0]
                    );
            old_code = code;
        } else {
            std::string out_string = table_at(table, old_code) + table_at(table, old_code)[0];
            write_string(output, out_string);
            table.push_back(out_string);
            if (table.size() == ( 512-258)) nbits = 10;
            if (table.size() == (1024-258)) nbits = 11;
            if (table.size() == (2048-258)) nbits = 12;
            old_code = code;
        }
   }
   return output;
}
<|endoftext|>