<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 <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/foreach.hpp>
#include <bh.h>
#include <vector>
#include <map>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include "bh_ir.h"
#include "bh_fuse.h"

using namespace std;
using namespace boost;
namespace io = boost::iostreams;

/* Creates a Bohrium Internal Representation (BhIR) from a instruction list.
*
* @ninstr      Number of instructions
* @instr_list  The instruction list
*/
bh_ir::bh_ir(bh_intp ninstr, const bh_instruction instr_list[])
{
    bh_ir::instr_list = vector<bh_instruction>(instr_list, &instr_list[ninstr]);
}

/* Creates a BhIR from a serialized BhIR.
*
* @bhir The BhIr serialized as a char array or vector
*/
bh_ir::bh_ir(const char bhir[], bh_intp size)
{
    io::basic_array_source<char> source(bhir,size);
    io::stream<io::basic_array_source <char> > input_stream(source);
    archive::binary_iarchive ia(input_stream);
    ia >> *this;
}

/* Serialize the BhIR object into a char buffer
*  (use the bh_ir constructor for deserialization)
*
*  @buffer   The char vector to serialize into
*/
void bh_ir::serialize(vector<char> &buffer) const
{
    io::stream<io::back_insert_device<vector<char> > > output_stream(buffer);
    archive::binary_oarchive oa(output_stream);
    oa << *this;
    output_stream.flush();
}

/* Returns the cost of the BhIR */
uint64_t bh_ir::cost() const
{
    uint64_t sum = 0;
    BOOST_FOREACH(const bh_ir_kernel &k, kernel_list)
    {
        sum += k.cost();
    }
    return sum;
}

/* Pretty print the kernel list */
void bh_ir::pprint_kernel_list() const
{
    char msg[100]; int i=0;
    BOOST_FOREACH(const bh_ir_kernel &k, kernel_list)
    {
        snprintf(msg, 100, "kernel-%d", i++);
        bh_pprint_instr_krnl(&k, msg);
    }
}

void bh_ir_kernel::add_instr(uint64_t instr_idx)
{

    /* Help function that checks if aligned view 'v' exist in 'views' */
    struct
    {
        bool operator()(const bh_view &v, const vector<bh_view> &views)
        {
            BOOST_FOREACH(const bh_view &i, views)
            {
                if(bh_view_aligned(&v, &i))
                    return true;
            }
            return false;
        }
    }aligned_view_exist;

    const bh_instruction& instr = bhir->instr_list[instr_idx];

    if(instr.opcode == BH_DISCARD)
    {
        //When discarding we might have to remove arrays from 'outputs' and 'temps'
        const bh_base *base = instr.operand[0].base;
        for(vector<bh_view>::iterator it=outputs.begin(); it != outputs.end(); ++it)
        {
            if(base == it->base)
            {
                outputs.erase(it);

                //If the discarded array isn't in 'inputs' (and not in 'outputs')
                //than it is a temp array
                if(not aligned_view_exist(*it, inputs))
                   temps.push_back(base);
                break;
            }
        }
    }
    else if(instr.opcode != BH_FREE)
    {
        //Add the output of the instruction to 'outputs'
        if(not aligned_view_exist(instr.operand[0], outputs))
            outputs.push_back(instr.operand[0]);

        //Add the inputs of the instruction to 'inputs'
        const int nop = bh_operands(instr.opcode);
        for(int i=1; i<nop; ++i)
        {
            const bh_view &v = instr.operand[i];
            if(bh_is_constant(&v))
                continue;

            //If 'v' is in 'inputs' already we can continue
            if(aligned_view_exist(v, inputs))
                continue;

            //Additionally, we shouldn't add 'v' to 'inputs' if it is
            //the output of an existing instruction.
            bool local_source = false;
            BOOST_FOREACH(uint64_t idx, instr_indexes)
            {
                if(bh_view_aligned(&v, &bhir->instr_list[idx].operand[0]))
                {
                    local_source = true;
                    break;
                }
            }
            if(!local_source)
                inputs.push_back(v);
        }
    }
    instr_indexes.push_back(instr_idx);
};

/* Determines whether all instructions in 'this' kernel
 * are system opcodes (e.g. BH_DISCARD, BH_FREE, etc.)
 *
 * @return The boolean answer
 */
bool bh_ir_kernel::only_system_opcodes() const
{
    BOOST_FOREACH(uint64_t this_idx, instr_indexes)
    {
        if(not bh_opcode_is_system(bhir->instr_list[this_idx].opcode))
            return false;
    }
    return true;
}

/* Determines whether the kernel fusible legal
 *
 * @return The boolean answer
 */
bool bh_ir_kernel::fusible() const
{
    for(uint64_t i=0; i<instr_indexes.size(); ++i)
    {
        const bh_instruction *instr = &bhir->instr_list[instr_indexes[i]];
        for(uint64_t j=i+1; j<instr_indexes.size(); ++j)
        {
            if(not bohrium::check_fusible(instr, &bhir->instr_list[instr_indexes[j]]))
                return false;
        }
    }
    return true;
}

/* Determines whether it is legal to fuse with the instruction
 *
 * @instr_idx  The index of the instruction
 * @return     The boolean answer
 */
bool bh_ir_kernel::fusible(uint64_t instr_idx) const
{
    const bh_instruction *instr = &bhir->instr_list[instr_idx];
    BOOST_FOREACH(uint64_t i, instr_indexes)
    {
        if(not bohrium::check_fusible(instr, &bhir->instr_list[i]))
            return false;
    }
    return true;
}

/* Determines whether it is legal to fuse with the kernel
 *
 * @other  The other kernel
 * @return The boolean answer
 */
bool bh_ir_kernel::fusible(const bh_ir_kernel &other) const
{
    BOOST_FOREACH(uint64_t idx1, instr_indexes)
    {
        const bh_instruction *instr = &bhir->instr_list[idx1];
        BOOST_FOREACH(uint64_t idx2, other.instr_indexes)
        {
            if(not bohrium::check_fusible(instr, &other.bhir->instr_list[idx2]))
                return false;
        }
    }
    return true;
}

/* Determines whether it is legal to fuse with the instruction
 * without changing 'this' kernel's dependencies.
 *
 * @instr_idx  The index of the instruction
 * @return     The boolean answer
 */
bool bh_ir_kernel::fusible_gently(uint64_t instr_idx) const
{
    const bh_instruction &instr = bhir->instr_list[instr_idx];

    //Check that 'instr' is gentle fusible with at least one existing instruction
    //that is not a system opcode (unless all instructions in 'this' kernel are
    //system opcodes)
    if(only_system_opcodes())
    {
        BOOST_FOREACH(uint64_t this_idx, instr_indexes)
        {
            const bh_instruction &this_instr = bhir->instr_list[this_idx];
            if(bh_instr_fusible_gently(&instr, &this_instr) &&
               bohrium::check_fusible(&instr, &this_instr))
                return true;
        }
    }
    else
    {
        BOOST_FOREACH(uint64_t this_idx, instr_indexes)
        {
            const bh_instruction &this_instr = bhir->instr_list[this_idx];
            if(bh_opcode_is_system(this_instr.opcode))
                continue;

            if(bh_instr_fusible_gently(&instr, &this_instr) &&
               bohrium::check_fusible(&instr, &this_instr))
                return true;
        }
    }
    return false;
}

/* Determines whether it is legal to fuse with the kernel without
 * changing 'this' kernel's dependencies.
 *
 * @other  The other kernel
 * @return The boolean answer
 */
bool bh_ir_kernel::fusible_gently(const bh_ir_kernel &other) const
{

    //When all instructions in the 'other' kernel are system opcodes
    //only one of the instructions needs to be gentle fusible.
    if(other.only_system_opcodes())
    {
        BOOST_FOREACH(uint64_t other_idx, other.instr_indexes)
        {
            if(fusible_gently(other_idx))
                return true;
        }
        return false;
    }
    else
    {
        //Check that each instruction in 'other' is gentle fusible
        //with 'this' kernel while ignoring system opcodes.
        BOOST_FOREACH(uint64_t other_idx, other.instr_indexes)
        {
            if(bh_opcode_is_system(bhir->instr_list[other_idx].opcode))
                continue;
            if(not fusible_gently(other_idx))
                return false;
        }
    }
    return true;
}

/* Determines dependency between 'this' kernel and the instruction 'instr',
 * which is true when:
 *      'instr' writes to an array that 'this' access
 *                        or
 *      'this' writes to an array that 'instr' access
 *
 * @instr_idx  The index of the instruction
 * @return     0: no dependency
 *             1: this kernel depend on 'instr'
 *            -1: 'instr' depend on this kernel
 */
int bh_ir_kernel::dependency(uint64_t instr_idx) const
{
    int ret = 0;
    BOOST_FOREACH(uint64_t this_idx, instr_indexes)
    {
        if(bh_instr_dependency(&bhir->instr_list[instr_idx],
                               &bhir->instr_list[this_idx]))
        {
            if(this_idx >= instr_idx)
            {
                assert(ret == 0 or ret == 1);//Check for cyclic dependency
                ret = 1;
                //TODO: return 'ret' here, but for now we check all instructions
            }
            else
            {
                assert(ret == 0 or ret == -1);//Check for cyclic dependency
                ret = -1;
                //TODO: return 'ret' here, but for now we check all instructions
            }
        }
    }
    return ret;
}

/* Determines dependency between this kernel and 'other',
 * which is true when:
 *      'other' writes to an array that 'this' access
 *                        or
 *      'this' writes to an array that 'other' access
 *
 * @other    The other kernel
 * @return   0: no dependency
 *           1: this kernel depend on 'other'
 *          -1: 'other' depend on this kernel
 */
int bh_ir_kernel::dependency(const bh_ir_kernel &other) const
{
    int ret = 0;
    BOOST_FOREACH(uint64_t other_idx, other.instr_indexes)
    {
        const int dep = dependency(other_idx);
        if(dep != 0)
        {
            assert(ret == 0 or ret == dep);//Check for cyclic dependency
            ret = dep;
            //TODO: return 'ret' here, but for now we check all instructions
        }
    }
    return ret;
}

/* Returns the cost of a bh_view */
inline static uint64_t cost_of_view(const bh_view &v)
{
    return bh_nelements_nbcast(&v) * bh_type_size(v.base->type);
}

/* Returns the cost of the kernel */
uint64_t bh_ir_kernel::cost() const
{
    uint64_t sum = 0;
    BOOST_FOREACH(const bh_view &v, input_list())
    {
        sum += cost_of_view(v);
    }
    BOOST_FOREACH(const bh_view &v, output_list())
    {
        sum += cost_of_view(v);
    }
    return sum;
}

