<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <boost/optional.hpp>

#include "Utils.hpp"
#include "PerfsTimer.hpp"
#include "Options.hpp"
#include "likely.hpp"

#include "ltac/PeepholeOptimizer.hpp"
#include "ltac/Printer.hpp"

#include "mtac/Utils.hpp"

using namespace eddic;

namespace {

template<typename T>
inline bool is_reg(T value){
    return mtac::is<ltac::Register>(value);
}

inline bool transform_to_nop(std::shared_ptr<ltac::Instruction> instruction){
    if(instruction->op == ltac::Operator::NOP){
        return false;
    }

    instruction->op = ltac::Operator::NOP;
    instruction->arg1.reset();
    instruction->arg2.reset();

    return true;
}

inline bool optimize_statement(ltac::Statement& statement){
    if(boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::MOV){
            //MOV reg, 0 can be transformed into XOR reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::XOR;
                instruction->arg2 = instruction->arg1;

                return true;
            }

            if(is_reg(*instruction->arg1) && is_reg(*instruction->arg2)){
                auto& reg1 = boost::get<ltac::Register>(*instruction->arg1);
                auto& reg2 = boost::get<ltac::Register>(*instruction->arg2);

                //MOV reg, reg is useless
                if(reg1 == reg2){
                    return transform_to_nop(instruction);
                }
            }
        }

        if(instruction->op == ltac::Operator::ADD){
            //ADD reg, 1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return true;
            }

            //ADD reg, -1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                    return true;
            }
        }

        if(instruction->op == ltac::Operator::SUB){
            //SUB reg, 1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                    return true;
            }

            //SUB reg, -1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                    return true;
            }
        }

        if(instruction->op == ltac::Operator::MUL){
            //Optimize multiplications with SHIFTs or LEAs
            if(is_reg(*instruction->arg1) && mtac::is<int>(*instruction->arg2)){
                int constant = boost::get<int>(*instruction->arg2);

                auto reg = boost::get<ltac::Register>(*instruction->arg1);

                if(isPowerOfTwo(constant)){
                    instruction->op = ltac::Operator::SHIFT_LEFT;
                    instruction->arg2 = powerOfTwo(constant);

                    return true;
                }

                if(constant == 3){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 2, 0);

                    return true;
                }

                if(constant == 5){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 4, 0);

                    return true;
                }

                if(constant == 9){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 8, 0);

                    return true;
                }
            }
        }

        if(instruction->op == ltac::Operator::CMP_INT){
            //Optimize comparisons with 0 with or reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::OR;
                instruction->arg2 = instruction->arg1;

                    return true;
            }
        }
    }

    return false;
}

inline bool multiple_statement_optimizations(ltac::Statement& s1, ltac::Statement& s2){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(s1) && mtac::is<std::shared_ptr<ltac::Instruction>>(s2)){
        auto& i1 = boost::get<std::shared_ptr<ltac::Instruction>>(s1);
        auto& i2 = boost::get<std::shared_ptr<ltac::Instruction>>(s2);

        //Statements after LEAVE are dead
        if(i1->op == ltac::Operator::LEAVE){
            return transform_to_nop(i2);
        }

        //Combine two FREE STACK into one
        if(i1->op == ltac::Operator::FREE_STACK && i2->op == ltac::Operator::FREE_STACK){
            i1->arg1 = boost::get<int>(*i1->arg1) + boost::get<int>(*i2->arg1);

            return transform_to_nop(i2);
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::MOV){
            if(is_reg(*i1->arg1) && is_reg(*i1->arg2) && is_reg(*i2->arg1) && is_reg(*i2->arg2)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg12 = boost::get<ltac::Register>(*i1->arg2);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);
                auto reg22 = boost::get<ltac::Register>(*i2->arg2);

                //cross MOV (ir4 = ir5, ir5 = ir4), keep only the first
                if (reg11 == reg22 && reg12 == reg21){
                    return transform_to_nop(i2);
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);

                //Two MOV to the same register => keep only last MOV
                if(reg11 == reg21){
                    return transform_to_nop(i1);
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg2)){
                if(boost::get<ltac::Address>(&*i1->arg2) && boost::get<ltac::Address>(&*i2->arg1)){
                    if(boost::get<ltac::Address>(*i1->arg2) == boost::get<ltac::Address>(*i2->arg1)){
                        return transform_to_nop(i2);
                    }
                }
            } else if(is_reg(*i1->arg2) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Address>(&*i1->arg1) && boost::get<ltac::Address>(&*i2->arg2)){
                    if(boost::get<ltac::Address>(*i1->arg1) == boost::get<ltac::Address>(*i2->arg2)){
                        return transform_to_nop(i2);
                    }
                }
            }
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::ADD){
            if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Register>(*i1->arg1) == boost::get<ltac::Register>(*i2->arg1)){
                    if(boost::get<ltac::Register>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<ltac::Register>(*i1->arg2), boost::get<int>(*i2->arg2));

                        return transform_to_nop(i1);
                    } else if(boost::get<std::string>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<std::string>(*i1->arg2), boost::get<int>(*i2->arg2));

                        return transform_to_nop(i1);
                    }
                }
            }
        }
    }

    return false;
}

inline bool is_nop(ltac::Statement& statement){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::NOP){
            return true;
        }
    }

    return false;
}

bool basic_optimizations(std::shared_ptr<ltac::Function> function){
    auto& statements = function->getStatements();

    auto it = statements.begin();
    auto end = statements.end() - 1;

    bool optimized = false;

    while(it != end){
        auto& s1 = *it;
        auto& s2 = *(it + 1);

        //Optimizations that looks at only one statement
        optimized |= optimize_statement(s1);
        optimized |= optimize_statement(s2);

        //Optimizations that looks at several statements at once
        optimized |= multiple_statement_optimizations(s1, s2);

        if(unlikely(is_nop(s1))){
            it = statements.erase(it);
            end = statements.end() - 1;

            continue;
        }

        ++it;
    }

    return optimized;
}

bool constant_propagation(std::shared_ptr<ltac::Function> function){
    bool optimized = false;

    auto& statements = function->getStatements();

    std::unordered_map<ltac::Register, int, ltac::RegisterHash> constants;

    for(std::size_t i = 0; i < statements.size(); ++i){
        auto statement = statements[i];

        if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
            auto instruction = *ptr;

            //Erase constant
            if(instruction->arg1 && is_reg(*instruction->arg1)){
                auto reg1 = boost::get<ltac::Register>(*instruction->arg1);

                constants.erase(reg1);
            }

            //Collect constants
            if(instruction->op == ltac::Operator::XOR){
                if(is_reg(*instruction->arg1) && is_reg(*instruction->arg2)){
                    auto reg1 = boost::get<ltac::Register>(*instruction->arg1);
                    auto reg2 = boost::get<ltac::Register>(*instruction->arg2);

                    if(reg1 == reg2){
                        constants[reg1] = 0;
                    }
                }
            } else if(instruction->op == ltac::Operator::MOV){
                if(is_reg(*instruction->arg1)){
                    if (auto* valuePtr = boost::get<int>(&*instruction->arg2)){
                        auto reg1 = boost::get<ltac::Register>(*instruction->arg1);
                        constants[reg1] = *valuePtr;
                    }
                }
            }

            //Optimize MOV
            if(instruction->op == ltac::Operator::MOV){
                if(is_reg(*instruction->arg2)){
                    auto reg2 = boost::get<ltac::Register>(*instruction->arg2);

                    if(constants.find(reg2) != constants.end()){
                        instruction->arg2 = constants[reg2];
                        optimized = true;
                    }
                }
            }
        } else {
            //At this point, the basic block is at its end
            constants.clear();
        }
    }

    return optimized;
}

bool debug(const std::string& name, bool b, std::shared_ptr<ltac::Function> function){
    if(option_defined("dev")){
        if(b){
            std::cout << "optimization " << name << " returned true" << std::endl;

            //Print the function
            ltac::Printer printer;
            printer.print(function);
        } else {
            std::cout << "optimization " << name << " returned false" << std::endl;
        }
    }

    return b;
}

} //end of anonymous namespace

void eddic::ltac::optimize(std::shared_ptr<ltac::Program> program){
    PerfsTimer timer("Peephole optimizations");

    for(auto& function : program->functions){
        if(option_defined("dev")){
            std::cout << "Start optimizations on " << function->getName() << std::endl;

            //Print the function
            ltac::Printer printer;
            printer.print(function);
        }

        bool optimized;
        do {
            optimized = false;

            optimized |= debug("Basic optimizations", basic_optimizations(function), function);
            optimized |= debug("Constant propagation", constant_propagation(function), function);
        } while(optimized);
    }
}
<commit_msg>Implement first prototype of dead-code-elimination<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <boost/optional.hpp>

#include "Utils.hpp"
#include "PerfsTimer.hpp"
#include "Options.hpp"
#include "likely.hpp"
#include "Platform.hpp"

#include "ltac/PeepholeOptimizer.hpp"
#include "ltac/Printer.hpp"

#include "mtac/Utils.hpp"

using namespace eddic;

namespace {

template<typename T>
inline bool is_reg(T value){
    return mtac::is<ltac::Register>(value);
}

inline bool transform_to_nop(std::shared_ptr<ltac::Instruction> instruction){
    if(instruction->op == ltac::Operator::NOP){
        return false;
    }

    instruction->op = ltac::Operator::NOP;
    instruction->arg1.reset();
    instruction->arg2.reset();

    return true;
}

inline bool optimize_statement(ltac::Statement& statement){
    if(boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::MOV){
            //MOV reg, 0 can be transformed into XOR reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::XOR;
                instruction->arg2 = instruction->arg1;

                return true;
            }

            if(is_reg(*instruction->arg1) && is_reg(*instruction->arg2)){
                auto& reg1 = boost::get<ltac::Register>(*instruction->arg1);
                auto& reg2 = boost::get<ltac::Register>(*instruction->arg2);

                //MOV reg, reg is useless
                if(reg1 == reg2){
                    return transform_to_nop(instruction);
                }
            }
        }