/* Returns the cost savings of merging with the 'other' kernel.
 * The cost savings is defined as the amount the BhIR will drop
 * in price if the two kernels are fused.
 * NB: This function determens the dependency order between the
 * two kernels and calculate the cost saving based on that order.
 *
 * @other  The other kernel
 * @return The cost value. Returns -1 if 'this' and the 'other'
 *         kernel isn't fusible.
 */
int64_t bh_ir_kernel::merge_cost_savings(const bh_ir_kernel &other) const
{
    if(this == &other)
        return 0;

    if(not fusible(other))
        return -1;

    const bh_ir_kernel *a;
    const bh_ir_kernel *b;
    //Lets make sure that 'a' depend on 'b'
    if(this->dependency(other) == 1)
    {
        a = this;
        b = &other;
    }
    else
    {
        a = &other;
        b = this;
    }

    int64_t price_drop = 0;

    //Subtract inputs in 'a' that comes from 'b' or is already an input in 'b'
    BOOST_FOREACH(const bh_view &i, a->input_list())
    {
        BOOST_FOREACH(const bh_view &o, b->output_list())
        {
            if(bh_view_aligned(&i, &o))
                price_drop += cost_of_view(i);
        }
        BOOST_FOREACH(const bh_view &o, b->input_list())
        {
            if(bh_view_aligned(&i, &o))
                price_drop += cost_of_view(i);
        }
    }
    //Subtract outputs from 'b' that are discared in 'a'
    BOOST_FOREACH(const bh_view &o, b->output_list())
    {
        BOOST_FOREACH(uint64_t a_instr_idx, a->instr_indexes)
        {
            const bh_instruction &a_instr = a->bhir->instr_list[a_instr_idx];
            if(a_instr.opcode == BH_DISCARD and a_instr.operand[0].base == o.base)
            {
                price_drop += cost_of_view(o);
                break;
            }
        }
    }
    return price_drop;
}

<commit_msg>bhir: now bh_ir_kernel::add_instr() only add arrays to 'temps' when they are not previously synchronized<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 <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/foreach.hpp>
#include <bh.h>
#include <vector>
#include <map>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include "bh_ir.h"
#include "bh_fuse.h"

using namespace std;
using namespace boost;
namespace io = boost::iostreams;

/* Creates a Bohrium Internal Representation (BhIR) from a instruction list.
*
* @ninstr      Number of instructions
* @instr_list  The instruction list
*/
bh_ir::bh_ir(bh_intp ninstr, const bh_instruction instr_list[])
{
    bh_ir::instr_list = vector<bh_instruction>(instr_list, &instr_list[ninstr]);
}

/* Creates a BhIR from a serialized BhIR.
*
* @bhir The BhIr serialized as a char array or vector
*/
bh_ir::bh_ir(const char bhir[], bh_intp size)
{
    io::basic_array_source<char> source(bhir,size);
    io::stream<io::basic_array_source <char> > input_stream(source);
    archive::binary_iarchive ia(input_stream);
    ia >> *this;
}

/* Serialize the BhIR object into a char buffer
*  (use the bh_ir constructor for deserialization)
*
*  @buffer   The char vector to serialize into
*/
void bh_ir::serialize(vector<char> &buffer) const
{
    io::stream<io::back_insert_device<vector<char> > > output_stream(buffer);
    archive::binary_oarchive oa(output_stream);
    oa << *this;
    output_stream.flush();
}

/* Returns the cost of the BhIR */
uint64_t bh_ir::cost() const
{
    uint64_t sum = 0;
    BOOST_FOREACH(const bh_ir_kernel &k, kernel_list)
    {
        sum += k.cost();
    }
    return sum;
}

/* Pretty print the kernel list */
void bh_ir::pprint_kernel_list() const
{
    char msg[100]; int i=0;
    BOOST_FOREACH(const bh_ir_kernel &k, kernel_list)
    {
        snprintf(msg, 100, "kernel-%d", i++);
        bh_pprint_instr_krnl(&k, msg);
    }
}

void bh_ir_kernel::add_instr(uint64_t instr_idx)
{

    /* Help function that checks if aligned view 'v' exist in 'views' */
    struct
    {
        bool operator()(const bh_view &v, const vector<bh_view> &views)
        {
            BOOST_FOREACH(const bh_view &i, views)
            {
                if(bh_view_aligned(&v, &i))
                    return true;
            }
            return false;
        }
    }aligned_view_exist;

    /* Help function that checks if 'b' is synchronized in kernel 'k' */
    struct
    {
        bool operator()(const bh_ir_kernel &k, const bh_base *b)
        {
            BOOST_FOREACH(uint64_t idx, k.instr_indexes)
            {
                const bh_instruction &instr = k.bhir->instr_list[idx];
                if(instr.opcode == BH_SYNC and instr.operand[0].base == b)
                    return true;
            }
            return false;
        }
    }is_base_synced;

    const bh_instruction& instr = bhir->instr_list[instr_idx];
    if(instr.opcode == BH_DISCARD)
    {
        //When discarding we might have to remove arrays from 'outputs' and 'temps'
        //if the discared array isn't synchronized
        const bh_base *base = instr.operand[0].base;
        if(not is_base_synced(*this, base))
        {
            for(vector<bh_view>::iterator it=outputs.begin(); it != outputs.end(); ++it)
            {
                if(base == it->base)
                {
                    outputs.erase(it);

                    //If the discarded array isn't in 'inputs' (and not in 'outputs')
                    //than it is a temp array
                    if(not aligned_view_exist(*it, inputs))
                       temps.push_back(base);
                    break;
                }
            }
        }
    }
    else if(instr.opcode != BH_FREE)
    {
        //Add the output of the instruction to 'outputs'
        if(not aligned_view_exist(instr.operand[0], outputs))
            outputs.push_back(instr.operand[0]);

        //Add the inputs of the instruction to 'inputs'
        const int nop = bh_operands(instr.opcode);
        for(int i=1; i<nop; ++i)
        {
            const bh_view &v = instr.operand[i];
            if(bh_is_constant(&v))
                continue;

            //If 'v' is in 'inputs' already we can continue
            if(aligned_view_exist(v, inputs))
                continue;

            //Additionally, we shouldn't add 'v' to 'inputs' if it is
            //the output of an existing instruction.
            bool local_source = false;
            BOOST_FOREACH(uint64_t idx, instr_indexes)
            {
                if(bh_view_aligned(&v, &bhir->instr_list[idx].operand[0]))
                {
                    local_source = true;
                    break;
                }
            }
            if(!local_source)
                inputs.push_back(v);
        }
    }
    instr_indexes.push_back(instr_idx);
};

/* Determines whether all instructions in 'this' kernel
 * are system opcodes (e.g. BH_DISCARD, BH_FREE, etc.)
 *
 * @return The boolean answer
 */
bool bh_ir_kernel::only_system_opcodes() const
{
    BOOST_FOREACH(uint64_t this_idx, instr_indexes)
    {
        if(not bh_opcode_is_system(bhir->instr_list[this_idx].opcode))
            return false;
    }
    return true;
}

/* Determines whether the kernel fusible legal
 *
 * @return The boolean answer
 */
bool bh_ir_kernel::fusible() const
{
    for(uint64_t i=0; i<instr_indexes.size(); ++i)
    {
        const bh_instruction *instr = &bhir->instr_list[instr_indexes[i]];
        for(uint64_t j=i+1; j<instr_indexes.size(); ++j)
        {
            if(not bohrium::check_fusible(instr, &bhir->instr_list[instr_indexes[j]]))
                return false;
        }
    }
    return true;
}

/* Determines whether it is legal to fuse with the instruction
 *
 * @instr_idx  The index of the instruction
 * @return     The boolean answer
 */
bool bh_ir_kernel::fusible(uint64_t instr_idx) const
{
    const bh_instruction *instr = &bhir->instr_list[instr_idx];
    BOOST_FOREACH(uint64_t i, instr_indexes)
    {
        if(not bohrium::check_fusible(instr, &bhir->instr_list[i]))
            return false;
    }
    return true;
}

/* Determines whether it is legal to fuse with the kernel
 *
 * @other  The other kernel
 * @return The boolean answer
 */
bool bh_ir_kernel::fusible(const bh_ir_kernel &other) const
{
    BOOST_FOREACH(uint64_t idx1, instr_indexes)
    {
        const bh_instruction *instr = &bhir->instr_list[idx1];
        BOOST_FOREACH(uint64_t idx2, other.instr_indexes)
        {
            if(not bohrium::check_fusible(instr, &other.bhir->instr_list[idx2]))
                return false;
        }
    }
    return true;
}

/* Determines whether it is legal to fuse with the instruction
 * without changing 'this' kernel's dependencies.
 *
 * @instr_idx  The index of the instruction
 * @return     The boolean answer
 */
bool bh_ir_kernel::fusible_gently(uint64_t instr_idx) const
{
    const bh_instruction &instr = bhir->instr_list[instr_idx];

    //Check that 'instr' is gentle fusible with at least one existing instruction
    //that is not a system opcode (unless all instructions in 'this' kernel are
    //system opcodes)
    if(only_system_opcodes())
    {
        BOOST_FOREACH(uint64_t this_idx, instr_indexes)
        {
            const bh_instruction &this_instr = bhir->instr_list[this_idx];
            if(bh_instr_fusible_gently(&instr, &this_instr) &&
               bohrium::check_fusible(&instr, &this_instr))
                return true;
        }
    }
    else
    {
        BOOST_FOREACH(uint64_t this_idx, instr_indexes)
        {
            const bh_instruction &this_instr = bhir->instr_list[this_idx];
            if(bh_opcode_is_system(this_instr.opcode))
                continue;

            if(bh_instr_fusible_gently(&instr, &this_instr) &&
               bohrium::check_fusible(&instr, &this_instr))
                return true;
        }
    }
    return false;
}

/* Determines whether it is legal to fuse with the kernel without
 * changing 'this' kernel's dependencies.
 *
 * @other  The other kernel
 * @return The boolean answer
 */
bool bh_ir_kernel::fusible_gently(const bh_ir_kernel &other) const
{

    //When all instructions in the 'other' kernel are system opcodes
    //only one of the instructions needs to be gentle fusible.
    if(other.only_system_opcodes())
    {
        BOOST_FOREACH(uint64_t other_idx, other.instr_indexes)
        {
            if(fusible_gently(other_idx))
                return true;
        }
        return false;
    }
    else
    {
        //Check that each instruction in 'other' is gentle fusible
        //with 'this' kernel while ignoring system opcodes.
        BOOST_FOREACH(uint64_t other_idx, other.instr_indexes)
        {
            if(bh_opcode_is_system(bhir->instr_list[other_idx].opcode))
                continue;
            if(not fusible_gently(other_idx))
                return false;
        }
    }
    return true;
}

/* Determines dependency between 'this' kernel and the instruction 'instr',
 * which is true when:
 *      'instr' writes to an array that 'this' access
 *                        or
 *      'this' writes to an array that 'instr' access
 *
 * @instr_idx  The index of the instruction
 * @return     0: no dependency
 *             1: this kernel depend on 'instr'
 *            -1: 'instr' depend on this kernel
 */
int bh_ir_kernel::dependency(uint64_t instr_idx) const
{
    int ret = 0;
    BOOST_FOREACH(uint64_t this_idx, instr_indexes)
    {
        if(bh_instr_dependency(&bhir->instr_list[instr_idx],
                               &bhir->instr_list[this_idx]))
        {
            if(this_idx >= instr_idx)
            {
                assert(ret == 0 or ret == 1);//Check for cyclic dependency
                ret = 1;
                //TODO: return 'ret' here, but for now we check all instructions
            }
            else
            {
                assert(ret == 0 or ret == -1);//Check for cyclic dependency
                ret = -1;
                //TODO: return 'ret' here, but for now we check all instructions
            }
        }
    }
    return ret;
}

/* Determines dependency between this kernel and 'other',
 * which is true when:
 *      'other' writes to an array that 'this' access
 *                        or
 *      'this' writes to an array that 'other' access
 *
 * @other    The other kernel
 * @return   0: no dependency
 *           1: this kernel depend on 'other'
 *          -1: 'other' depend on this kernel
 */
int bh_ir_kernel::dependency(const bh_ir_kernel &other) const
{
    int ret = 0;
    BOOST_FOREACH(uint64_t other_idx, other.instr_indexes)
    {
        const int dep = dependency(other_idx);
        if(dep != 0)
        {
            assert(ret == 0 or ret == dep);//Check for cyclic dependency
            ret = dep;
            //TODO: return 'ret' here, but for now we check all instructions
        }
    }
    return ret;
}

/* Returns the cost of a bh_view */
inline static uint64_t cost_of_view(const bh_view &v)
{
    return bh_nelements_nbcast(&v) * bh_type_size(v.base->type);
}

/* Returns the cost of the kernel */
uint64_t bh_ir_kernel::cost() const
{
    uint64_t sum = 0;
    BOOST_FOREACH(const bh_view &v, input_list())
    {
        sum += cost_of_view(v);
    }
    BOOST_FOREACH(const bh_view &v, output_list())
    {
        sum += cost_of_view(v);
    }
    return sum;
}

/* Returns the cost savings of merging with the 'other' kernel.
 * The cost savings is defined as the amount the BhIR will drop
 * in price if the two kernels are fused.
 * NB: This function determens the dependency order between the
 * two kernels and calculate the cost saving based on that order.
 *
 * @other  The other kernel
 * @return The cost value. Returns -1 if 'this' and the 'other'
 *         kernel isn't fusible.
 */
int64_t bh_ir_kernel::merge_cost_savings(const bh_ir_kernel &other) const
{
    if(this == &other)
        return 0;

    if(not fusible(other))
        return -1;

    const bh_ir_kernel *a;
    const bh_ir_kernel *b;
    //Lets make sure that 'a' depend on 'b'
    if(this->dependency(other) == 1)
    {
        a = this;
        b = &other;
    }
    else
    {
        a = &other;
        b = this;
    }

    int64_t price_drop = 0;

    //Subtract inputs in 'a' that comes from 'b' or is already an input in 'b'
    BOOST_FOREACH(const bh_view &i, a->input_list())
    {
        BOOST_FOREACH(const bh_view &o, b->output_list())
        {
            if(bh_view_aligned(&i, &o))
                price_drop += cost_of_view(i);
        }
        BOOST_FOREACH(const bh_view &o, b->input_list())
        {
            if(bh_view_aligned(&i, &o))
                price_drop += cost_of_view(i);
        }
    }
    //Subtract outputs from 'b' that are discared in 'a'
    BOOST_FOREACH(const bh_view &o, b->output_list())
    {
        BOOST_FOREACH(uint64_t a_instr_idx, a->instr_indexes)
        {
            const bh_instruction &a_instr = a->bhir->instr_list[a_instr_idx];
            if(a_instr.opcode == BH_DISCARD and a_instr.operand[0].base == o.base)
            {
                price_drop += cost_of_view(o);
                break;
            }
        }
    }
    return price_drop;
}

<|endoftext|>


<commit_before>// [WriteFile Name=SearchForWebmap, Category=CloudAndPortal]
// [Legal]
// Copyright 2016 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//

#include "AuthenticationManager.h"
#include "Map.h"
#include "MapQuickView.h"
#include "Basemap.h"
#include "Portal.h"
#include "PortalItem.h"
#include "PortalItemListModel.h"
#include "PortalQueryParametersForItems.h"
#include "SearchForWebmap.h"

#include <QDate>

using namespace Esri::ArcGISRuntime;

SearchForWebmap::SearchForWebmap(QQuickItem* parent /* = nullptr */):
    QQuickItem(parent)
{
    AuthenticationManager::instance()->setCredentialCacheEnabled(false);
}

SearchForWebmap::~SearchForWebmap()
{
}

void SearchForWebmap::componentComplete()
{
    QQuickItem::componentComplete();
    emit authManagerChanged();

    connect(m_portal, &Portal::loadStatusChanged, this, [this](){
        m_portalLoaded = m_portal->loadStatus() == LoadStatus::Loaded;
        emit portalLoadedChanged();
    });

    //! [SearchForWebmap CPP Portal find items completed]
    connect(m_portal, &Portal::findItemsCompleted, this, [this](PortalQueryResultSetForItems *webmapResults){
        m_webmapResults = webmapResults;
        m_webmaps = m_webmapResults->itemResults();
        emit webmapsChanged();
        emit hasMoreResultsChanged();
    });
    //! [SearchForWebmap CPP Portal find items completed]

    m_portal->load();

    // find QML MapView component
    m_mapView = findChild<MapQuickView*>("mapView");
    m_mapView->setWrapAroundMode(WrapAroundMode::Disabled);
}

bool SearchForWebmap::portalLoaded() const
{
    return m_portalLoaded;
}

QAbstractListModel* SearchForWebmap::webmaps() const
{
    return m_webmaps;
}

bool SearchForWebmap::hasMoreResults() const
{
    return m_webmapResults && m_webmapResults->nextQueryParameters().startIndex() > -1;
}

QString SearchForWebmap::mapLoadError() const
{
    return m_mapLoadeError;
}

void SearchForWebmap::search(const QString keyword)
{
    //! [SearchForWebmap CPP Portal find items]
    // webmaps authored prior to July 2nd, 2014 are not supported - so search only from that date to the current time
    QString fromDate = QString("000000%1").arg(QDateTime(QDate(2014, 7, 2)).toTime_t());
    QString toDate = QString("000000%1").arg(QDateTime::currentDateTime().toTime_t());

    PortalQueryParametersForItems query;
    query.setSearchString(QString("tags:\"%1\" AND +uploaded:[%2 TO %3]")
                          .arg(keyword)
                          .arg(fromDate)
                          .arg(toDate));
    query.setTypes(QList<PortalItemType>() << PortalItemType::WebMap);

    m_portal->findItems(query);
    //! [SearchForWebmap CPP Portal find items]

    m_mapView->setVisible(false);
}

void SearchForWebmap::searchNext()
{
    if (!m_webmapResults)
        return;

    //! [Portal find with nextQueryParameters]
    PortalQueryParameters nextQuery = m_webmapResults->nextQueryParameters();
    // check whether the startIndex of the new query is valid
    if (nextQuery.startIndex() != -1)
        m_portal->findItems(nextQuery);
    //! [Portal find with nextQueryParameters]
}

void SearchForWebmap::loadSelectedWebmap(int index)
{
    if (!m_webmaps)
        return;

    PortalItem* selectedItem = m_webmaps->at(index);
    if (!selectedItem)
        return;

    if (m_selectedItem)
        m_selectedItem->disconnect();

    m_selectedItem = selectedItem;

    connect(m_selectedItem, &PortalItem::loadStatusChanged, this, [this]{
        if (!m_selectedItem || m_selectedItem->loadStatus() != LoadStatus::Loaded)
            return;

        if (m_map)
            m_map->disconnect();

        m_mapLoadeError.clear();
        emit mapLoadErrorChanged();

        m_map = new Map(m_selectedItem, this);

        connect(m_map, &Map::errorOccurred, this, [this](){
            m_mapLoadeError = m_map->loadError().message();
            emit mapLoadErrorChanged();
        });

        connect(m_map, &Map::loadStatusChanged, this, [this](){
            if (!m_map || m_map->loadStatus() != LoadStatus::Loaded)
                return;

            m_mapView->setMap(m_map);
            m_mapView->setVisible(true);
        });

        m_map->load();
    });
    m_selectedItem->load();
}

void SearchForWebmap::errorAccepted()
{
    m_mapLoadeError.clear();
    emit mapLoadErrorChanged();
}