        if(instruction->op == ltac::Operator::ADD){
            //ADD reg, 1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return true;
            }

            //ADD reg, -1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                    return true;
            }
        }

        if(instruction->op == ltac::Operator::SUB){
            //SUB reg, 1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                    return true;
            }

            //SUB reg, -1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                    return true;
            }
        }

        if(instruction->op == ltac::Operator::MUL){
            //Optimize multiplications with SHIFTs or LEAs
            if(is_reg(*instruction->arg1) && mtac::is<int>(*instruction->arg2)){
                int constant = boost::get<int>(*instruction->arg2);

                auto reg = boost::get<ltac::Register>(*instruction->arg1);

                if(isPowerOfTwo(constant)){
                    instruction->op = ltac::Operator::SHIFT_LEFT;
                    instruction->arg2 = powerOfTwo(constant);

                    return true;
                }

                if(constant == 3){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 2, 0);

                    return true;
                }

                if(constant == 5){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 4, 0);

                    return true;
                }

                if(constant == 9){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 8, 0);

                    return true;
                }
            }
        }

        if(instruction->op == ltac::Operator::CMP_INT){
            //Optimize comparisons with 0 with or reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::OR;
                instruction->arg2 = instruction->arg1;

                    return true;
            }
        }
    }

    return false;
}

inline bool multiple_statement_optimizations(ltac::Statement& s1, ltac::Statement& s2){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(s1) && mtac::is<std::shared_ptr<ltac::Instruction>>(s2)){
        auto& i1 = boost::get<std::shared_ptr<ltac::Instruction>>(s1);
        auto& i2 = boost::get<std::shared_ptr<ltac::Instruction>>(s2);

        //Statements after LEAVE are dead
        if(i1->op == ltac::Operator::LEAVE){
            return transform_to_nop(i2);
        }

        //Combine two FREE STACK into one
        if(i1->op == ltac::Operator::FREE_STACK && i2->op == ltac::Operator::FREE_STACK){
            i1->arg1 = boost::get<int>(*i1->arg1) + boost::get<int>(*i2->arg1);

            return transform_to_nop(i2);
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::MOV){
            if(is_reg(*i1->arg1) && is_reg(*i1->arg2) && is_reg(*i2->arg1) && is_reg(*i2->arg2)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg12 = boost::get<ltac::Register>(*i1->arg2);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);
                auto reg22 = boost::get<ltac::Register>(*i2->arg2);

                //cross MOV (ir4 = ir5, ir5 = ir4), keep only the first
                if (reg11 == reg22 && reg12 == reg21){
                    return transform_to_nop(i2);
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);

                //Two MOV to the same register => keep only last MOV
                if(reg11 == reg21){
                    return transform_to_nop(i1);
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg2)){
                if(boost::get<ltac::Address>(&*i1->arg2) && boost::get<ltac::Address>(&*i2->arg1)){
                    if(boost::get<ltac::Address>(*i1->arg2) == boost::get<ltac::Address>(*i2->arg1)){
                        return transform_to_nop(i2);
                    }
                }
            } else if(is_reg(*i1->arg2) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Address>(&*i1->arg1) && boost::get<ltac::Address>(&*i2->arg2)){
                    if(boost::get<ltac::Address>(*i1->arg1) == boost::get<ltac::Address>(*i2->arg2)){
                        return transform_to_nop(i2);
                    }
                }
            }
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::ADD){
            if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Register>(*i1->arg1) == boost::get<ltac::Register>(*i2->arg1)){
                    if(boost::get<ltac::Register>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<ltac::Register>(*i1->arg2), boost::get<int>(*i2->arg2));

                        return transform_to_nop(i1);
                    } else if(boost::get<std::string>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<std::string>(*i1->arg2), boost::get<int>(*i2->arg2));

                        return transform_to_nop(i1);
                    }
                }
            }
        }
    }

    return false;
}

inline bool is_nop(ltac::Statement& statement){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::NOP){
            return true;
        }
    }

    return false;
}

bool basic_optimizations(std::shared_ptr<ltac::Function> function){
    auto& statements = function->getStatements();

    auto it = statements.begin();
    auto end = statements.end() - 1;

    bool optimized = false;

    while(it != end){
        auto& s1 = *it;
        auto& s2 = *(it + 1);

        //Optimizations that looks at only one statement
        optimized |= optimize_statement(s1);
        optimized |= optimize_statement(s2);

        //Optimizations that looks at several statements at once
        optimized |= multiple_statement_optimizations(s1, s2);

        if(unlikely(is_nop(s1))){
            it = statements.erase(it);
            end = statements.end() - 1;

            continue;
        }

        ++it;
    }

    return optimized;
}

bool constant_propagation(std::shared_ptr<ltac::Function> function){
    bool optimized = false;

    auto& statements = function->getStatements();

    std::unordered_map<ltac::Register, int, ltac::RegisterHash> constants;

    for(std::size_t i = 0; i < statements.size(); ++i){
        auto statement = statements[i];

        if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
            auto instruction = *ptr;

            //Erase constant
            if(instruction->arg1 && is_reg(*instruction->arg1)){
                auto reg1 = boost::get<ltac::Register>(*instruction->arg1);

                constants.erase(reg1);
            }

            //Collect constants
            if(instruction->op == ltac::Operator::XOR){
                if(is_reg(*instruction->arg1) && is_reg(*instruction->arg2)){
                    auto reg1 = boost::get<ltac::Register>(*instruction->arg1);
                    auto reg2 = boost::get<ltac::Register>(*instruction->arg2);

                    if(reg1 == reg2){
                        constants[reg1] = 0;
                    }
                }
            } else if(instruction->op == ltac::Operator::MOV){
                if(is_reg(*instruction->arg1)){
                    if (auto* valuePtr = boost::get<int>(&*instruction->arg2)){
                        auto reg1 = boost::get<ltac::Register>(*instruction->arg1);
                        constants[reg1] = *valuePtr;
                    }
                }
            }

            //Optimize MOV
            if(instruction->op == ltac::Operator::MOV){
                if(is_reg(*instruction->arg2)){
                    auto reg2 = boost::get<ltac::Register>(*instruction->arg2);

                    if(constants.find(reg2) != constants.end()){
                        instruction->arg2 = constants[reg2];
                        optimized = true;
                    }
                }
            }
        } else {
            //At this point, the basic block is at its end
            constants.clear();
        }
    }

    return optimized;
}

typedef std::unordered_set<ltac::Register, ltac::RegisterHash> RegisterUsage;

//TODO This can be optimized by doing it context dependent to avoid saving each register
void add_escaped_registers(RegisterUsage& usage){
    auto descriptor = getPlatformDescriptor(platform);

    usage.insert(ltac::Register(descriptor->int_return_register1()));
    usage.insert(ltac::Register(descriptor->int_return_register2()));

    for(unsigned int i = 1; i <= descriptor->numberOfIntParamRegisters(); ++i){
        usage.insert(ltac::Register(descriptor->int_param_register(i)));
    }
}

bool dead_code_elimination(std::shared_ptr<ltac::Function> function){
    bool optimized = false;

    auto& statements = function->getStatements();

    RegisterUsage usage;
    add_escaped_registers(usage);

    for(long i = statements.size() - 1; i >= 0; --i){
        auto statement = statements[i];

        if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
            auto instruction = *ptr;

            //Optimize MOV and XOR
            if(instruction->op == ltac::Operator::MOV){
                if(is_reg(*instruction->arg1)){
                    auto reg1 = boost::get<ltac::Register>(*instruction->arg1);

                    if(usage.find(reg1) == usage.end()){
                        optimized = transform_to_nop(instruction);
                    }
                }
            } else if(instruction->op == ltac::Operator::XOR){
                if(is_reg(*instruction->arg1) || is_reg(*instruction->arg2)){
                    auto reg1 = boost::get<ltac::Register>(*instruction->arg1);
                    auto reg2 = boost::get<ltac::Register>(*instruction->arg2);

                    if(reg1 == reg2 && usage.find(reg1) == usage.end()){
                        optimized = transform_to_nop(instruction);
                    }
                }
            }

            //Collect usage
            if(instruction->arg1 && is_reg(*instruction->arg1)){
                auto reg1 = boost::get<ltac::Register>(*instruction->arg1);
                usage.insert(reg1);
            }

            if(instruction->arg2 && is_reg(*instruction->arg2)){
                auto reg2 = boost::get<ltac::Register>(*instruction->arg2);
                usage.insert(reg2);
            }

            if(instruction->arg3 && is_reg(*instruction->arg3)){
                auto reg3 = boost::get<ltac::Register>(*instruction->arg3);
                usage.insert(reg3);
            }

            //Erase usage if the register gets written to
            if(instruction->arg1 && is_reg(*instruction->arg1)){
                auto reg1 = boost::get<ltac::Register>(*instruction->arg1);

                usage.erase(reg1);
            }
        } else {
            //At this point, the basic block is at its end
            usage.clear();
            add_escaped_registers(usage);
        }
    }

    return optimized;
}

bool debug(const std::string& name, bool b, std::shared_ptr<ltac::Function> function){
    if(option_defined("dev")){
        if(b){
            std::cout << "optimization " << name << " returned true" << std::endl;

            //Print the function
            ltac::Printer printer;
            printer.print(function);
        } else {
            std::cout << "optimization " << name << " returned false" << std::endl;
        }
    }

    return b;
}

} //end of anonymous namespace

void eddic::ltac::optimize(std::shared_ptr<ltac::Program> program){
    PerfsTimer timer("Peephole optimizations");

    for(auto& function : program->functions){
        if(option_defined("dev")){
            std::cout << "Start optimizations on " << function->getName() << std::endl;

            //Print the function
            ltac::Printer printer;
            printer.print(function);
        }

        bool optimized;
        do {
            optimized = false;

            optimized |= debug("Basic optimizations", basic_optimizations(function), function);
            optimized |= debug("Constant propagation", constant_propagation(function), function);
            optimized |= debug("Dead-Code Elimination", dead_code_elimination(function), function);
        } while(optimized);
    }
}
<|endoftext|>


<commit_before>///
/// @file   SieveOfEratosthenes.cpp
/// @brief  Implementation of the segmented sieve of Eratosthenes.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the New BSD License. See the
/// LICENSE file in the top level directory.
///

#include "config.h"
#include "SieveOfEratosthenes.h"
#include "PreSieve.h"
#include "EratSmall.h"
#include "EratMedium.h"
#include "EratBig.h"
#include "imath.h"
#include "primesieve_error.h"

#include <stdint.h>
#include <exception>
#include <string>
#include <cstdlib>

namespace soe {

const uint_t SieveOfEratosthenes::bitValues_[8] = { 7, 11, 13, 17, 19, 23, 29, 31 };

/// De Bruijn bitscan table
const uint_t SieveOfEratosthenes::bruijnBitValues_[64] =
{
    7,  47,  11,  49,  67, 113,  13,  53,
   89,  71, 161, 101, 119, 187,  17, 233,
   59,  79,  91,  73, 133, 139, 163, 103,
  149, 121, 203, 169, 191, 217,  19, 239,
   43,  61, 109,  83, 157,  97, 181, 229,
   77, 131, 137, 143, 199, 167, 211,  41,
  107, 151, 179, 227, 127, 197, 209,  37,
  173, 223, 193,  31, 221,  29,  23, 241
};

/// @param start      Sieve primes >= start.
/// @param stop       Sieve primes <= stop.
/// @param sieveSize  A sieve size in kilobytes.
/// @param preSieve   Pre-sieve multiples of small primes <= preSieve
///                   to speed up the sieve of Eratosthenes.
/// @pre   start      >= 7
/// @pre   stop       <= 2^64 - 2^32 * 10
/// @pre   sieveSize  >= 1 && <= 4096
/// @pre   preSieve   >= 13 && <= 23
///
SieveOfEratosthenes::SieveOfEratosthenes(uint64_t start,
                                         uint64_t stop,
                                         uint_t sieveSize,
                                         uint_t preSieve) :
  start_(start),
  stop_(stop),
  sieve_(NULL),
  preSieve_(NULL),
  eratSmall_(NULL),
  eratMedium_(NULL),
  eratBig_(NULL)
{
  if (start_ < 7)
    throw primesieve_error("SieveOfEratosthenes: start must be >= 7");
  if (start_ > stop_)
    throw primesieve_error("SieveOfEratosthenes: start must be <= stop");
  // sieveSize_ must be a power of 2
  sieveSize_ = getInBetween(1u, floorPowerOf2(sieveSize), 4096u);
  sieveSize_ *= 1024; // convert to bytes
  segmentLow_ = start_ - getByteRemainder(start_);
  segmentHigh_ = segmentLow_ + sieveSize_ * NUMBERS_PER_BYTE + 1;
  sqrtStop_ = static_cast<uint_t>(isqrt(stop_));
  init(preSieve);
}

SieveOfEratosthenes::~SieveOfEratosthenes()
{
  cleanUp();
}

void SieveOfEratosthenes::cleanUp()
{
  delete[] sieve_;
  delete preSieve_;
  delete eratSmall_;
  delete eratMedium_;
  delete eratBig_;
}

void SieveOfEratosthenes::init(uint_t limitPreSieve)
{
  limitEratSmall_  = static_cast<uint_t>(sieveSize_ * config::FACTOR_ERATSMALL);
  limitEratMedium_ = static_cast<uint_t>(sieveSize_ * config::FACTOR_ERATMEDIUM);
  try {
    // allocate the sieve of Eratosthenes array
    sieve_ = new byte_t[sieveSize_];
    preSieve_ = new PreSieve(limitPreSieve);

    if (sqrtStop_ > getPreSieve())    eratSmall_  = new EratSmall (stop_, sieveSize_, limitEratSmall_);
    if (sqrtStop_ > limitEratSmall_)  eratMedium_ = new EratMedium(stop_, sieveSize_, limitEratMedium_);
    if (sqrtStop_ > limitEratMedium_) eratBig_    = new EratBig   (stop_, sieveSize_, sqrtStop_);
  }
  catch (const std::exception& e) {
    cleanUp();
    throw e;
  }
}

uint_t SieveOfEratosthenes::getSqrtStop() const
{
  return sqrtStop_;
}

uint_t SieveOfEratosthenes::getPreSieve() const
{
  return preSieve_->getLimit();
}

std::string SieveOfEratosthenes::getMaxStopString()
{
  return EratBig::getMaxStopString();
}

uint64_t SieveOfEratosthenes::getMaxStop()
{
  return EratBig::getMaxStop();
}

uint64_t SieveOfEratosthenes::getByteRemainder(uint64_t n)
{
  uint64_t r = n % NUMBERS_PER_BYTE;
  if (r <= 1)
    r += NUMBERS_PER_BYTE;
  return r;
}

void SieveOfEratosthenes::sieveSegment()
{
  preSieve();
  crossOffMultiples();
  segmentProcessed(sieve_, sieveSize_);
}

void SieveOfEratosthenes::crossOffMultiples()
{
  if (eratSmall_)   eratSmall_->crossOff(sieve_, &sieve_[sieveSize_]);
  if (eratMedium_) eratMedium_->crossOff(sieve_, sieveSize_);
  if (eratBig_)       eratBig_->crossOff(sieve_);
}

/// Pre-sieve multiples of small primes e.g. <= 19
/// to speed up the sieve of Eratosthenes.
///
void SieveOfEratosthenes::preSieve()
{
  preSieve_->doIt(sieve_, sieveSize_, segmentLow_);
  // unset bits (numbers) < start_
  if (segmentLow_ <= start_) {
    if (start_ <= preSieve_->getLimit())
      sieve_[0] = 0xff;
    int i = 0;
    while (bitValues_[i] < getByteRemainder(start_)) i++;
    sieve_[0] &= 0xff << i;
  }
}

/// Sieve the last segments remaining after that sieve(uint_t)
/// has been called for all primes up to sqrt(stop).
///
void SieveOfEratosthenes::finish()
{
  // sieve all segments left except the last one
  while (segmentHigh_ < stop_) {
    sieveSegment();
    segmentLow_  += sieveSize_ * NUMBERS_PER_BYTE;
    segmentHigh_ += sieveSize_ * NUMBERS_PER_BYTE;
  }
  // sieve the last segment
  uint64_t remainder = getByteRemainder(stop_);
  sieveSize_ = static_cast<uint_t>((stop_ - remainder) - segmentLow_) / NUMBERS_PER_BYTE + 1;
  segmentHigh_ = segmentLow_ + sieveSize_ * NUMBERS_PER_BYTE + 1;
  preSieve();
  crossOffMultiples();
  int i;
  // unset bits (numbers) > stop_
  for (i = 0; i < 8; i++)
    if (bitValues_[i] > remainder)
      break;
  sieve_[sieveSize_ - 1] &= ~(0xff << i);
  for (uint_t j = sieveSize_; j % 8 != 0; j++)
    sieve_[j] = 0;
  segmentProcessed(sieve_, sieveSize_);
}

} // namespace soe
<commit_msg>improved code readability<commit_after>///
/// @file   SieveOfEratosthenes.cpp
/// @brief  Implementation of the segmented sieve of Eratosthenes.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the New BSD License. See the
/// LICENSE file in the top level directory.
///

#include "config.h"
#include "SieveOfEratosthenes.h"
#include "PreSieve.h"
#include "EratSmall.h"
#include "EratMedium.h"
#include "EratBig.h"
#include "imath.h"
#include "primesieve_error.h"

#include <stdint.h>
#include <exception>
#include <string>
#include <cstdlib>