AuthenticationManager *SearchForWebmap::authManager() const
{
    return AuthenticationManager::instance();
}
<commit_msg>fix name (#460)<commit_after>// [WriteFile Name=SearchForWebmap, Category=CloudAndPortal]
// [Legal]
// Copyright 2016 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//

#include "AuthenticationManager.h"
#include "Map.h"
#include "MapQuickView.h"
#include "Basemap.h"
#include "Portal.h"
#include "PortalItem.h"
#include "PortalItemListModel.h"
#include "PortalQueryParametersForItems.h"
#include "SearchForWebmap.h"

#include <QDate>

using namespace Esri::ArcGISRuntime;

SearchForWebmap::SearchForWebmap(QQuickItem* parent /* = nullptr */):
    QQuickItem(parent)
{
    AuthenticationManager::instance()->setCredentialCacheEnabled(false);
}

SearchForWebmap::~SearchForWebmap()
{
}

void SearchForWebmap::componentComplete()
{
    QQuickItem::componentComplete();
    emit authManagerChanged();

    connect(m_portal, &Portal::loadStatusChanged, this, [this](){
        m_portalLoaded = m_portal->loadStatus() == LoadStatus::Loaded;
        emit portalLoadedChanged();
    });

    //! [SearchForWebmap CPP Portal find items completed]
    connect(m_portal, &Portal::findItemsCompleted, this, [this](PortalQueryResultSetForItems *webmapResults){
        m_webmapResults = webmapResults;
        m_webmaps = m_webmapResults->itemResults();
        emit webmapsChanged();
        emit hasMoreResultsChanged();
    });
    //! [SearchForWebmap CPP Portal find items completed]

    m_portal->load();

    // find QML MapView component
    m_mapView = findChild<MapQuickView*>("mapView");
    m_mapView->setWrapAroundMode(WrapAroundMode::Disabled);
}

bool SearchForWebmap::portalLoaded() const
{
    return m_portalLoaded;
}

QAbstractListModel* SearchForWebmap::webmaps() const
{
    return m_webmaps;
}

bool SearchForWebmap::hasMoreResults() const
{
    return m_webmapResults && m_webmapResults->nextQueryParameters().startIndex() > -1;
}

QString SearchForWebmap::mapLoadError() const
{
    return m_mapLoadeError;
}

void SearchForWebmap::search(const QString keyword)
{
    //! [SearchForWebmap CPP Portal find items]
    // webmaps authored prior to July 2nd, 2014 are not supported - so search only from that date to the current time
    QString fromDate = QString("000000%1").arg(QDateTime(QDate(2014, 7, 2)).toTime_t());
    QString toDate = QString("000000%1").arg(QDateTime::currentDateTime().toTime_t());

    PortalQueryParametersForItems query;
    query.setSearchString(QString("tags:\"%1\" AND +uploaded:[%2 TO %3]")
                          .arg(keyword)
                          .arg(fromDate)
                          .arg(toDate));
    query.setTypes(QList<PortalItemType>() << PortalItemType::WebMap);

    m_portal->findItems(query);
    //! [SearchForWebmap CPP Portal find items]

    m_mapView->setVisible(false);
}

void SearchForWebmap::searchNext()
{
    if (!m_webmapResults)
        return;

    //! [Portal find with nextQueryParameters]
    PortalQueryParametersForItems nextQuery = m_webmapResults->nextQueryParameters();
    // check whether the startIndex of the new query is valid
    if (nextQuery.startIndex() != -1)
        m_portal->findItems(nextQuery);
    //! [Portal find with nextQueryParameters]
}

void SearchForWebmap::loadSelectedWebmap(int index)
{
    if (!m_webmaps)
        return;

    PortalItem* selectedItem = m_webmaps->at(index);
    if (!selectedItem)
        return;

    if (m_selectedItem)
        m_selectedItem->disconnect();

    m_selectedItem = selectedItem;

    connect(m_selectedItem, &PortalItem::loadStatusChanged, this, [this]{
        if (!m_selectedItem || m_selectedItem->loadStatus() != LoadStatus::Loaded)
            return;

        if (m_map)
            m_map->disconnect();

        m_mapLoadeError.clear();
        emit mapLoadErrorChanged();

        m_map = new Map(m_selectedItem, this);

        connect(m_map, &Map::errorOccurred, this, [this](){
            m_mapLoadeError = m_map->loadError().message();
            emit mapLoadErrorChanged();
        });

        connect(m_map, &Map::loadStatusChanged, this, [this](){
            if (!m_map || m_map->loadStatus() != LoadStatus::Loaded)
                return;

            m_mapView->setMap(m_map);
            m_mapView->setVisible(true);
        });

        m_map->load();
    });
    m_selectedItem->load();
}

void SearchForWebmap::errorAccepted()
{
    m_mapLoadeError.clear();
    emit mapLoadErrorChanged();
}

AuthenticationManager *SearchForWebmap::authManager() const
{
    return AuthenticationManager::instance();
}
<|endoftext|>


<commit_before>#include <sstream>

// Include 3rd party headers.
#include <odb/transaction.hxx>
#include <odb/mysql/database.hxx>
#include <bites.hpp>

// Include application headers.
#include "Captor.hpp"
#include "DBWriter.hpp"
#include "mapping.hpp"
#include "mapping-odb.hxx"

namespace wabbit {

void DBWriter::run ()
{
    // Connect to database.
    odb::mysql::database db (
        m_config["username"],
        m_config["password"],
        m_config["db_name"]
        );

    // Pull from the queue while there are valid tasks.
    Captor::FrameAndTime task;
    m_input_queue.wait_and_pop(task);
    while(task.first)
    {
        // Assemble the time string.
        auto tstring = bites::time2string (
            task.second,
            "%Y-%m-%d %H:%M:%S:%f"
            );

        // Create the image field.
        wabbit::Image img (tstring);

        // Start the transaction.
        odb::transaction trans (db.begin());

        // Add the image field.
        db.persist(img);

        // Increment the size.
        typedef odb::query<wabbit::Datum> query;
        auto result =
            db.query<wabbit::Datum> (query::name == "size");
        auto datum = result.begin();
        int size = atoi(datum->value().c_str());
        std::stringstream ss;
        ss << size + 1;
        datum->value (ss.str());
        db.update(*datum);

        // Update latest timestamp.
        result = db.query<wabbit::Datum> (query::name == "latest_tstamp");
        datum = result.begin();
        datum->value (tstring);
        db.update(*datum);

        // Commit to database.
        trans.commit();

        // Signal done.
        m_done_queue.push (task.first);

        // Pull the next frame.
        m_input_queue.wait_and_pop (task);
    }
}

}  // namespace wabbit.
<commit_msg>Fix bug in timestamp-to-string conversion.<commit_after>#include <sstream>

// Include 3rd party headers.
#include <odb/transaction.hxx>
#include <odb/mysql/database.hxx>
#include <bites.hpp>

// Include application headers.
#include "Captor.hpp"
#include "DBWriter.hpp"
#include "mapping.hpp"
#include "mapping-odb.hxx"

namespace wabbit {

void DBWriter::run ()
{
    // Connect to database.
    odb::mysql::database db (
        m_config["username"],
        m_config["password"],
        m_config["db_name"]
        );

    // Pull from the queue while there are valid tasks.
    Captor::FrameAndTime task;
    m_input_queue.wait_and_pop(task);
    while(task.first)
    {
        // Assemble the time string.
        auto tstring = bites::time2string (
            task.second,
            "%Y-%m-%d %H:%M:%S.%f"
            );

        // Create the image field.
        wabbit::Image img (tstring);

        // Start the transaction.
        odb::transaction trans (db.begin());

        // Add the image field.
        db.persist(img);

        // Increment the size.
        typedef odb::query<wabbit::Datum> query;
        auto result =
            db.query<wabbit::Datum> (query::name == "size");
        auto datum = result.begin();
        int size = atoi(datum->value().c_str());
        std::stringstream ss;
        ss << size + 1;
        datum->value (ss.str());
        db.update(*datum);

        // Update latest timestamp.
        result = db.query<wabbit::Datum> (query::name == "latest_tstamp");
        datum = result.begin();
        datum->value (tstring);
        db.update(*datum);

        // Commit to database.
        trans.commit();

        // Signal done.
        m_done_queue.push (task.first);

        // Pull the next frame.
        m_input_queue.wait_and_pop (task);
    }
}

}  // namespace wabbit.
<|endoftext|>


<commit_before>/*
    OF-TangibleFramework . Framework for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2009 Daniel Gallardo Grassot <daniel.gallardo@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/
#include "ofMain.h"
#include "GraphicDispatcher.hpp"

GraphicDispatcher::GraphicDispatcher(){
}

GraphicDispatcher::~GraphicDispatcher(){
}

void GraphicDispatcher::Draw(){
    glDisable(GL_DEPTH_TEST);
    for(std::list<Graphic*>::iterator it = graphics.begin(); it != graphics.end(); it++)
        (*it)->draw();
    glEnable(GL_DEPTH_TEST);
}

void GraphicDispatcher::Update(){
    for(std::list<Graphic*>::iterator it = graphics.begin(); it != graphics.end(); it++)
        (*it)->update();
}

void GraphicDispatcher::Resize(int w, int h){
    for(std::list<Graphic*>::iterator it = graphics.begin(); it != graphics.end(); it++)
        (*it)->resize(w,h);
}

void GraphicDispatcher::AddGraphic(Graphic* graphic){
    graphics.push_back(graphic);
    graphics.sort(CompareLayers);
}

void GraphicDispatcher::RemoveGraphic(Graphic* graphic){
    graphics.remove(graphic);
}

void GraphicDispatcher::bring_top(Graphic* graphic){
    for ( std::list<Graphic*>::iterator it=graphics.begin(); it!=graphics.end();it++){
        if ( (*it) == graphic){
            graphics.remove(*it);
            break;
        }
    }
    graphics.push_back(graphic);
    graphics.sort(CompareLayers);
}
<commit_msg>Allowing to delete Graphics on update or draw<commit_after>/*
    OF-TangibleFramework . Framework for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2009 Daniel Gallardo Grassot <daniel.gallardo@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/
#include "ofMain.h"
#include "GraphicDispatcher.hpp"

GraphicDispatcher::GraphicDispatcher(){
}

GraphicDispatcher::~GraphicDispatcher(){
}

void GraphicDispatcher::Draw(){
    glDisable(GL_DEPTH_TEST);
    for(std::list<Graphic*>::iterator it = graphics.begin(); it != graphics.end(); it++)
        (*it)->draw();
    glEnable(GL_DEPTH_TEST);
}

void GraphicDispatcher::Update(){
    std::list<Graphic*> l (graphics);
    for(std::list<Graphic*>::iterator it = l.begin(); it != l.end(); it++)
        (*it)->update();
}

void GraphicDispatcher::Resize(int w, int h){
    std::list<Graphic*> l (graphics);
    for(std::list<Graphic*>::iterator it = l.begin(); it != l.end(); it++)
        (*it)->resize(w,h);
}

void GraphicDispatcher::AddGraphic(Graphic* graphic){
    graphics.push_back(graphic);
    graphics.sort(CompareLayers);
}

void GraphicDispatcher::RemoveGraphic(Graphic* graphic){
    graphics.remove(graphic);
}

void GraphicDispatcher::bring_top(Graphic* graphic){
    for ( std::list<Graphic*>::iterator it=graphics.begin(); it!=graphics.end();it++){
        if ( (*it) == graphic){
            graphics.remove(*it);
            break;
        }
    }
    graphics.push_back(graphic);
    graphics.sort(CompareLayers);
}
<|endoftext|>


<commit_before>/*
* HMAC_RNG
* (C) 2008-2009,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/hmac_rng.h>
#include <botan/libstate.h>
#include <botan/get_byte.h>
#include <botan/entropy_src.h>
#include <botan/internal/xor_buf.h>
#include <algorithm>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode& prf,
              secure_vector<byte>& K,
              u32bit& counter,
              const std::string& label)
   {
   prf.update(K);
   prf.update(label);
   prf.update_be(counter);
   prf.final(&K[0]);

   ++counter;
   }

}

/*
* HMAC_RNG Constructor
*/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
                   MessageAuthenticationCode* prf) :
   m_extractor(extractor), m_prf(prf)
   {
   if(!m_prf->valid_keylength(m_extractor->output_length()) ||
      !m_extractor->valid_keylength(m_prf->output_length()))
      throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
                             m_extractor->name() + " and " +
                             m_prf->name());

   // First PRF inputs are all zero, as specified in section 2
   m_K.resize(m_prf->output_length());

   /*
   Normally we want to feedback PRF outputs to the extractor function
   to ensure a single bad poll does not reduce entropy. Thus in reseed
   we'll want to invoke the PRF before we reset the PRF key, but until
   the first reseed the PRF is unkeyed. Rather than trying to keep
   track of this, just set the initial PRF key to constant zero.
   Since all PRF inputs in the first reseed are constants, this
   amounts to suffixing the seed in the first poll with a fixed
   constant string.

   The PRF key will not be used to generate outputs until after reseed
   sets m_seeded to true.
   */
   secure_vector<byte> prf_key(m_extractor->output_length());
   m_prf->set_key(prf_key);

   /*
   Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.

   This will be used during the first extraction sequence; XTS values
   after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   m_extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
   }

/*
* Generate a buffer of random bytes
*/
void HMAC_RNG::randomize(byte out[], size_t length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(*m_prf, m_K, m_counter, "rng");

      if(m_counter % AUTOMATIC_RESEED_RATE == 0)
         reseed(AUTOMATIC_RESEED_BITS);

      const size_t copied = std::min<size_t>(m_K.size() / 2, length);

      copy_mem(out, &m_K[0], copied);
      out += copied;
      length -= copied;
      }
   }

/*
* Poll for entropy and reset the internal keys
*/
void HMAC_RNG::reseed(size_t poll_bits)
   {
   /*
   Using the terminology of E-t-E, XTR is the MAC function (normally
   HMAC) seeded with XTS (below) and we form SKM, the key material, by
   polling as many sources as we think needed to reach our polling
   goal. We then also include feedback of the current PRK so that
   a bad poll doesn't wipe us out.
   */

   Entropy_Accumulator_BufferedComputation accum(*m_extractor, poll_bits);

   global_state().poll_available_sources(accum);

   /*
   * It is necessary to feed forward poll data. Otherwise, a good poll
   * (collecting a large amount of conditional entropy) followed by a
   * bad one (collecting little) would be unsafe. Do this by
   * generating new PRF outputs using the previous key and feeding
   * them into the extractor function.
   *
   * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF
   * output using the CTXinfo "reseed". Provide these values as input
   * to the extractor function.
   */
   hmac_prf(*m_prf, m_K, m_counter, "rng");
   m_extractor->update(m_K); // K is the CTXinfo=rng PRF output

   hmac_prf(*m_prf, m_K, m_counter, "reseed");
   m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into
      the extractor, and set the PRF key to that */
   m_prf->set_key(m_extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(*m_prf, m_K, m_counter, "xts");
   m_extractor->set_key(m_K);

   // Reset state
   zeroise(m_K);
   m_counter = 0;

   /*
   * Consider ourselves seeded once we've collected an estimated 128 bits of
   * entropy in a single poll.
   */
   if(accum.bits_collected() >= 128)
      m_seeded = true;
   }

/*
* Add user-supplied entropy to the extractor input
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
   {
   m_extractor->update(input, length);
   reseed(AUTOMATIC_RESEED_BITS);
   }

/*
* Clear memory of sensitive data
*/
void HMAC_RNG::clear()
   {
   m_seeded = false;
   m_extractor->clear();
   m_prf->clear();
   zeroise(m_K);
   m_counter = 0;
   }

/*
* Return the name of this type
*/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + m_extractor->name() + "," + m_prf->name() + ")";
   }

}
<commit_msg>Include a timestamp as part of the HMAC_RNG PRF inputs<commit_after>/*
* HMAC_RNG
* (C) 2008-2009,2013 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/hmac_rng.h>
#include <botan/libstate.h>
#include <botan/get_byte.h>
#include <botan/entropy_src.h>
#include <botan/internal/xor_buf.h>
#include <algorithm>
#include <chrono>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode& prf,
              secure_vector<byte>& K,
              u32bit& counter,
              const std::string& label)
   {
   typedef std::chrono::high_resolution_clock clock;

   auto timestamp = clock::now().time_since_epoch().count();

   prf.update(K);
   prf.update(label);
   prf.update_be(timestamp);
   prf.update_be(counter);
   prf.final(&K[0]);

   ++counter;
   }

}

/*
* HMAC_RNG Constructor
*/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
                   MessageAuthenticationCode* prf) :
   m_extractor(extractor), m_prf(prf)
   {
   if(!m_prf->valid_keylength(m_extractor->output_length()) ||
      !m_extractor->valid_keylength(m_prf->output_length()))
      throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
                             m_extractor->name() + " and " +
                             m_prf->name());

   // First PRF inputs are all zero, as specified in section 2
   m_K.resize(m_prf->output_length());

   /*
   Normally we want to feedback PRF outputs to the extractor function
   to ensure a single bad poll does not reduce entropy. Thus in reseed
   we'll want to invoke the PRF before we reset the PRF key, but until
   the first reseed the PRF is unkeyed. Rather than trying to keep
   track of this, just set the initial PRF key to constant zero.
   Since all PRF inputs in the first reseed are constants, this
   amounts to suffixing the seed in the first poll with a fixed
   constant string.

   The PRF key will not be used to generate outputs until after reseed
   sets m_seeded to true.
   */
   secure_vector<byte> prf_key(m_extractor->output_length());
   m_prf->set_key(prf_key);

   /*
   Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.

   This will be used during the first extraction sequence; XTS values
   after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   m_extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
   }

/*
* Generate a buffer of random bytes
*/
void HMAC_RNG::randomize(byte out[], size_t length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(*m_prf, m_K, m_counter, "rng");

      if(m_counter % AUTOMATIC_RESEED_RATE == 0)
         reseed(AUTOMATIC_RESEED_BITS);

      const size_t copied = std::min<size_t>(m_K.size() / 2, length);

      copy_mem(out, &m_K[0], copied);
      out += copied;
      length -= copied;
      }
   }

/*
* Poll for entropy and reset the internal keys
*/
void HMAC_RNG::reseed(size_t poll_bits)
   {
   /*
   Using the terminology of E-t-E, XTR is the MAC function (normally
   HMAC) seeded with XTS (below) and we form SKM, the key material, by
   polling as many sources as we think needed to reach our polling
   goal. We then also include feedback of the current PRK so that
   a bad poll doesn't wipe us out.
   */

   Entropy_Accumulator_BufferedComputation accum(*m_extractor, poll_bits);

   global_state().poll_available_sources(accum);

   /*
   * It is necessary to feed forward poll data. Otherwise, a good poll
   * (collecting a large amount of conditional entropy) followed by a
   * bad one (collecting little) would be unsafe. Do this by
   * generating new PRF outputs using the previous key and feeding
   * them into the extractor function.
   *
   * Cycle the RNG once (CTXinfo="rng"), then generate a new PRF
   * output using the CTXinfo "reseed". Provide these values as input
   * to the extractor function.
   */
   hmac_prf(*m_prf, m_K, m_counter, "rng");
   m_extractor->update(m_K); // K is the CTXinfo=rng PRF output

   hmac_prf(*m_prf, m_K, m_counter, "reseed");
   m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into
      the extractor, and set the PRF key to that */
   m_prf->set_key(m_extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(*m_prf, m_K, m_counter, "xts");
   m_extractor->set_key(m_K);

   // Reset state
   zeroise(m_K);
   m_counter = 0;

   /*
   * Consider ourselves seeded once we've collected an estimated 128 bits of
   * entropy in a single poll.
   */
   if(accum.bits_collected() >= 128)
      m_seeded = true;
   }

/*
* Add user-supplied entropy to the extractor input
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
   {
   m_extractor->update(input, length);
   reseed(AUTOMATIC_RESEED_BITS);
   }

/*
* Clear memory of sensitive data
*/
void HMAC_RNG::clear()
   {
   m_seeded = false;
   m_extractor->clear();
   m_prf->clear();
   zeroise(m_K);
   m_counter = 0;
   }

/*
* Return the name of this type
*/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + m_extractor->name() + "," + m_prf->name() + ")";
   }

}
<|endoftext|>


<commit_before>/*
* HMAC_RNG
* (C) 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/hmac_rng.h>
#include <botan/get_byte.h>
#include <botan/internal/xor_buf.h>
#include <botan/internal/stl_util.h>
#include <algorithm>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode* prf,
              MemoryRegion<byte>& K,
              u32bit& counter,
              const std::string& label)
   {
   prf->update(K, K.size());
   prf->update(label);
   for(u32bit i = 0; i != 4; ++i)
      prf->update(get_byte(i, counter));
   prf->final(K);

   ++counter;
   }

}

/**
* Generate a buffer of random bytes
*/
void HMAC_RNG::randomize(byte out[], u32bit length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(prf, K, counter, "rng");

      const u32bit copied = std::min(K.size(), length);

      copy_mem(out, K.begin(), copied);
      out += copied;
      length -= copied;
      }
   }

/**
* Reseed the internal state, also accepting user input to include
*/
void HMAC_RNG::reseed_with_input(u32bit poll_bits,
                                 const byte input[], u32bit input_length)
   {
   /**
   Using the terminology of E-t-E, XTR is the MAC function (normally
   HMAC) seeded with XTS (below) and we form SKM, the key material, by
   fast polling each source, and then slow polling as many as we think
   we need (in the following loop), and feeding all of the poll
   results, along with any optional user input, along with, finally,
   feedback of the current PRK value, into the extractor function.
   */

   Entropy_Accumulator_BufferedComputation accum(*extractor, poll_bits);

   if(!entropy_sources.empty())
      {
      u32bit poll_attempt = 0;

      while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
         {
         entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum);
         ++poll_attempt;
         }
      }

   // And now add the user-provided input, if any
   if(input_length)
      accum.add(input, input_length, 1);

   /*
   It is necessary to feed forward poll data. Otherwise, a good poll
   (collecting a large amount of conditional entropy) followed by a
   bad one (collecting little) would be unsafe. Do this by generating
   new PRF outputs using the previous key and feeding them into the
   extractor function.

   Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output
   using the CTXinfo "reseed". Provide these values as input to the
   extractor function.
   */
   hmac_prf(prf, K, counter, "rng");
   extractor->update(K); // K is the CTXinfo=rng PRF output

   hmac_prf(prf, K, counter, "reseed");
   extractor->update(K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into
      the extractor, and set the PRF key to that */
   prf->set_key(extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(prf, K, counter, "xts");
   extractor->set_key(K, K.size());

   // Reset state
   K.clear();
   counter = 0;

   if(input_length || accum.bits_collected() >= poll_bits)
      seeded = true;
   }

/**
* Reseed the internal state
*/
void HMAC_RNG::reseed(u32bit poll_bits)
   {
   reseed_with_input(poll_bits, 0, 0);
   }

/**
* Add user-supplied entropy by reseeding and including this
* input among the poll data
*/
void HMAC_RNG::add_entropy(const byte input[], u32bit length)
   {
   reseed_with_input(0, input, length);
   }

/**
* Add another entropy source to the list
*/
void HMAC_RNG::add_entropy_source(EntropySource* src)
   {
   entropy_sources.push_back(src);
   }

/*
* Clear memory of sensitive data
*/
void HMAC_RNG::clear()
   {
   extractor->clear();
   prf->clear();
   K.clear();
   counter = 0;
   seeded = false;
   }

/**
* Return the name of this type
*/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")";
   }