namespace soe {

const uint_t SieveOfEratosthenes::bitValues_[8] = { 7, 11, 13, 17, 19, 23, 29, 31 };

/// De Bruijn bitscan table
const uint_t SieveOfEratosthenes::bruijnBitValues_[64] =
{
    7,  47,  11,  49,  67, 113,  13,  53,
   89,  71, 161, 101, 119, 187,  17, 233,
   59,  79,  91,  73, 133, 139, 163, 103,
  149, 121, 203, 169, 191, 217,  19, 239,
   43,  61, 109,  83, 157,  97, 181, 229,
   77, 131, 137, 143, 199, 167, 211,  41,
  107, 151, 179, 227, 127, 197, 209,  37,
  173, 223, 193,  31, 221,  29,  23, 241
};

/// @param start      Sieve primes >= start.
/// @param stop       Sieve primes <= stop.
/// @param sieveSize  A sieve size in kilobytes.
/// @param preSieve   Pre-sieve multiples of small primes <= preSieve
///                   to speed up the sieve of Eratosthenes.
/// @pre   start      >= 7
/// @pre   stop       <= 2^64 - 2^32 * 10
/// @pre   sieveSize  >= 1 && <= 4096
/// @pre   preSieve   >= 13 && <= 23
///
SieveOfEratosthenes::SieveOfEratosthenes(uint64_t start,
                                         uint64_t stop,
                                         uint_t sieveSize,
                                         uint_t preSieve) :
  start_(start),
  stop_(stop),
  sieve_(NULL),
  preSieve_(NULL),
  eratSmall_(NULL),
  eratMedium_(NULL),
  eratBig_(NULL)
{
  if (start_ < 7)
    throw primesieve_error("SieveOfEratosthenes: start must be >= 7");
  if (start_ > stop_)
    throw primesieve_error("SieveOfEratosthenes: start must be <= stop");
  sqrtStop_ = static_cast<uint_t>(isqrt(stop_));
  // sieveSize_ must be a power of 2
  sieveSize_ = getInBetween(1u, floorPowerOf2(sieveSize), 4096u);
  sieveSize_ *= 1024; // convert to bytes
  segmentLow_ = start_ - getByteRemainder(start_);
  segmentHigh_ = segmentLow_ + sieveSize_ * NUMBERS_PER_BYTE + 1;
  // allocate the sieve of Eratosthenes array
  sieve_ = new byte_t[sieveSize_];
  init(preSieve);
}

SieveOfEratosthenes::~SieveOfEratosthenes()
{
  cleanUp();
}

void SieveOfEratosthenes::cleanUp()
{
  delete[] sieve_;
  delete preSieve_;
  delete eratSmall_;
  delete eratMedium_;
  delete eratBig_;
}

void SieveOfEratosthenes::init(uint_t preSieve)
{
  limitEratSmall_  = static_cast<uint_t>(sieveSize_ * config::FACTOR_ERATSMALL);
  limitEratMedium_ = static_cast<uint_t>(sieveSize_ * config::FACTOR_ERATMEDIUM);
  try {
    preSieve_ = new PreSieve(preSieve);

    if (sqrtStop_ > getPreSieve())    eratSmall_  = new EratSmall (stop_, sieveSize_, limitEratSmall_);
    if (sqrtStop_ > limitEratSmall_)  eratMedium_ = new EratMedium(stop_, sieveSize_, limitEratMedium_);
    if (sqrtStop_ > limitEratMedium_) eratBig_    = new EratBig   (stop_, sieveSize_, sqrtStop_);
  }
  catch (const std::exception& e) {
    cleanUp();
    throw e;
  }
}

uint_t SieveOfEratosthenes::getSqrtStop() const
{
  return sqrtStop_;
}

uint_t SieveOfEratosthenes::getPreSieve() const
{
  return preSieve_->getLimit();
}

std::string SieveOfEratosthenes::getMaxStopString()
{
  return EratBig::getMaxStopString();
}

uint64_t SieveOfEratosthenes::getMaxStop()
{
  return EratBig::getMaxStop();
}

uint64_t SieveOfEratosthenes::getByteRemainder(uint64_t n)
{
  uint64_t r = n % NUMBERS_PER_BYTE;
  if (r <= 1)
    r += NUMBERS_PER_BYTE;
  return r;
}

void SieveOfEratosthenes::sieveSegment()
{
  preSieve();
  crossOffMultiples();
  segmentProcessed(sieve_, sieveSize_);
}

void SieveOfEratosthenes::crossOffMultiples()
{
  if (eratSmall_)   eratSmall_->crossOff(sieve_, &sieve_[sieveSize_]);
  if (eratMedium_) eratMedium_->crossOff(sieve_, sieveSize_);
  if (eratBig_)       eratBig_->crossOff(sieve_);
}

/// Pre-sieve multiples of small primes e.g. <= 19
/// to speed up the sieve of Eratosthenes.
///
void SieveOfEratosthenes::preSieve()
{
  preSieve_->doIt(sieve_, sieveSize_, segmentLow_);
  // unset bits (numbers) < start_
  if (segmentLow_ <= start_) {
    if (start_ <= preSieve_->getLimit())
      sieve_[0] = 0xff;
    int i = 0;
    while (bitValues_[i] < getByteRemainder(start_)) i++;
    sieve_[0] &= 0xff << i;
  }
}

/// Sieve the last segments remaining after that sieve(uint_t)
/// has been called for all primes up to sqrt(stop).
///
void SieveOfEratosthenes::finish()
{
  // sieve all segments left except the last one
  while (segmentHigh_ < stop_) {
    sieveSegment();
    segmentLow_  += sieveSize_ * NUMBERS_PER_BYTE;
    segmentHigh_ += sieveSize_ * NUMBERS_PER_BYTE;
  }
  // sieve the last segment
  uint64_t remainder = getByteRemainder(stop_);
  sieveSize_ = static_cast<uint_t>((stop_ - remainder) - segmentLow_) / NUMBERS_PER_BYTE + 1;
  segmentHigh_ = segmentLow_ + sieveSize_ * NUMBERS_PER_BYTE + 1;
  preSieve();
  crossOffMultiples();
  int i;
  // unset bits (numbers) > stop_
  for (i = 0; i < 8; i++)
    if (bitValues_[i] > remainder)
      break;
  sieve_[sieveSize_ - 1] &= ~(0xff << i);
  for (uint_t j = sieveSize_; j % 8 != 0; j++)
    sieve_[j] = 0;
  segmentProcessed(sieve_, sieveSize_);
}

} // namespace soe
<|endoftext|>


<commit_before>#ifndef __STAN__IO__STAN_CSV_READER_HPP__
#define __STAN__IO__STAN_CSV_READER_HPP__

#include <istream>
#include <iostream>
#include <sstream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <stan/math/matrix.hpp>

namespace stan {
  namespace io {

    // FIXME: should consolidate with the options from the command line in stan::gm
    struct stan_csv_metadata {
      int stan_version_major;
      int stan_version_minor;
      int stan_version_patch;

      std::string model;
      std::string data;
      std::string init;
      bool append_samples;
      bool save_warmup;
      size_t seed;
      bool random_seed;
      size_t chain_id;
      size_t iter;
      size_t warmup;
      size_t thin;
      bool equal_step_sizes;
      bool nondiag_mass;
      int leapfrog_steps;
      int max_treedepth;
      double epsilon;
      double epsilon_pm;
      double delta;
      double gamma;
      std::string algorithm;
    };

    struct stan_csv_adaptation {
      double step_size;
      Eigen::MatrixXd metric;
    };

    struct stan_csv_timing {
      double warmup;
      double sampling;
    };

    struct stan_csv {
      stan_csv_metadata metadata;
      Eigen::Matrix<std::string, Eigen::Dynamic, 1> header;
      stan_csv_adaptation adaptation;
      Eigen::MatrixXd samples;
      stan_csv_timing timing;
    };

    /**
     * Reads from a Stan output csv file.
     */
    class stan_csv_reader {

    public:

      stan_csv_reader() {}
      ~stan_csv_reader() {}

      static bool read_metadata(std::istream& in, stan_csv_metadata& metadata) {

        std::stringstream ss;
        std::string line;

        if (in.peek() != '#')
          return false;
        while (in.peek() == '#') {
          std::getline(in, line);
          ss << line << '\n';
        }
        ss.seekg(std::ios_base::beg);

        char comment;
        std::string lhs;

        // Skip first two lines
        std::getline(ss, line);
        std::getline(ss, line);

        while (ss.good()) {

          ss >> comment;
          std::getline(ss, lhs, '=');
          boost::trim(lhs);

          if (lhs.compare("") == 0) { // no-op
          } else if (lhs.compare("stan_version_major") == 0) {
            ss >> metadata.stan_version_major;
          } else if (lhs.compare("stan_version_minor") == 0) {
            ss >> metadata.stan_version_minor;
          } else if (lhs.compare("stan_version_patch") == 0) {
            ss >> metadata.stan_version_patch;
          } else if (lhs.compare("model") == 0) {
            ss >> metadata.model;
          } else if (lhs.compare("data") == 0) {
            ss >> metadata.data;
          } else if (lhs.compare("init") == 0) {
            std::getline(ss, metadata.init);
            boost::trim(metadata.init);
            ss.unget();
          } else if (lhs.compare("append_samples") == 0) {
            ss >> metadata.append_samples;
          } else if (lhs.compare("save_warmup") == 0) {
            ss >> metadata.save_warmup;
          } else if (lhs.compare("seed") == 0) {
            ss >> metadata.seed;
            metadata.random_seed = false;
          } else if (lhs.compare("chain_id") == 0) {
            ss >> metadata.chain_id;
          } else if (lhs.compare("iter") == 0) {
            ss >> metadata.iter;
          } else if (lhs.compare("warmup") == 0) {
            ss >> metadata.warmup;
          } else if (lhs.compare("thin") == 0) {
            ss >> metadata.thin;
          } else if (lhs.compare("equal_step_sizes") == 0) {
            ss >> metadata.equal_step_sizes;
                } else if (lhs.compare("nondiag_mass") == 0) {
            ss >> metadata.nondiag_mass;
          } else if (lhs.compare("leapfrog_steps") == 0) {
            ss >> metadata.leapfrog_steps;
          } else if (lhs.compare("max_treedepth") == 0) {
            ss >> metadata.max_treedepth;
          } else if (lhs.compare("epsilon") == 0) {
            ss >> metadata.epsilon;
          } else if (lhs.compare("epsilon_pm") == 0) {
            ss >> metadata.epsilon_pm;
          } else if (lhs.compare("delta") == 0) {
            ss >> metadata.delta;
          } else if (lhs.compare("gamma") == 0) {
            ss >> metadata.gamma;
          } else if (lhs.compare("algorithm") == 0) {
            std::getline(ss, metadata.algorithm);
            boost::trim(metadata.algorithm);
            ss.unget();
          } else {
            std::cout << "unused option: " << lhs << std::endl;
          }

          std::getline(ss, line);

        }

        if (ss.good() == true)
          return false;

        return true;

      } // read_metadata

      static bool read_header(std::istream& in, Eigen::Matrix<std::string, Eigen::Dynamic, 1>& header) {

        std::string line;

        if (in.peek() != 'l')
          return false;

        std::getline(in, line);
        std::stringstream ss(line);

        header.resize(std::count(line.begin(), line.end(), ',') + 1);
        int idx = 0;
        while (ss.good()) {
          std::string token;
          std::getline(ss, token, ',');
          boost::trim(token);

          int pos = token.find('.');
          if (pos > 0) {
            token.replace(pos, 1, "[");
            std::replace(token.begin(), token.end(), '.', ',');
            token += "]";
          }
          header(idx++) = token;
        }
        return true;
      }

      static bool read_adaptation(std::istream& in, stan_csv_adaptation& adaptation) {

        std::stringstream ss;
        std::string line;
        int lines = 0;

        if (in.peek() != '#' || in.good() == false)
          return false;

        while (in.peek() == '#') {
          std::getline(in, line);
          ss << line << std::endl;
          lines++;
        }
        ss.seekg(std::ios_base::beg);

        char comment; // Buffer for comment indicator, #

        // Skip first two lines
        std::getline(ss, line);

        // Stepsize
        std::getline(ss, line, '=');
        boost::trim(line);
        ss >> adaptation.step_size;

        // Metric parameters
        std::getline(ss, line);
        std::getline(ss, line);
        std::getline(ss, line);

        int rows = lines - 3;
        int cols = std::count(line.begin(), line.end(), ',') + 1;
        adaptation.metric.resize(rows, cols);

        for (int row = 0; row < rows; row++) {

          std::stringstream line_ss;
          line_ss.str(line);
          line_ss >> comment;

          for (int col = 0; col < cols; col++) {
            std::string token;
            std::getline(line_ss, token, ',');
            boost::trim(token);
            adaptation.metric(row, col) = boost::lexical_cast<double>(token);
          }

          std::getline(ss, line); // Read in next line

        }

        if (ss.good())
          return false;
        else
          return true;

      }

      static bool read_samples(std::istream& in, Eigen::MatrixXd& samples, stan_csv_timing& timing) {

        std::stringstream ss;
        std::string line;

        int rows = 0;
        int cols = -1;

        if (in.peek() == '#' || in.good() == false)
          return false;

        while (in.good()) {

          bool comment_line = (in.peek() == '#');
          bool empty_line   = (in.peek() == '\n');

          std::getline(in, line);

          if (empty_line) continue;
          if (!line.length()) break;

          if (comment_line) {

            if (line.find("(Warm-up)") != std::string::npos) {
              int left = 16;
              int right = line.find(" seconds");
              timing.warmup += boost::lexical_cast<double>(line.substr(left, right - left));
            } else if (line.find("(Sampling)") != std::string::npos) {
              int left = 16;
              int right = line.find(" seconds");
              timing.sampling += boost::lexical_cast<double>(line.substr(left, right - left));
            }

          }
          else {

            ss << line << '\n';

            int current_cols = std::count(line.begin(), line.end(), ',') + 1;
            if (cols == -1) {
              cols = current_cols;
            } else if (cols != current_cols) {
              std::cout << "Error: expected " << cols << " columns, but found "
                        << current_cols << " instead for row " << rows + 1 << std::endl;
              return false;
            }
            rows++;

          }

          in.peek();

        }

        ss.seekg(std::ios_base::beg);

        if (rows > 0) {
          samples.resize(rows, cols);
          for (int row = 0; row < rows; row++) {
            std::getline(ss, line);
            std::stringstream ls(line);
            for (int col = 0; col < cols; col++) {
              std::getline(ls, line, ',');
              std::cout << row << "\t" << col << "\t" << line << std::endl;
              samples(row, col) = boost::lexical_cast<double>(line);
            }
          }
        }
        return true;
      }

      /**
       * Parses the file.
       *
       */
      static stan_csv parse(std::istream& in) {

        stan_csv data;

        if (!read_metadata(in, data.metadata)) {
          std::cout << "Warning: non-fatal error reading metadata" << std::endl;
        }

        if (!read_header(in, data.header)) {
          std::cout << "Error: error reading header" << std::endl;
          throw std::invalid_argument("Error with header of input file in parse");
        }

        if (!read_adaptation(in, data.adaptation)) {
          std::cout << "Warning: non-fatal error reading adapation data" << std::endl;
        }

        data.timing.warmup = 0;
        data.timing.sampling = 0;

        if (!read_samples(in, data.samples, data.timing)) {
          std::cout << "Warning: non-fatal error reading samples" << std::endl;
        }

        return data;

      }

    };

  } // io

} // stan

#endif
<commit_msg>Removed debug output line<commit_after>#ifndef __STAN__IO__STAN_CSV_READER_HPP__
#define __STAN__IO__STAN_CSV_READER_HPP__

#include <istream>
#include <iostream>
#include <sstream>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <stan/math/matrix.hpp>

namespace stan {
  namespace io {

    // FIXME: should consolidate with the options from the command line in stan::gm
    struct stan_csv_metadata {
      int stan_version_major;
      int stan_version_minor;
      int stan_version_patch;

      std::string model;
      std::string data;
      std::string init;
      bool append_samples;
      bool save_warmup;
      size_t seed;
      bool random_seed;
      size_t chain_id;
      size_t iter;
      size_t warmup;
      size_t thin;
      bool equal_step_sizes;
      bool nondiag_mass;
      int leapfrog_steps;
      int max_treedepth;
      double epsilon;
      double epsilon_pm;
      double delta;
      double gamma;
      std::string algorithm;
    };

    struct stan_csv_adaptation {
      double step_size;
      Eigen::MatrixXd metric;
    };

    struct stan_csv_timing {
      double warmup;
      double sampling;
    };

    struct stan_csv {
      stan_csv_metadata metadata;
      Eigen::Matrix<std::string, Eigen::Dynamic, 1> header;
      stan_csv_adaptation adaptation;
      Eigen::MatrixXd samples;
      stan_csv_timing timing;
    };

    /**
     * Reads from a Stan output csv file.
     */
    class stan_csv_reader {

    public:

      stan_csv_reader() {}
      ~stan_csv_reader() {}

      static bool read_metadata(std::istream& in, stan_csv_metadata& metadata) {

        std::stringstream ss;
        std::string line;

        if (in.peek() != '#')
          return false;
        while (in.peek() == '#') {
          std::getline(in, line);
          ss << line << '\n';
        }
        ss.seekg(std::ios_base::beg);

        char comment;
        std::string lhs;

        // Skip first two lines
        std::getline(ss, line);
        std::getline(ss, line);

        while (ss.good()) {

          ss >> comment;
          std::getline(ss, lhs, '=');
          boost::trim(lhs);

          if (lhs.compare("") == 0) { // no-op
          } else if (lhs.compare("stan_version_major") == 0) {
            ss >> metadata.stan_version_major;
          } else if (lhs.compare("stan_version_minor") == 0) {
            ss >> metadata.stan_version_minor;
          } else if (lhs.compare("stan_version_patch") == 0) {
            ss >> metadata.stan_version_patch;
          } else if (lhs.compare("model") == 0) {
            ss >> metadata.model;
          } else if (lhs.compare("data") == 0) {
            ss >> metadata.data;
          } else if (lhs.compare("init") == 0) {
            std::getline(ss, metadata.init);
            boost::trim(metadata.init);
            ss.unget();
          } else if (lhs.compare("append_samples") == 0) {
            ss >> metadata.append_samples;
          } else if (lhs.compare("save_warmup") == 0) {
            ss >> metadata.save_warmup;
          } else if (lhs.compare("seed") == 0) {
            ss >> metadata.seed;
            metadata.random_seed = false;
          } else if (lhs.compare("chain_id") == 0) {
            ss >> metadata.chain_id;
          } else if (lhs.compare("iter") == 0) {
            ss >> metadata.iter;
          } else if (lhs.compare("warmup") == 0) {
            ss >> metadata.warmup;
          } else if (lhs.compare("thin") == 0) {
            ss >> metadata.thin;
          } else if (lhs.compare("equal_step_sizes") == 0) {
            ss >> metadata.equal_step_sizes;
                } else if (lhs.compare("nondiag_mass") == 0) {
            ss >> metadata.nondiag_mass;
          } else if (lhs.compare("leapfrog_steps") == 0) {
            ss >> metadata.leapfrog_steps;
          } else if (lhs.compare("max_treedepth") == 0) {
            ss >> metadata.max_treedepth;
          } else if (lhs.compare("epsilon") == 0) {
            ss >> metadata.epsilon;
          } else if (lhs.compare("epsilon_pm") == 0) {
            ss >> metadata.epsilon_pm;
          } else if (lhs.compare("delta") == 0) {
            ss >> metadata.delta;
          } else if (lhs.compare("gamma") == 0) {
            ss >> metadata.gamma;
          } else if (lhs.compare("algorithm") == 0) {
            std::getline(ss, metadata.algorithm);
            boost::trim(metadata.algorithm);
            ss.unget();
          } else {
            std::cout << "unused option: " << lhs << std::endl;
          }

          std::getline(ss, line);

        }

        if (ss.good() == true)
          return false;

        return true;

      } // read_metadata

      static bool read_header(std::istream& in, Eigen::Matrix<std::string, Eigen::Dynamic, 1>& header) {

        std::string line;

        if (in.peek() != 'l')
          return false;

        std::getline(in, line);
        std::stringstream ss(line);

        header.resize(std::count(line.begin(), line.end(), ',') + 1);
        int idx = 0;
        while (ss.good()) {
          std::string token;
          std::getline(ss, token, ',');
          boost::trim(token);

          int pos = token.find('.');
          if (pos > 0) {
            token.replace(pos, 1, "[");
            std::replace(token.begin(), token.end(), '.', ',');
            token += "]";
          }
          header(idx++) = token;
        }
        return true;
      }

      static bool read_adaptation(std::istream& in, stan_csv_adaptation& adaptation) {

        std::stringstream ss;
        std::string line;
        int lines = 0;

        if (in.peek() != '#' || in.good() == false)
          return false;

        while (in.peek() == '#') {
          std::getline(in, line);
          ss << line << std::endl;
          lines++;
        }
        ss.seekg(std::ios_base::beg);

        char comment; // Buffer for comment indicator, #

        // Skip first two lines
        std::getline(ss, line);

        // Stepsize
        std::getline(ss, line, '=');
        boost::trim(line);
        ss >> adaptation.step_size;

        // Metric parameters
        std::getline(ss, line);
        std::getline(ss, line);
        std::getline(ss, line);

        int rows = lines - 3;
        int cols = std::count(line.begin(), line.end(), ',') + 1;
        adaptation.metric.resize(rows, cols);

        for (int row = 0; row < rows; row++) {

          std::stringstream line_ss;
          line_ss.str(line);
          line_ss >> comment;

          for (int col = 0; col < cols; col++) {
            std::string token;
            std::getline(line_ss, token, ',');
            boost::trim(token);
            adaptation.metric(row, col) = boost::lexical_cast<double>(token);
          }

          std::getline(ss, line); // Read in next line

        }

        if (ss.good())
          return false;
        else
          return true;

      }