/**
* HMAC_RNG Constructor
*/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac,
                   MessageAuthenticationCode* prf_mac) :
   extractor(extractor_mac), prf(prf_mac)
   {
   // First PRF inputs are all zero, as specified in section 2
   K.resize(prf->OUTPUT_LENGTH);
   counter = 0;
   seeded = false;

   /*
   Normally we want to feedback PRF output into the input to the
   extractor function to ensure a single bad poll does not damage the
   RNG, but obviously that is meaningless to do on the first poll.

   We will want to use the PRF before we set the first key (in
   reseed_with_input), and it is a pain to keep track if it is set or
   not. Since the first time it doesn't matter anyway, just set it to
   a constant: randomize() will not produce output unless is_seeded()
   returns true, and that will only be the case if the estimated
   entropy counter is high enough. That variable is only set when a
   reseeding is performed.
   */
   std::string prf_key = "Botan HMAC_RNG PRF";
   prf->set_key(reinterpret_cast<const byte*>(prf_key.c_str()),
                prf_key.length());

   /*
   This will be used as the first XTS value when extracting input.
   XTS values after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   std::string xts = "Botan HMAC_RNG XTS";
   extractor->set_key(reinterpret_cast<const byte*>(xts.c_str()),
                      xts.length());
   }

/**
* HMAC_RNG Destructor
*/
HMAC_RNG::~HMAC_RNG()
   {
   delete extractor;
   delete prf;

   std::for_each(entropy_sources.begin(), entropy_sources.end(),
                 del_fun<EntropySource>());

   counter = 0;
   }

}
<commit_msg>In add_entropy(), additionally poll for 64 bits of system entropy to mix in with the user input.<commit_after>/*
* HMAC_RNG
* (C) 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/hmac_rng.h>
#include <botan/get_byte.h>
#include <botan/internal/xor_buf.h>
#include <botan/internal/stl_util.h>
#include <algorithm>

namespace Botan {

namespace {

void hmac_prf(MessageAuthenticationCode* prf,
              MemoryRegion<byte>& K,
              u32bit& counter,
              const std::string& label)
   {
   prf->update(K, K.size());
   prf->update(label);
   for(u32bit i = 0; i != 4; ++i)
      prf->update(get_byte(i, counter));
   prf->final(K);

   ++counter;
   }

}

/**
* Generate a buffer of random bytes
*/
void HMAC_RNG::randomize(byte out[], u32bit length)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   /*
    HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
   */
   while(length)
      {
      hmac_prf(prf, K, counter, "rng");

      const u32bit copied = std::min(K.size(), length);

      copy_mem(out, K.begin(), copied);
      out += copied;
      length -= copied;
      }
   }

/**
* Reseed the internal state, also accepting user input to include
*/
void HMAC_RNG::reseed_with_input(u32bit poll_bits,
                                 const byte input[], u32bit input_length)
   {
   /**
   Using the terminology of E-t-E, XTR is the MAC function (normally
   HMAC) seeded with XTS (below) and we form SKM, the key material, by
   fast polling each source, and then slow polling as many as we think
   we need (in the following loop), and feeding all of the poll
   results, along with any optional user input, along with, finally,
   feedback of the current PRK value, into the extractor function.
   */

   Entropy_Accumulator_BufferedComputation accum(*extractor, poll_bits);

   if(!entropy_sources.empty())
      {
      u32bit poll_attempt = 0;

      while(!accum.polling_goal_achieved() && poll_attempt < poll_bits)
         {
         entropy_sources[poll_attempt % entropy_sources.size()]->poll(accum);
         ++poll_attempt;
         }
      }

   // And now add the user-provided input, if any
   if(input_length)
      accum.add(input, input_length, 1);

   /*
   It is necessary to feed forward poll data. Otherwise, a good poll
   (collecting a large amount of conditional entropy) followed by a
   bad one (collecting little) would be unsafe. Do this by generating
   new PRF outputs using the previous key and feeding them into the
   extractor function.

   Cycle the RNG once (CTXinfo="rng"), then generate a new PRF output
   using the CTXinfo "reseed". Provide these values as input to the
   extractor function.
   */
   hmac_prf(prf, K, counter, "rng");
   extractor->update(K); // K is the CTXinfo=rng PRF output

   hmac_prf(prf, K, counter, "reseed");
   extractor->update(K); // K is the CTXinfo=reseed PRF output

   /* Now derive the new PRK using everything that has been fed into
      the extractor, and set the PRF key to that */
   prf->set_key(extractor->final());

   // Now generate a new PRF output to use as the XTS extractor salt
   hmac_prf(prf, K, counter, "xts");
   extractor->set_key(K, K.size());

   // Reset state
   K.clear();
   counter = 0;

   if(input_length > 64 || accum.bits_collected() >= 128)
      seeded = true;
   }

/**
* Reseed the internal state
*/
void HMAC_RNG::reseed(u32bit poll_bits)
   {
   reseed_with_input(poll_bits, 0, 0);
   }

/**
* Add user-supplied entropy by reseeding and including this
* input among the poll data
*/
void HMAC_RNG::add_entropy(const byte input[], u32bit length)
   {
   reseed_with_input(64, input, length);
   }

/**
* Add another entropy source to the list
*/
void HMAC_RNG::add_entropy_source(EntropySource* src)
   {
   entropy_sources.push_back(src);
   }

/*
* Clear memory of sensitive data
*/
void HMAC_RNG::clear()
   {
   extractor->clear();
   prf->clear();
   K.clear();
   counter = 0;
   seeded = false;
   }

/**
* Return the name of this type
*/
std::string HMAC_RNG::name() const
   {
   return "HMAC_RNG(" + extractor->name() + "," + prf->name() + ")";
   }

/**
* HMAC_RNG Constructor
*/
HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor_mac,
                   MessageAuthenticationCode* prf_mac) :
   extractor(extractor_mac), prf(prf_mac)
   {
   if(!prf->valid_keylength(extractor->OUTPUT_LENGTH) ||
      !extractor->valid_keylength(prf->OUTPUT_LENGTH))
      throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
                             extractor->name() + " and " +
                             prf->name());

   // First PRF inputs are all zero, as specified in section 2
   K.resize(prf->OUTPUT_LENGTH);
   counter = 0;
   seeded = false;

   /*
   Normally we want to feedback PRF output into the input to the
   extractor function to ensure a single bad poll does not damage the
   RNG, but obviously that is meaningless to do on the first poll.

   We will want to use the PRF before we set the first key (in
   reseed_with_input), and it is a pain to keep track if it is set or
   not. Since the first time it doesn't matter anyway, just set the
   PRF key to constant zero: randomize() will not produce output
   unless is_seeded() returns true, and that will only be the case if
   the estimated entropy counter is high enough. That variable is only
   set when a reseeding is performed.
   */
   MemoryVector<byte> prf_key(extractor->OUTPUT_LENGTH);
   prf->set_key(prf_key);

   /*
   Use PRF("Botan HMAC_RNG XTS") as the intitial XTS key.

   This will be used during the first extraction sequence; XTS values
   after this one are generated using the PRF.

   If I understand the E-t-E paper correctly (specifically Section 4),
   using this fixed extractor key is safe to do.
   */
   extractor->set_key(prf->process("Botan HMAC_RNG XTS"));
   }

/**
* HMAC_RNG Destructor
*/
HMAC_RNG::~HMAC_RNG()
   {
   delete extractor;
   delete prf;

   std::for_each(entropy_sources.begin(), entropy_sources.end(),
                 del_fun<EntropySource>());

   counter = 0;
   }

}
<|endoftext|>


<commit_before>//=============================================================================
//
//                               OpenMesh
//        Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
//                           www.openmesh.org
//
//-----------------------------------------------------------------------------
//
//                                License
//
//   This library is free software; you can redistribute it and/or modify it
//   under the terms of the GNU Lesser General Public License as published
//   by the Free Software Foundation, version 2.1.
//
//   This library is distributed in the hope that it will be useful, but
//   WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//   Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public
//   License along with this library; if not, write to the Free Software
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//=============================================================================
#ifdef _MSC_VER
#  pragma warning(disable: 4267 4311)
#endif

#include <iostream>
#include <fstream>

#include <QApplication>
#include <QMessageBox>
#include "SubdivideWidget.hh"

#include <GL/glut.h>

int main(int argc, char **argv)
{
  // OpenGL check
  QApplication::setColorSpec( QApplication::CustomColor );
  QApplication app(argc,argv);

  glutInit(&argc,argv);

  if ( !QGLFormat::hasOpenGL() ) {
    QString msg = "System has no OpenGL support!";
    QMessageBox::critical( NULL, "OpenGL", msg + argv[1], QMessageBox::Ok );
    return -1;
  }

  // create widget
  SubdivideWidget* w = new SubdivideWidget(0, "Subdivider");

  w->resize(400, 400);
  w->show();

  // load scene
  if (argc > 1)
  {
     if ( ! w->open_mesh(argv[1]) )
     {
        QString msg = "Cannot read mesh from file ";
        QMessageBox::critical( NULL, argv[1], msg + argv[1], QMessageBox::Ok );
        return -1;
     }
  }

  return app.exec();
}
<commit_msg>Adapted include path for darwin compatibility<commit_after>//=============================================================================
//
//                               OpenMesh
//        Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
//                           www.openmesh.org
//
//-----------------------------------------------------------------------------
//
//                                License
//
//   This library is free software; you can redistribute it and/or modify it
//   under the terms of the GNU Lesser General Public License as published
//   by the Free Software Foundation, version 2.1.
//
//   This library is distributed in the hope that it will be useful, but
//   WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//   Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public
//   License along with this library; if not, write to the Free Software
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//=============================================================================
#ifdef _MSC_VER
#  pragma warning(disable: 4267 4311)
#endif

#include <iostream>
#include <fstream>

#include <QApplication>
#include <QMessageBox>
#include "SubdivideWidget.hh"

#ifdef ARCH_DARWIN
#include <glut.h>
#else
#include <GL/glut.h>
#endif

int main(int argc, char **argv)
{
  // OpenGL check
  QApplication::setColorSpec( QApplication::CustomColor );
  QApplication app(argc,argv);

  glutInit(&argc,argv);

  if ( !QGLFormat::hasOpenGL() ) {
    QString msg = "System has no OpenGL support!";
    QMessageBox::critical( NULL, "OpenGL", msg + argv[1], QMessageBox::Ok );
    return -1;
  }

  // create widget
  SubdivideWidget* w = new SubdivideWidget(0, "Subdivider");

  w->resize(400, 400);
  w->show();

  // load scene
  if (argc > 1)
  {
     if ( ! w->open_mesh(argv[1]) )
     {
        QString msg = "Cannot read mesh from file ";
        QMessageBox::critical( NULL, argv[1], msg + argv[1], QMessageBox::Ok );
        return -1;
     }
  }

  return app.exec();
}
<|endoftext|>


<commit_before>#include "FontBlankSymbol.h"
#include "FontSprite.h"
#include "Font.h"

#include "common/Vector.h"
#include "common/color_trans.h"
#include "common/FileNameTools.h"
#include "common/FileNameParser.h"
#include "common/Settings.h"
#include "common/Math.h"
#include "dataset/SpriteTools.h"
#include "render/PrimitiveDraw.h"
#include "render/Shader.h"
#include "render/LabelNew.h"

//OpenGL Headers
#include <windows.h>
#include <GL/gl.h>

#include <json/json.h>

namespace d2d
{

FontBlankSymbol::FontBlankSymbol()
{
	static int id = 0;
	m_name = wxT("fontblank") + wxVariant(id++);

	align_hori = align_vert = 0;
	size = 0;
	width = height = 100;

	m_font = NULL;

	m_style.fill = true;
	m_style.color.set(0.7f, 0.7f, 0.7f, 0.7f);
}

FontBlankSymbol::~FontBlankSymbol()
{
//	m_font->release();
}

void FontBlankSymbol::reloadTexture() const
{
}

void FontBlankSymbol::draw(const Screen& scr,
						   const Matrix& mt,
						   const Colorf& mul,
						   const Colorf& add,
						   const ISprite* sprite/* = NULL*/) const
{
// 	if (Settings::DrawFontType & Settings::DrawFontBg) {
// 		DrawBackground(scr, sprite, mt);
// 	}
	if (Settings::DrawFontType & Settings::DrawFontText) {
		DrawText(scr, sprite, mt);
	}

	SpriteTools::DrawName(scr, sprite, mt);
}

Rect FontBlankSymbol::getSize(const ISprite* sprite/* = NULL*/) const
{
	return Rect(width, height);
}

void FontBlankSymbol::refresh()
{
}

bool FontBlankSymbol::loadFont(const std::string& _filename)
{
	if (_filename == filename)
		return false;

	std::string filename = FilenameTools::getAbsolutePath(m_filepath, _filename);
	if (!FileNameParser::isType(filename, FileNameParser::e_freetype)
		|| !FilenameTools::isExist(filename))
		return false;

	delete m_font, m_font = NULL;
	m_font = FontMgr::Instance()->getItem(filename);
	return m_font != NULL;
}

void FontBlankSymbol::loadResources()
{
	Json::Value value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(m_filepath.fn_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, value);
	fin.close();

	name = value["name"].asString();
	font = value["font"].asString();
	color = value["color"].asString();
	if (!value["align"].isNull()) {
		align_hori = value["align"].asDouble();
	} else {
		align_hori = value["align hori"].asDouble();
		align_vert = value["align vert"].asDouble();
	}
	size = value["size"].asDouble();
	width = value["width"].asDouble();
	height = value["height"].asDouble();
	if (value["font filename"].isNull())
		m_font = NULL;
	else {
		filename = value["font filename"].asString();
		loadFont(filename);
	}
}

void FontBlankSymbol::DrawBackground(const Screen& scr, const ISprite* sprite,
									 const Matrix& mt) const
{
	float w = width, h = height;
	const FontSprite* s = dynamic_cast<const FontSprite*>(sprite);
	if (s)
	{
		w = s->width;
		h = s->height;
		if (m_font)
			glColor4f(s->color.r, s->color.g, s->color.b, s->color.a);
	}
	Vector center(0, 0);
	center = Math::transVector(center, mt);
	PrimitiveDraw::rect(scr, center, w*0.5f, h*0.5f, m_style);
}

void FontBlankSymbol::DrawText(const Screen& scr, const ISprite* sprite, const Matrix& mt) const
{
	if (sprite) {
		if (const FontSprite* font = dynamic_cast<const FontSprite*>(sprite)) {
			const std::string& str = font->GetTextContext();
			if (!str.empty()) {
				Vector pos = sprite->getPosition();
				pos = Math::transVector(Vector(pos), mt);

				LabelStyle style;
				style.has_edge = font->has_edge;
				style.font_size = font->size;
				style.width = font->width;
				style.height = font->height;
				style.color = font->color;
				style.align_hori = font->align_hori;
				style.align_vert = font->align_vert;

				LabelNew::Print(scr, str.c_str(), pos, style);
			}
		}
	}

// 	if (sprite) {
// 		if (const FontSprite* font = dynamic_cast<const FontSprite*>(sprite)) {
// 			const std::string& str = font->GetTextContext();
// 			if (!str.empty()) {
// 				d2d::PrimitiveDraw::text(str.c_str());
// 			}
// 		}
// 	}

// 	if (m_font)
// 	{
// 		float w = width;
// 		if (const FontSprite* s = dynamic_cast<const FontSprite*>(sprite)) {
// 			w = s->width;
// 		}
// 		Shader::Instance()->null();
// 		print(-w*0.5f, 0, "abcdEFGH1234");
// 	}
}

void FontBlankSymbol::print(float x, float y, const char* text) const
{
	// We want a coordinate system where things coresponding to window pixels.
	//	pushScreenCoordinateMatrix();

	GLuint font=m_font->list_base;
	float h=m_font->h/.63f;						//We make the height about 1.5* that of

	//Here is some code to split the text that we have been
	//given into a set of lines.
	//This could be made much neater by using
	//a regular expression library such as the one avliable from
	//boost.org (I've only done it out by hand to avoid complicating
	//this tutorial with unnecessary library dependencies).
	const char *start_line=text;
	const char *c;
	std::vector<std::string> lines;
	for(c=text;*c;c++) {
		if(*c=='\n') {
			std::string line;
			for(const char *n=start_line;n<c;n++) line.append(1,*n);
			lines.push_back(line);
			start_line=c+1;
		}
	}
	if(start_line) {
		std::string line;
		for(const char *n=start_line;n<c;n++) line.append(1,*n);
		lines.push_back(line);
	}

	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_LIGHTING);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_DEPTH_TEST);
	//glEnable(GL_BLEND);
	// set in shader
	//	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glListBase(font);

	float modelview_matrix[16];
	glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);

	//This is where the text display actually happens.
	//For each line of text we reset the modelview matrix
	//so that the line's text will start in the correct position.
	//Notice that we need to reset the matrix, rather than just translating
	//down by h. This is because when each character is
	//draw it modifies the current matrix so that the next character
	//will be drawn immediatly after it.
	for(int i=0;i<lines.size();i++) {

		glPushMatrix();
		glLoadIdentity();
		glTranslatef(x,y-h*i,0);
		glMultMatrixf(modelview_matrix);

		//  The commented out raster position stuff can be useful if you need to
		//  know the length of the text that you are creating.
		//  If you decide to use it make sure to also uncomment the glBitmap command
		//  in make_dlist().
		//	glRasterPos2f(0,0);
		glCallLists(lines[i].length(), GL_UNSIGNED_BYTE, lines[i].c_str());
		//	float rpos[4];
		//	glGetFloatv(GL_CURRENT_RASTER_POSITION ,rpos);
		//	float len=x-rpos[0];

		glPopMatrix();
	}

	glPopAttrib();

	//	pop_projection_matrix();

	glBindTexture(GL_TEXTURE_2D, NULL);
}

} // d2d<commit_msg>[FIXED] font content偏移<commit_after>#include "FontBlankSymbol.h"
#include "FontSprite.h"
#include "Font.h"

#include "common/Vector.h"
#include "common/color_trans.h"
#include "common/FileNameTools.h"
#include "common/FileNameParser.h"
#include "common/Settings.h"
#include "common/Math.h"
#include "dataset/SpriteTools.h"
#include "render/PrimitiveDraw.h"
#include "render/Shader.h"
#include "render/LabelNew.h"

//OpenGL Headers
#include <windows.h>
#include <GL/gl.h>

#include <json/json.h>