      static bool read_samples(std::istream& in, Eigen::MatrixXd& samples, stan_csv_timing& timing) {

        std::stringstream ss;
        std::string line;

        int rows = 0;
        int cols = -1;

        if (in.peek() == '#' || in.good() == false)
          return false;

        while (in.good()) {

          bool comment_line = (in.peek() == '#');
          bool empty_line   = (in.peek() == '\n');

          std::getline(in, line);

          if (empty_line) continue;
          if (!line.length()) break;

          if (comment_line) {

            if (line.find("(Warm-up)") != std::string::npos) {
              int left = 16;
              int right = line.find(" seconds");
              timing.warmup += boost::lexical_cast<double>(line.substr(left, right - left));
            } else if (line.find("(Sampling)") != std::string::npos) {
              int left = 16;
              int right = line.find(" seconds");
              timing.sampling += boost::lexical_cast<double>(line.substr(left, right - left));
            }

          }
          else {

            ss << line << '\n';

            int current_cols = std::count(line.begin(), line.end(), ',') + 1;
            if (cols == -1) {
              cols = current_cols;
            } else if (cols != current_cols) {
              std::cout << "Error: expected " << cols << " columns, but found "
                        << current_cols << " instead for row " << rows + 1 << std::endl;
              return false;
            }
            rows++;

          }

          in.peek();

        }

        ss.seekg(std::ios_base::beg);

        if (rows > 0) {
          samples.resize(rows, cols);
          for (int row = 0; row < rows; row++) {
            std::getline(ss, line);
            std::stringstream ls(line);
            for (int col = 0; col < cols; col++) {
              std::getline(ls, line, ',');
              samples(row, col) = boost::lexical_cast<double>(line);
            }
          }
        }
        return true;
      }

      /**
       * Parses the file.
       *
       */
      static stan_csv parse(std::istream& in) {

        stan_csv data;

        if (!read_metadata(in, data.metadata)) {
          std::cout << "Warning: non-fatal error reading metadata" << std::endl;
        }

        if (!read_header(in, data.header)) {
          std::cout << "Error: error reading header" << std::endl;
          throw std::invalid_argument("Error with header of input file in parse");
        }

        if (!read_adaptation(in, data.adaptation)) {
          std::cout << "Warning: non-fatal error reading adapation data" << std::endl;
        }

        data.timing.warmup = 0;
        data.timing.sampling = 0;

        if (!read_samples(in, data.samples, data.timing)) {
          std::cout << "Warning: non-fatal error reading samples" << std::endl;
        }

        return data;

      }

    };

  } // io

} // stan

#endif
<|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2009 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "lzmainputstream.h"
extern "C" {
  #include "lzma/LzmaDec.h"
}
#include "textutils.h"
#include <iostream>

using namespace Strigi;
using namespace std;

class LZMAInputStream::Private {
public:
    LZMAInputStream* const p;
    CLzmaProps props;
    CLzmaDec state;
    InputStream *input;
    const char* next_in;
    int32_t avail_in;
    int64_t bytesDecompressed;