namespace d2d
{

FontBlankSymbol::FontBlankSymbol()
{
	static int id = 0;
	m_name = wxT("fontblank") + wxVariant(id++);

	align_hori = align_vert = 0;
	size = 0;
	width = height = 100;

	m_font = NULL;

	m_style.fill = true;
	m_style.color.set(0.7f, 0.7f, 0.7f, 0.7f);
}

FontBlankSymbol::~FontBlankSymbol()
{
//	m_font->release();
}

void FontBlankSymbol::reloadTexture() const
{
}

void FontBlankSymbol::draw(const Screen& scr,
						   const Matrix& mt,
						   const Colorf& mul,
						   const Colorf& add,
						   const ISprite* sprite/* = NULL*/) const
{
 	if (Settings::DrawFontType & Settings::DrawFontBg) {
 		DrawBackground(scr, sprite, mt);
 	}
	if (Settings::DrawFontType & Settings::DrawFontText) {
		DrawText(scr, sprite, mt);
	}

	SpriteTools::DrawName(scr, sprite, mt);
}

Rect FontBlankSymbol::getSize(const ISprite* sprite/* = NULL*/) const
{
	return Rect(width, height);
}

void FontBlankSymbol::refresh()
{
}

bool FontBlankSymbol::loadFont(const std::string& _filename)
{
	if (_filename == filename)
		return false;

	std::string filename = FilenameTools::getAbsolutePath(m_filepath, _filename);
	if (!FileNameParser::isType(filename, FileNameParser::e_freetype)
		|| !FilenameTools::isExist(filename))
		return false;

	delete m_font, m_font = NULL;
	m_font = FontMgr::Instance()->getItem(filename);
	return m_font != NULL;
}

void FontBlankSymbol::loadResources()
{
	Json::Value value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(m_filepath.fn_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, value);
	fin.close();

	name = value["name"].asString();
	font = value["font"].asString();
	color = value["color"].asString();
	if (!value["align"].isNull()) {
		align_hori = value["align"].asDouble();
	} else {
		align_hori = value["align hori"].asDouble();
		align_vert = value["align vert"].asDouble();
	}
	size = value["size"].asDouble();
	width = value["width"].asDouble();
	height = value["height"].asDouble();
	if (value["font filename"].isNull())
		m_font = NULL;
	else {
		filename = value["font filename"].asString();
		loadFont(filename);
	}
}

void FontBlankSymbol::DrawBackground(const Screen& scr, const ISprite* sprite,
									 const Matrix& mt) const
{
	float w = width, h = height;
	const FontSprite* s = dynamic_cast<const FontSprite*>(sprite);
	if (s)
	{
		w = s->width;
		h = s->height;
		if (m_font)
			glColor4f(s->color.r, s->color.g, s->color.b, s->color.a);
	}
	Vector center(0, 0);
	center = Math::transVector(center, mt);
	PrimitiveDraw::rect(scr, center, w*0.5f, h*0.5f, m_style);
}

void FontBlankSymbol::DrawText(const Screen& scr, const ISprite* sprite, const Matrix& mt) const
{
	if (sprite) {
		if (const FontSprite* font = dynamic_cast<const FontSprite*>(sprite)) {
			const std::string& str = font->GetTextContext();
			if (!str.empty()) {
				Vector pos = Math::transVector(Vector(0, 0), mt);

				LabelStyle style;
				style.has_edge = font->has_edge;
				style.font_size = font->size;
				style.width = font->width;
				style.height = font->height;
				style.color = font->color;
				style.align_hori = font->align_hori;
				style.align_vert = font->align_vert;

				LabelNew::Print(scr, str.c_str(), pos, style);
			}
		}
	}

// 	if (sprite) {
// 		if (const FontSprite* font = dynamic_cast<const FontSprite*>(sprite)) {
// 			const std::string& str = font->GetTextContext();
// 			if (!str.empty()) {
// 				d2d::PrimitiveDraw::text(str.c_str());
// 			}
// 		}
// 	}

// 	if (m_font)
// 	{
// 		float w = width;
// 		if (const FontSprite* s = dynamic_cast<const FontSprite*>(sprite)) {
// 			w = s->width;
// 		}
// 		Shader::Instance()->null();
// 		print(-w*0.5f, 0, "abcdEFGH1234");
// 	}
}

void FontBlankSymbol::print(float x, float y, const char* text) const
{
	// We want a coordinate system where things coresponding to window pixels.
	//	pushScreenCoordinateMatrix();

	GLuint font=m_font->list_base;
	float h=m_font->h/.63f;						//We make the height about 1.5* that of

	//Here is some code to split the text that we have been
	//given into a set of lines.
	//This could be made much neater by using
	//a regular expression library such as the one avliable from
	//boost.org (I've only done it out by hand to avoid complicating
	//this tutorial with unnecessary library dependencies).
	const char *start_line=text;
	const char *c;
	std::vector<std::string> lines;
	for(c=text;*c;c++) {
		if(*c=='\n') {
			std::string line;
			for(const char *n=start_line;n<c;n++) line.append(1,*n);
			lines.push_back(line);
			start_line=c+1;
		}
	}
	if(start_line) {
		std::string line;
		for(const char *n=start_line;n<c;n++) line.append(1,*n);
		lines.push_back(line);
	}

	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
	glMatrixMode(GL_MODELVIEW);
	glDisable(GL_LIGHTING);
	glEnable(GL_TEXTURE_2D);
	glDisable(GL_DEPTH_TEST);
	//glEnable(GL_BLEND);
	// set in shader
	//	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glListBase(font);

	float modelview_matrix[16];
	glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);

	//This is where the text display actually happens.
	//For each line of text we reset the modelview matrix
	//so that the line's text will start in the correct position.
	//Notice that we need to reset the matrix, rather than just translating
	//down by h. This is because when each character is
	//draw it modifies the current matrix so that the next character
	//will be drawn immediatly after it.
	for(int i=0;i<lines.size();i++) {

		glPushMatrix();
		glLoadIdentity();
		glTranslatef(x,y-h*i,0);
		glMultMatrixf(modelview_matrix);

		//  The commented out raster position stuff can be useful if you need to
		//  know the length of the text that you are creating.
		//  If you decide to use it make sure to also uncomment the glBitmap command
		//  in make_dlist().
		//	glRasterPos2f(0,0);
		glCallLists(lines[i].length(), GL_UNSIGNED_BYTE, lines[i].c_str());
		//	float rpos[4];
		//	glGetFloatv(GL_CURRENT_RASTER_POSITION ,rpos);
		//	float len=x-rpos[0];

		glPopMatrix();
	}

	glPopAttrib();

	//	pop_projection_matrix();

	glBindTexture(GL_TEXTURE_2D, NULL);
}

} // d2d<|endoftext|>


<commit_before>//===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains support for the DJ Bernstein hash function.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/DJB.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Unicode.h"

using namespace llvm;

static UTF32 chopOneUTF32(StringRef &Buffer) {
  UTF32 C;
  const UTF8 *const Begin8Const =
      reinterpret_cast<const UTF8 *>(Buffer.begin());
  const UTF8 *Begin8 = Begin8Const;
  UTF32 *Begin32 = &C;

  // In lenient mode we will always end up with a "reasonable" value in C for
  // non-empty input.
  assert(!Buffer.empty());
  ConvertUTF8toUTF32(&Begin8, reinterpret_cast<const UTF8 *>(Buffer.end()),
                     &Begin32, &C + 1, lenientConversion);
  Buffer = Buffer.drop_front(Begin8 - Begin8Const);
  return C;
}

static StringRef toUTF8(UTF32 C, MutableArrayRef<UTF8> Storage) {
  const UTF32 *Begin32 = &C;
  UTF8 *Begin8 = Storage.begin();

  // The case-folded output should always be a valid unicode character, so use
  // strict mode here.
  ConversionResult CR = ConvertUTF32toUTF8(&Begin32, &C + 1, &Begin8,
                                           Storage.end(), strictConversion);
  assert(CR == conversionOK && "Case folding produced invalid char?");
  (void)CR;
  return StringRef(reinterpret_cast<char *>(Storage.begin()),
                   Begin8 - Storage.begin());
}

static UTF32 foldCharDwarf(UTF32 C) {
  // DWARF v5 addition to the unicode folding rules.
  // Fold "Latin Small Letter Dotless I" and "Latin Capital Letter I With Dot
  // Above" into "i".
  if (C == 0x130 || C == 0x131)
    return 'i';
  return sys::unicode::foldCharSimple(C);
}

static uint32_t caseFoldingDjbHashCharSlow(StringRef &Buffer, uint32_t H) {
  UTF32 C = chopOneUTF32(Buffer);

  C = foldCharDwarf(C);

  std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage;
  StringRef Folded = toUTF8(C, Storage);
  return djbHash(Folded, H);
}

uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) {
  while (!Buffer.empty()) {
    unsigned char C = Buffer.front();
    if (LLVM_LIKELY(C <= 0x7f)) {
      // US-ASCII, encoded as one character in utf-8.
      // This is by far the most common case, so handle this specially.
      if (C >= 'A' && C <= 'Z')
        C = 'a' + (C - 'A'); // fold uppercase into lowercase
      H = (H << 5) + H + C;
      Buffer = Buffer.drop_front();
      continue;
    }
    H = caseFoldingDjbHashCharSlow(Buffer, H);
  }
  return H;
}
<commit_msg>caseFoldingDjbHash: simplify and make the US-ASCII fast path faster<commit_after>//===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains support for the DJ Bernstein hash function.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/DJB.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Unicode.h"

using namespace llvm;

static UTF32 chopOneUTF32(StringRef &Buffer) {
  UTF32 C;
  const UTF8 *const Begin8Const =
      reinterpret_cast<const UTF8 *>(Buffer.begin());
  const UTF8 *Begin8 = Begin8Const;
  UTF32 *Begin32 = &C;

  // In lenient mode we will always end up with a "reasonable" value in C for
  // non-empty input.
  assert(!Buffer.empty());
  ConvertUTF8toUTF32(&Begin8, reinterpret_cast<const UTF8 *>(Buffer.end()),
                     &Begin32, &C + 1, lenientConversion);
  Buffer = Buffer.drop_front(Begin8 - Begin8Const);
  return C;
}

static StringRef toUTF8(UTF32 C, MutableArrayRef<UTF8> Storage) {
  const UTF32 *Begin32 = &C;
  UTF8 *Begin8 = Storage.begin();

  // The case-folded output should always be a valid unicode character, so use
  // strict mode here.
  ConversionResult CR = ConvertUTF32toUTF8(&Begin32, &C + 1, &Begin8,
                                           Storage.end(), strictConversion);
  assert(CR == conversionOK && "Case folding produced invalid char?");
  (void)CR;
  return StringRef(reinterpret_cast<char *>(Storage.begin()),
                   Begin8 - Storage.begin());
}

static UTF32 foldCharDwarf(UTF32 C) {
  // DWARF v5 addition to the unicode folding rules.
  // Fold "Latin Small Letter Dotless I" and "Latin Capital Letter I With Dot
  // Above" into "i".
  if (C == 0x130 || C == 0x131)
    return 'i';
  return sys::unicode::foldCharSimple(C);
}

static Optional<uint32_t> fastCaseFoldingDjbHash(StringRef Buffer, uint32_t H) {
  bool allASCII = true;
  for (unsigned char C : Buffer) {
    H = H * 33 + ('A' <= C && C <= 'Z' ? C - 'A' + 'a' : C);
    allASCII &= C <= 0x7f;
  }
  if (allASCII)
    return H;
  return None;
}

uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) {
  if (Optional<uint32_t> Result = fastCaseFoldingDjbHash(Buffer, H))
    return *Result;

  std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage;
  while (!Buffer.empty()) {
    UTF32 C = foldCharDwarf(chopOneUTF32(Buffer));
    StringRef Folded = toUTF8(C, Storage);
    H = djbHash(Folded, H);
  }
  return H;
}
<|endoftext|>