    Private(LZMAInputStream* p, InputStream* i);
    ~Private();
    void readFromStream();
    int32_t fillBuffer(char* start, int32_t space);
};
bool
LZMAInputStream::checkHeader(const char* data, int32_t datasize) {
    if (datasize < LZMA_PROPS_SIZE + 8) return false;

    // lzma does not have magic bytes, but it has a function for parsing
    // the header which contains the stream properties
    // by limiting the range of sizes we support and doing a sanity check on the
    // size of the dictionary, the number of files that are regarded as valid
    // can be limited
    CLzmaProps props;
    SRes res = LzmaProps_Decode(&props, (const Byte*)data, LZMA_PROPS_SIZE);
    int64_t size = readLittleEndianInt64(data + LZMA_PROPS_SIZE);
    return res == SZ_OK && (size == -1 ||
        (props.dicSize < size && size < 1099511627776LL)); // only support < 1Tb
}
LZMAInputStream::LZMAInputStream(InputStream* input)
    :p(new Private(this, input)){
}
static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
static void SzFree(void *p, void *address) { p = p; free(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
LZMAInputStream::Private::Private(LZMAInputStream* bis, InputStream* i)
        :p(bis), input(i) {

    // check the header and read the size of the uncompressed stream
    SRes res = SZ_ERROR_UNSUPPORTED;
    LzmaDec_Construct(&state);
    const char* data;
    int32_t nread;
    const int32_t headersize = LZMA_PROPS_SIZE+8;
    nread = input->read(data, headersize, headersize);
    if (nread == headersize && checkHeader(data, headersize)) {
        // allocate the decompressor
        res = LzmaDec_Allocate(&state, (const Byte*)data, LZMA_PROPS_SIZE,
            &g_Alloc);
        p->m_size = readLittleEndianInt64(data + LZMA_PROPS_SIZE);
    }
    if (res != SZ_OK || p->m_size < -1) {
        p->m_error = "LZMA header is not supported.";
        p->m_status = Error;
        return;
    }
    LzmaDec_Init(&state);
    bytesDecompressed = 0;

    // signal that we need to read into the buffer
    avail_in = 0;

    // set the minimum size for the output buffer
    p->setMinBufSize(262144);
}
LZMAInputStream::~LZMAInputStream() {
    delete p;
}
LZMAInputStream::Private::~Private() {
    LzmaDec_Free(&state, &g_Alloc);
}
void
LZMAInputStream::Private::readFromStream() {
    // read data from the input stream
    avail_in = input->read(next_in, 1, 0);
    if (avail_in <= -1) {
        p->m_status = Error;
        p->m_error = input->error();
    } else if (avail_in < 1) {
        p->m_status = Error;
        p->m_error = "unexpected end of stream";
    }
}
int32_t
LZMAInputStream::fillBuffer(char* start, int32_t space) {
    if (m_status != Ok) return -1;
    if (m_size == p->bytesDecompressed) {
        return -1;
    }
    return p->fillBuffer(start, space);
}
int32_t
LZMAInputStream::Private::fillBuffer(char* start, int32_t space) {
    // make sure there is data to decompress
    if (avail_in == 0) {
        readFromStream();
        if (p->m_status != Ok) {
            // no data was read
            return -1;
        }
    }
    // decompress
    SizeT outProcessed = space;
    SizeT inProcessed = avail_in;
    ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
    int64_t bytesTodo = p->m_size - bytesDecompressed;
    if (p->m_size != -1 && outProcessed > bytesTodo) {
        outProcessed = (SizeT)bytesTodo;
        finishMode = LZMA_FINISH_END;
    }
    ELzmaStatus status;
    SRes res = LzmaDec_DecodeToBuf(&state, (Byte*)start, &outProcessed,
        (const Byte*)next_in, &inProcessed, finishMode, &status);
    avail_in -= inProcessed;
    next_in += inProcessed;
    bytesDecompressed += outProcessed;
    if (res != SZ_OK) {
        p->m_error = "error decompressing";
        p->m_status = Error;
        return -1;
    }
    if (inProcessed == 0 && outProcessed == 0) {
        if (p->m_size != -1 || status != LZMA_STATUS_FINISHED_WITH_MARK) {
            p->m_error = "unexpected end";
            p->m_status = Error;
            return -1;
        }
        p->m_size = bytesDecompressed;
    } else if (status == LZMA_STATUS_FINISHED_WITH_MARK) {
        p->m_size = bytesDecompressed;
    }
    return outProcessed;
}
<commit_msg>Add check on 'magic' and dicSize.<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2009 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "lzmainputstream.h"
extern "C" {
  #include "lzma/LzmaDec.h"
}
#include "textutils.h"
#include <iostream>
#include <sstream>

using namespace Strigi;
using namespace std;

class LZMAInputStream::Private {
public:
    LZMAInputStream* const p;
    CLzmaProps props;
    CLzmaDec state;
    InputStream *input;
    const char* next_in;
    int32_t avail_in;
    int64_t bytesDecompressed;

    Private(LZMAInputStream* p, InputStream* i);
    ~Private();
    void readFromStream();
    int32_t fillBuffer(char* start, int32_t space);
};
bool
LZMAInputStream::checkHeader(const char* data, int32_t datasize) {
    if (datasize < LZMA_PROPS_SIZE + 8) return false;

    // lzma does not have magic bytes, but it has a function for parsing
    // the header which contains the stream properties
    // nevertheless some use '5d 00' as the magic bytes
    if (data[0] != 0x5d || data[1] != 0x00) return false;

    // by limiting the range of sizes and doing a sanity check on the
    // size of the dictionary, the number of files that are regarded as valid
    // can be limited
    CLzmaProps props;
    SRes res = LzmaProps_Decode(&props, (const Byte*)data, LZMA_PROPS_SIZE);
    int64_t size = readLittleEndianInt64(data + LZMA_PROPS_SIZE);
    return res == SZ_OK && props.dicSize <= 8388608 && (size == -1 ||
        (props.dicSize < size && size < 1099511627776LL)); // only support < 1Tb
}
LZMAInputStream::LZMAInputStream(InputStream* input)
    :p(new Private(this, input)){
}
static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
static void SzFree(void *p, void *address) { p = p; free(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
LZMAInputStream::Private::Private(LZMAInputStream* bis, InputStream* i)
        :p(bis), input(i) {

    // check the header and read the size of the uncompressed stream
    SRes res = SZ_ERROR_UNSUPPORTED;
    LzmaDec_Construct(&state);
    const char* data;
    int32_t nread;
    const int32_t headersize = LZMA_PROPS_SIZE+8;
    nread = input->read(data, headersize, headersize);
    if (nread == headersize && checkHeader(data, headersize)) {
        // allocate the decompressor
        res = LzmaDec_Allocate(&state, (const Byte*)data, LZMA_PROPS_SIZE,
            &g_Alloc);
        p->m_size = readLittleEndianInt64(data + LZMA_PROPS_SIZE);
    }
    if (res != SZ_OK || p->m_size < -1) {
        p->m_error = "LZMA header is not supported.";
        p->m_status = Error;
        return;
    }
    LzmaDec_Init(&state);
    bytesDecompressed = 0;

    // signal that we need to read into the buffer
    avail_in = 0;

    // set the minimum size for the output buffer
    p->setMinBufSize(262144);
}
LZMAInputStream::~LZMAInputStream() {
    delete p;
}
LZMAInputStream::Private::~Private() {
    LzmaDec_Free(&state, &g_Alloc);
}
void
LZMAInputStream::Private::readFromStream() {
    // read data from the input stream
    avail_in = input->read(next_in, 1, 0);
    if (avail_in <= -1) {
        p->m_status = Error;
        p->m_error = input->error();
    } else if (avail_in < 1) {
        p->m_status = Error;
        p->m_error = "unexpected end of stream";
    }
}
int32_t
LZMAInputStream::fillBuffer(char* start, int32_t space) {
    if (m_status != Ok) return -1;
    if (m_size == p->bytesDecompressed) {
        return -1;
    }
    return p->fillBuffer(start, space);
}
int32_t
LZMAInputStream::Private::fillBuffer(char* start, int32_t space) {
    // make sure there is data to decompress
    if (avail_in == 0) {
        readFromStream();
        if (p->m_status != Ok) {
            // no data was read
            return -1;
        }
    }
    // decompress
    SizeT outProcessed = space;
    SizeT inProcessed = avail_in;
    ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
    int64_t bytesTodo = p->m_size - bytesDecompressed;
    if (p->m_size != -1 && outProcessed > bytesTodo) {
        outProcessed = (SizeT)bytesTodo;
        finishMode = LZMA_FINISH_END;
    }
    ELzmaStatus status;
    SRes res = LzmaDec_DecodeToBuf(&state, (Byte*)start, &outProcessed,
        (const Byte*)next_in, &inProcessed, finishMode, &status);
    avail_in -= inProcessed;
    next_in += inProcessed;
    bytesDecompressed += outProcessed;
    if (res != SZ_OK) {
        ostringstream str;
        str << "error decompressing dicsize: " << props.dicSize
            << " size: " << p->m_size
            << " decompressed: " << bytesDecompressed;
        p->m_error = str.str();
        p->m_status = Error;
        return -1;
    }
    if (inProcessed == 0 && outProcessed == 0) {
        if (p->m_size != -1 || status != LZMA_STATUS_FINISHED_WITH_MARK) {
            p->m_error = "unexpected end";
            p->m_status = Error;
            return -1;
        }
        p->m_size = bytesDecompressed;
    } else if (status == LZMA_STATUS_FINISHED_WITH_MARK) {
        p->m_size = bytesDecompressed;
    }
    return outProcessed;
}
<|endoftext|>


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

#include <stdio.h>

#include "esnpapi.h"

namespace
{

NPIdentifier getSpecialIdentifier(const Any& any)
{
    NPIdentifier id;

    if (any.isString())
    {
        id =  NPN_GetStringIdentifier(static_cast<const std::string>(any).c_str());
    }
    else
    {
        id = NPN_GetIntIdentifier(static_cast<uint32_t>(any));
    }
    return id;
}

template <typename T>
void expandSequence(NPP npp, const Sequence<T> sequence, NPVariant* variantArray)
{
    for (unsigned i = 0; i < sequence.getLength(); ++i)
    {
        convertToVariant(npp, sequence[i], variantArray + i);
    }
}

Any processResult(NPP npp, const NPVariant* variant)
{
    Any result = convertToAny(npp, variant);
    if (NPVARIANT_IS_OBJECT(*variant))
    {
        if (!result.isObject())
        {
            NPN_ReleaseObject(NPVARIANT_TO_OBJECT(*variant));
        }
        else if (!isStub(NPVARIANT_TO_OBJECT(*variant)))
        {
            ProxyObject* proxy = interface_cast<ProxyObject*>(static_cast<Object*>(result));
            if (proxy)
            {
                proxy->mark();
            }
        }
    }
    return result;
}

}  // namespace

Any invoke(Object* object, unsigned interfaceNumber, unsigned methodNumber,
           const char* meta, unsigned offset,
           unsigned argumentCount, Any* arguments)
{
    ProxyObject* proxy = interface_cast<ProxyObject*>(object);
    if (!proxy)
    {
        return Any();
    }
    Reflect::Interface interface = Reflect::Interface(meta);
    Reflect::Method method = Reflect::Method(meta + offset);
    Reflect::Type type = method.getReturnType();

    printf("invoke %s::%s %p\n", interface.getName().c_str(), method.getName().c_str(), proxy->getNPObject());

    NPIdentifier id;
    NPVariant result;
    VOID_TO_NPVARIANT(result);

    if (method.isGetter())
    {
        id = NPN_GetStringIdentifier(method.getName().c_str());
        if (NPN_GetProperty(proxy->getNPP(), proxy->getNPObject(), id, &result))
        {
            return processResult(proxy->getNPP(), &result);
        }
    }
    else if (method.isSetter())
    {
        id = NPN_GetStringIdentifier(method.getName().c_str());
        NPVariant value;
        convertToVariant(proxy->getNPP(), arguments[argumentCount - 1], &value);
        NPN_SetProperty(proxy->getNPP(), proxy->getNPObject(), id, &value);
    }
    else if (method.isSpecialGetter())
    {
        id = getSpecialIdentifier(arguments[argumentCount - 1]);
        if (NPN_GetProperty(proxy->getNPP(), proxy->getNPObject(), id, &result))
        {
            return processResult(proxy->getNPP(), &result);
        }
    }
    else if (method.isSpecialSetter() || method.isSpecialCreator())
    {
        id = getSpecialIdentifier(arguments[argumentCount - 2]);
        NPVariant value;
        convertToVariant(proxy->getNPP(), arguments[argumentCount - 1], &value);
        NPN_SetProperty(proxy->getNPP(), proxy->getNPObject(), id, &value);
    }
    else if (method.isSpecialDeleter())
    {
        id = getSpecialIdentifier(arguments[argumentCount - 1]);
        NPN_RemoveProperty(proxy->getNPP(), proxy->getNPObject(), id);
    }
    else
    {
        unsigned variadicCount = 0;
        if (method.isVariadic())
        {
            --argumentCount;
            Sequence<int> sequence(arguments[argumentCount]);  // TODO: make sure this works ignoring T
            variadicCount = sequence.getLength();
        }

        unsigned variantCount = argumentCount + variadicCount;
        NPVariant variantArray[variantCount];
        for (int i = 0; i < argumentCount; ++i)
        {
            convertToVariant(proxy->getNPP(), arguments[i], &variantArray[i]);
        }

        if (0 < variadicCount)
        {
            Reflect::Parameter param = method.listParameter();
            for (int i = 0; i < method.getParameterCount(); ++i)
            {
                param.next();
            }
            // TODO: Check Nullable, too.
            switch (param.getType().getType())
            {
            case Reflect::kBoolean:
                expandSequence(proxy->getNPP(), Sequence<bool>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kOctet:
                expandSequence(proxy->getNPP(), Sequence<uint8_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kShort:
                expandSequence(proxy->getNPP(), Sequence<int16_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kUnsignedShort:
                expandSequence(proxy->getNPP(), Sequence<uint16_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kLong:
                expandSequence(proxy->getNPP(), Sequence<int32_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kUnsignedLong:
                expandSequence(proxy->getNPP(), Sequence<uint32_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kLongLong:
                expandSequence(proxy->getNPP(), Sequence<int64_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kUnsignedLongLong:
                expandSequence(proxy->getNPP(), Sequence<uint64_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kFloat:
                expandSequence(proxy->getNPP(), Sequence<float>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kDouble:
                expandSequence(proxy->getNPP(), Sequence<double>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kString:
                expandSequence(proxy->getNPP(), Sequence<std::string>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kAny:
                expandSequence(proxy->getNPP(), Sequence<Any>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            // TODO: kSequence???
            case Reflect::kObject:
            default:
                expandSequence(proxy->getNPP(), Sequence<Object*>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            }
        }

        id = NPN_GetStringIdentifier(method.getName().c_str());
        if (method.isOperation())
        {
            if (NPN_Invoke(proxy->getNPP(), proxy->getNPObject(), id, variantArray, variantCount, &result))
            {
                return processResult(proxy->getNPP(), &result);
            }
        }
        else if (method.isConstructor())
        {
            // Chrome uses NPN_Construct()
            if (NPN_Construct(proxy->getNPP(), proxy->getNPObject(), variantArray, variantCount, &result))
            {
                return processResult(proxy->getNPP(), &result);
            }
            // Firefox uses NPN_InvokeDefault()
            if (NPN_InvokeDefault(proxy->getNPP(), proxy->getNPObject(), variantArray, variantCount, &result))
            {
                return processResult(proxy->getNPP(), &result);
            }
        }
    }
    return Any();
}
<commit_msg>(processResult) : Release the returned NPVariant value unless it is an NPObject to be used later.<commit_after>/*
 * Copyright 2009, 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>

#include "esnpapi.h"

namespace
{

NPIdentifier getSpecialIdentifier(const Any& any)
{
    NPIdentifier id;

    if (any.isString())
    {
        id =  NPN_GetStringIdentifier(static_cast<const std::string>(any).c_str());
    }
    else
    {
        id = NPN_GetIntIdentifier(static_cast<uint32_t>(any));
    }
    return id;
}

template <typename T>
void expandSequence(NPP npp, const Sequence<T> sequence, NPVariant* variantArray)
{
    for (unsigned i = 0; i < sequence.getLength(); ++i)
    {
        convertToVariant(npp, sequence[i], variantArray + i);
    }
}

Any processResult(NPP npp, NPVariant* variant)
{
    Any result = convertToAny(npp, variant);
    if (NPVARIANT_IS_OBJECT(*variant))
    {
        if (!result.isObject())
        {
            NPN_ReleaseObject(NPVARIANT_TO_OBJECT(*variant));
        }
        else if (!isStub(NPVARIANT_TO_OBJECT(*variant)))
        {
            ProxyObject* proxy = interface_cast<ProxyObject*>(static_cast<Object*>(result));
            if (proxy)
            {
                proxy->mark();
            }
        }
    }
    else
    {
        NPN_ReleaseVariantValue(variant);
    }
    return result;
}

}  // namespace

Any invoke(Object* object, unsigned interfaceNumber, unsigned methodNumber,
           const char* meta, unsigned offset,
           unsigned argumentCount, Any* arguments)
{
    ProxyObject* proxy = interface_cast<ProxyObject*>(object);
    if (!proxy)
    {
        return Any();
    }
    Reflect::Interface interface = Reflect::Interface(meta);
    Reflect::Method method = Reflect::Method(meta + offset);
    Reflect::Type type = method.getReturnType();

    printf("invoke %s::%s %p\n", interface.getName().c_str(), method.getName().c_str(), proxy->getNPObject());

    NPIdentifier id;
    NPVariant result;
    VOID_TO_NPVARIANT(result);

    if (method.isGetter())
    {
        id = NPN_GetStringIdentifier(method.getName().c_str());
        if (NPN_GetProperty(proxy->getNPP(), proxy->getNPObject(), id, &result))
        {
            return processResult(proxy->getNPP(), &result);
        }
    }
    else if (method.isSetter())
    {
        id = NPN_GetStringIdentifier(method.getName().c_str());
        NPVariant value;
        convertToVariant(proxy->getNPP(), arguments[argumentCount - 1], &value);
        NPN_SetProperty(proxy->getNPP(), proxy->getNPObject(), id, &value);
    }
    else if (method.isSpecialGetter())
    {
        id = getSpecialIdentifier(arguments[argumentCount - 1]);
        if (NPN_GetProperty(proxy->getNPP(), proxy->getNPObject(), id, &result))
        {
            return processResult(proxy->getNPP(), &result);
        }
    }
    else if (method.isSpecialSetter() || method.isSpecialCreator())
    {
        id = getSpecialIdentifier(arguments[argumentCount - 2]);
        NPVariant value;
        convertToVariant(proxy->getNPP(), arguments[argumentCount - 1], &value);
        NPN_SetProperty(proxy->getNPP(), proxy->getNPObject(), id, &value);
    }
    else if (method.isSpecialDeleter())
    {
        id = getSpecialIdentifier(arguments[argumentCount - 1]);
        NPN_RemoveProperty(proxy->getNPP(), proxy->getNPObject(), id);
    }
    else
    {
        unsigned variadicCount = 0;
        if (method.isVariadic())
        {
            --argumentCount;
            Sequence<int> sequence(arguments[argumentCount]);  // TODO: make sure this works ignoring T
            variadicCount = sequence.getLength();
        }

        unsigned variantCount = argumentCount + variadicCount;
        NPVariant variantArray[variantCount];
        for (int i = 0; i < argumentCount; ++i)
        {
            convertToVariant(proxy->getNPP(), arguments[i], &variantArray[i]);
        }

        if (0 < variadicCount)
        {
            Reflect::Parameter param = method.listParameter();
            for (int i = 0; i < method.getParameterCount(); ++i)
            {
                param.next();
            }
            // TODO: Check Nullable, too.
            switch (param.getType().getType())
            {
            case Reflect::kBoolean:
                expandSequence(proxy->getNPP(), Sequence<bool>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kOctet:
                expandSequence(proxy->getNPP(), Sequence<uint8_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kShort:
                expandSequence(proxy->getNPP(), Sequence<int16_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kUnsignedShort:
                expandSequence(proxy->getNPP(), Sequence<uint16_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kLong:
                expandSequence(proxy->getNPP(), Sequence<int32_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kUnsignedLong:
                expandSequence(proxy->getNPP(), Sequence<uint32_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kLongLong:
                expandSequence(proxy->getNPP(), Sequence<int64_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kUnsignedLongLong:
                expandSequence(proxy->getNPP(), Sequence<uint64_t>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kFloat:
                expandSequence(proxy->getNPP(), Sequence<float>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kDouble:
                expandSequence(proxy->getNPP(), Sequence<double>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kString:
                expandSequence(proxy->getNPP(), Sequence<std::string>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            case Reflect::kAny:
                expandSequence(proxy->getNPP(), Sequence<Any>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            // TODO: kSequence???
            case Reflect::kObject:
            default:
                expandSequence(proxy->getNPP(), Sequence<Object*>(arguments[argumentCount]), &variantArray[argumentCount]);
                break;
            }
        }

        id = NPN_GetStringIdentifier(method.getName().c_str());
        if (method.isOperation())
        {
            if (NPN_Invoke(proxy->getNPP(), proxy->getNPObject(), id, variantArray, variantCount, &result))
            {
                return processResult(proxy->getNPP(), &result);
            }
        }
        else if (method.isConstructor())
        {
            // Chrome uses NPN_Construct()
            if (NPN_Construct(proxy->getNPP(), proxy->getNPObject(), variantArray, variantCount, &result))
            {
                return processResult(proxy->getNPP(), &result);
            }
            // Firefox uses NPN_InvokeDefault()
            if (NPN_InvokeDefault(proxy->getNPP(), proxy->getNPObject(), variantArray, variantCount, &result))
            {
                return processResult(proxy->getNPP(), &result);
            }
        }
    }
    return Any();
}
<|endoftext|>


<commit_before>/*
 * qmqtt_frame.cpp - qmqtt frame
 *
 * Copyright (c) 2013  Ery Lee <ery.lee at gmail dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of mqttc nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include <QDataStream>
#include "qmqtt_frame.h"

namespace QMQTT {

Frame::Frame(quint8 header, QObject *parent) :
    QObject(parent),
    _header(header),
    _data(QByteArray())
{
}

Frame::Frame(quint8 header, QByteArray & data, QObject *parent) :
    QObject(parent),
    _header(header),
    _data(data)
{
}

Frame::~Frame()
{

}

quint8 Frame::header()
{
    return _header;
}

QByteArray & Frame::data()
{
    return _data;
}

char Frame::readChar()
{
    char c = _data.at(0);
    _data.remove(0, 1);
    return c;
}

int Frame::readInt()
{
    char msb = _data.at(0);
    char lsb = _data.at(1);
    _data.remove(0, 2);
    return (msb << 8) + lsb;
}

QString Frame::readString()
{
    int len = readInt();
    QString s(_data.left(len));
    _data.remove(0, len);
    return s;
}

void Frame::writeInt(int i)
{
    _data.append(MSB(i));
    _data.append(LSB(i));
}

void Frame::writeString(const QString &string)
{
    writeInt(string.size());
    _data.append(string);
}

void Frame::writeChar(char c)
{
    _data.append(c);
}

void Frame::writeRawData(const QByteArray &data)
{
    _data.append(data);
}

void Frame::write(QDataStream &stream)
{
    QByteArray lenbuf;
    stream << (quint8)_header;
    if(_data.size() == 0) {
        stream << (QChar)0;
        return;
    }
    qDebug("_data.size: %d", _data.size());
    encodeLength(lenbuf, _data.size());
    stream.writeRawData(lenbuf.data(), lenbuf.size());
    stream.writeRawData(_data.data(), _data.size());
}

void Frame::encodeLength(QByteArray &lenbuf, int length)
{
    char d;
    do {
        d = length % 128;
        length /= 128;
        if (length > 0) {
            d |= 0x80;
        }
        lenbuf.append(d);
    } while (length > 0);
}

} // namespace QMQTT
<commit_msg>QChar -> qunit8<commit_after>/*
 * qmqtt_frame.cpp - qmqtt frame
 *
 * Copyright (c) 2013  Ery Lee <ery.lee at gmail dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of mqttc nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include <QDataStream>
#include "qmqtt_frame.h"

namespace QMQTT {

Frame::Frame(quint8 header, QObject *parent) :
    QObject(parent),
    _header(header),
    _data(QByteArray())
{
}

Frame::Frame(quint8 header, QByteArray & data, QObject *parent) :
    QObject(parent),
    _header(header),
    _data(data)
{
}

Frame::~Frame()
{

}

quint8 Frame::header()
{
    return _header;
}

QByteArray & Frame::data()
{
    return _data;
}

char Frame::readChar()
{
    char c = _data.at(0);
    _data.remove(0, 1);
    return c;
}

int Frame::readInt()
{
    char msb = _data.at(0);
    char lsb = _data.at(1);
    _data.remove(0, 2);
    return (msb << 8) + lsb;
}

QString Frame::readString()
{
    int len = readInt();
    QString s(_data.left(len));
    _data.remove(0, len);
    return s;
}

void Frame::writeInt(int i)
{
    _data.append(MSB(i));
    _data.append(LSB(i));
}

void Frame::writeString(const QString &string)
{
    writeInt(string.size());
    _data.append(string);
}

void Frame::writeChar(char c)
{
    _data.append(c);
}

void Frame::writeRawData(const QByteArray &data)
{
    _data.append(data);
}

void Frame::write(QDataStream &stream)
{
    QByteArray lenbuf;
    stream << (quint8)_header;
    if(_data.size() == 0) {
        stream << (quint8)0;
        return;
    }
    qDebug("_data.size: %d", _data.size());
    encodeLength(lenbuf, _data.size());
    stream.writeRawData(lenbuf.data(), lenbuf.size());
    stream.writeRawData(_data.data(), _data.size());
}

void Frame::encodeLength(QByteArray &lenbuf, int length)
{
    char d;
    do {
        d = length % 128;
        length /= 128;
        if (length > 0) {
            d |= 0x80;
        }
        lenbuf.append(d);
    } while (length > 0);
}

} // namespace QMQTT
<|endoftext|>