<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 <memory>
#include <thread>

//#include "Utils.hpp"
#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"

#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"

//The custom optimizations
#include "mtac/VariableCleaner.hpp"
#include "mtac/RemoveEmptyFunctions.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/ConcatReduction.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/RemoveAssign.hpp"
#include "mtac/RemoveMultipleAssign.hpp"
#include "mtac/MathPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

using namespace eddic;

namespace {

static const unsigned int MAX_THREADS = 2;
static const bool DebugPerf = false;

template<typename Visitor>
bool apply_to_all(std::shared_ptr<mtac::Function> function){
    Visitor visitor;

    for(auto& block : function->getBasicBlocks()){
        visit_each(visitor, block->statements);
    }

    return visitor.optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks_two_pass(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visitor.pass = mtac::Pass::DATA_MINING;

        visit_each(visitor, block->statements);

        visitor.pass = mtac::Pass::OPTIMIZE;

        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Problem>
bool data_flow_optimization(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    Problem problem;

    auto results = mtac::data_flow(function, problem);

    //Once the data-flow problem is fixed, statements can be optimized
    for(auto& block : function->getBasicBlocks()){
        for(auto& statement : block->statements){
            optimized |= problem.optimize(statement, results);
        }
    }

    return optimized;
}

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

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

    return b;
}

}

void optimize_function(std::shared_ptr<mtac::Function> function, std::shared_ptr<StringPool> pool){
    if(option_defined("dev")){
        std::cout << "Start optimizations on " << function->getName() << std::endl;

        print(function);
    }

    bool optimized;
    do {
        optimized = false;

        optimized |= debug("Aritmetic Identities", apply_to_all<mtac::ArithmeticIdentities>(function), function);
        optimized |= debug("Reduce in Strength", apply_to_all<mtac::ReduceInStrength>(function), function);
        optimized |= debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);

        optimized |= debug("Constant propagation", data_flow_optimization<mtac::ConstantPropagationProblem>(function), function);
        optimized |= debug("Offset Constant Propagation", data_flow_optimization<mtac::OffsetConstantPropagationProblem>(function), function);

        //If there was optimizations here, better to try again before perfoming common subexpression
        if(optimized){
            continue;
        }

        optimized |= debug("Common Subexpression Elimination", data_flow_optimization<mtac::CommonSubexpressionElimination>(function), function);

        optimized |= debug("Math Propagation", apply_to_basic_blocks_two_pass<mtac::MathPropagation>(function), function);

        optimized |= debug("Dead-Code Elimination", mtac::dead_code_elimination(function), function);

        optimized |= debug("Optimize Branches", optimize_branches(function), function);
        optimized |= debug("Optimize Concat", optimize_concat(function, pool), function);
        optimized |= debug("Remove dead basic block", remove_dead_basic_blocks(function), function);
        optimized |= debug("Remove needless jumps", remove_needless_jumps(function), function);
    } while (optimized);

    //Remove variables that are not used after optimizations
    clean_variables(function);
}

void basic_optimize_function(std::shared_ptr<mtac::Function> function){
    if(option_defined("dev")){
        std::cout << "Start basic optimizations on " << function->getName() << std::endl;

        print(function);
    }

    debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);

    /*//Liveness debugging
    mtac::LiveVariableAnalysisProblem problem;
    auto results = mtac::data_flow(function, problem);

    for(auto& block : function->getBasicBlocks()){
        auto it = block->statements.begin();
        auto end = block->statements.end();

        while(it != end){
            auto statement = *it;

            mtac::Printer printer;
            printer.printStatement(statement);
            std::cout << "OUT{";
            for(auto& var : results->OUT_S[statement].values()){
                std::cout << var->name() << ", ";
            }
            std::cout << "}" << std::endl;
            std::cout << "IN{";
            for(auto& var : results->IN_S[statement].values()){
                std::cout << var->name() << ", ";
            }
            std::cout << "}" << std::endl;

            ++it;
        }
    }*/
}

void optimize_all_functions(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool){
    PerfsTimer timer("Whole optimizations");

    auto& functions = program->functions;

    //Find a better heuristic to configure the number of threads
    std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

    if(option_defined("dev")){
        threads = 1;
    }

    std::vector<std::thread> pool;
    for(std::size_t tid = 0; tid < threads; ++tid){
        pool.push_back(std::thread([tid, threads, &string_pool, &functions](){
            std::size_t i = tid;

            while(i < functions.size()){
                optimize_function(functions[i], string_pool);

                i += threads;
            }
        }));
    }

    //Wait for all the threads to finish
    std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
}

void mtac::Optimizer::optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool) const {
    bool optimized = false;

    do{
        optimize_all_functions(program, string_pool);

        optimized = mtac::remove_empty_functions(program);
    } while(optimized);
}

void mtac::Optimizer::basic_optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> /*string_pool*/) const {
    PerfsTimer timer("Whole basic optimizations");

    auto& functions = program->functions;

    //Find a better heuristic to configure the number of threads
    std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

    if(option_defined("dev")){
        threads = 1;
    }

    std::vector<std::thread> pool;
    for(std::size_t tid = 0; tid < threads; ++tid){
        pool.push_back(std::thread([tid, threads, &functions](){
            std::size_t i = tid;

            while(i < functions.size()){
                basic_optimize_function(functions[i]);

                i += threads;
            }
        }));
    }

    //Wait for all the threads to finish
    std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
}
<commit_msg>Cleanup<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 <memory>
#include <thread>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"

#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"

//The custom optimizations
#include "mtac/VariableCleaner.hpp"
#include "mtac/RemoveEmptyFunctions.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/ConcatReduction.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/RemoveAssign.hpp"
#include "mtac/RemoveMultipleAssign.hpp"
#include "mtac/MathPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

using namespace eddic;

namespace {

static const unsigned int MAX_THREADS = 2;
static const bool DebugPerf = false;

template<typename Visitor>
bool apply_to_all(std::shared_ptr<mtac::Function> function){
    Visitor visitor;

    for(auto& block : function->getBasicBlocks()){
        visit_each(visitor, block->statements);
    }

    return visitor.optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks_two_pass(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visitor.pass = mtac::Pass::DATA_MINING;

        visit_each(visitor, block->statements);

        visitor.pass = mtac::Pass::OPTIMIZE;

        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Problem>
bool data_flow_optimization(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    Problem problem;

    auto results = mtac::data_flow(function, problem);

    //Once the data-flow problem is fixed, statements can be optimized
    for(auto& block : function->getBasicBlocks()){
        for(auto& statement : block->statements){
            optimized |= problem.optimize(statement, results);
        }
    }

    return optimized;
}

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

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

    return b;
}

}

void optimize_function(std::shared_ptr<mtac::Function> function, std::shared_ptr<StringPool> pool){
    if(option_defined("dev")){
        std::cout << "Start optimizations on " << function->getName() << std::endl;

        print(function);
    }

    bool optimized;
    do {
        optimized = false;

        optimized |= debug("Aritmetic Identities", apply_to_all<mtac::ArithmeticIdentities>(function), function);
        optimized |= debug("Reduce in Strength", apply_to_all<mtac::ReduceInStrength>(function), function);
        optimized |= debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);

        optimized |= debug("Constant propagation", data_flow_optimization<mtac::ConstantPropagationProblem>(function), function);
        optimized |= debug("Offset Constant Propagation", data_flow_optimization<mtac::OffsetConstantPropagationProblem>(function), function);

        //If there was optimizations here, better to try again before perfoming common subexpression
        if(optimized){
            continue;
        }

        optimized |= debug("Common Subexpression Elimination", data_flow_optimization<mtac::CommonSubexpressionElimination>(function), function);

        optimized |= debug("Math Propagation", apply_to_basic_blocks_two_pass<mtac::MathPropagation>(function), function);

        optimized |= debug("Dead-Code Elimination", mtac::dead_code_elimination(function), function);

        optimized |= debug("Optimize Branches", optimize_branches(function), function);
        optimized |= debug("Optimize Concat", optimize_concat(function, pool), function);
        optimized |= debug("Remove dead basic block", remove_dead_basic_blocks(function), function);
        optimized |= debug("Remove needless jumps", remove_needless_jumps(function), function);
    } while (optimized);

    //Remove variables that are not used after optimizations
    clean_variables(function);
}

void basic_optimize_function(std::shared_ptr<mtac::Function> function){
    if(option_defined("dev")){
        std::cout << "Start basic optimizations on " << function->getName() << std::endl;

        print(function);
    }

    debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);

    /*//Liveness debugging
    mtac::LiveVariableAnalysisProblem problem;
    auto results = mtac::data_flow(function, problem);

    for(auto& block : function->getBasicBlocks()){
        auto it = block->statements.begin();
        auto end = block->statements.end();

        while(it != end){
            auto statement = *it;

            mtac::Printer printer;
            printer.printStatement(statement);
            std::cout << "OUT{";
            for(auto& var : results->OUT_S[statement].values()){
                std::cout << var->name() << ", ";
            }
            std::cout << "}" << std::endl;
            std::cout << "IN{";
            for(auto& var : results->IN_S[statement].values()){
                std::cout << var->name() << ", ";
            }
            std::cout << "}" << std::endl;

            ++it;
        }
    }*/
}

void optimize_all_functions(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool){
    PerfsTimer timer("Whole optimizations");

    auto& functions = program->functions;

    //Find a better heuristic to configure the number of threads
    std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

    if(option_defined("dev")){
        threads = 1;
    }

    std::vector<std::thread> pool;
    for(std::size_t tid = 0; tid < threads; ++tid){
        pool.push_back(std::thread([tid, threads, &string_pool, &functions](){
            std::size_t i = tid;

            while(i < functions.size()){
                optimize_function(functions[i], string_pool);

                i += threads;
            }
        }));
    }

    //Wait for all the threads to finish
    std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
}

void mtac::Optimizer::optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool) const {
    bool optimized = false;

    do{
        optimize_all_functions(program, string_pool);

        optimized = mtac::remove_empty_functions(program);
    } while(optimized);
}

void mtac::Optimizer::basic_optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> /*string_pool*/) const {
    PerfsTimer timer("Whole basic optimizations");

    auto& functions = program->functions;

    //Find a better heuristic to configure the number of threads
    std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

    if(option_defined("dev")){
        threads = 1;
    }

    std::vector<std::thread> pool;
    for(std::size_t tid = 0; tid < threads; ++tid){
        pool.push_back(std::thread([tid, threads, &functions](){
            std::size_t i = tid;

            while(i < functions.size()){
                basic_optimize_function(functions[i]);

                i += threads;
            }
        }));
    }

    //Wait for all the threads to finish
    std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
}
<|endoftext|>


<commit_before>#include <terrian_config.hpp>
#include <lua/lua.hpp>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

//For stringifying preprocessor values
#define xstr(s) str(s)
#define str(s) #s
#define concat(first, second) first second

int l_ink(lua_State *L) {
	int x;
	if (lua_gettop(L) >= 0) {
		x = (int)lua_tonumber(L, -1);
		lua_pushnumber(L, x + 1);
	}
	return 1;
}

struct Dog
{
	int age;
	int height;
	const char* breed;
};

static int newDog(lua_State* l) {
	Dog* bella = (Dog*)lua_newuserdata(l, sizeof(Dog));
	bella->age = 12;
	bella->height = 1;

	return 1;
}

static int DogGetAge(lua_State* l) {
	Dog *bella = (Dog*)lua_touserdata(l, 1);
	luaL_argcheck(l, bella != NULL, 1, "Dog expected");
	lua_pushinteger(l, bella->age);
	return 1;
}

static const struct luaL_Reg doglib[] = {
	{"new", newDog},
	{"age", DogGetAge},
	{NULL, NULL}

};

static void PrintLuaTypeAt(lua_State* l, const int i) {

	int type = lua_type(l, i);
	printf("Stack index %d\t\t", lua_absindex(l, i));
	switch (type) {

	case LUA_TNIL:
		printf("Value is nil.\n");
		break;
	case LUA_TBOOLEAN:
		printf("Value is boolean: %d\n", (int)lua_toboolean(l, i));
		break;
	case LUA_TLIGHTUSERDATA:
		printf("Value is light user data (just a pointer)\n");
		break;
	case LUA_TNUMBER:
		printf("Value is a number of: %d\n", (int)lua_tonumber(l, i));
		break;
	case LUA_TSTRING:
		printf("Value is a string of: %s\n", lua_tostring(l, i));
		break;
	case LUA_TTABLE:
		printf("Value is a table.\n");
		break;
	case LUA_TFUNCTION:
		printf("Value is a function.\n");
		break;
	case LUA_TUSERDATA:
		printf("Value is userdata\n");
		break;
	default:
		printf("Value is not printable\n");
		break;
	}
}

static void PrintTableAt(lua_State* l, int index){
	int tableIndex = lua_absindex(l, index);
	if (lua_istable(l, tableIndex) == 1) {
		lua_pushnil(l);               // pushes the first key (which is nil for whatever reason) onto the stack
		while (lua_next(l, tableIndex) != 0) { // key(-1) is replaced by the next key(-1) in table(tableIndex)
			PrintLuaTypeAt(l, -2);
			PrintLuaTypeAt(l, -1);
			lua_pop(l, 1);               // remove value(-1), now key on top at(-1)
			//leaves key(-1) at top for next interation
		}
	}
	else {
		fprintf(stderr, "Object at %d on stack is not a table\n", tableIndex);
	}

}
static void PrintTable(lua_State* l) {
	PrintTableAt(l, -1);
}

//From Programming in Lua 3rd Edition
static void stackDump (lua_State *L) {
	int i;
	int top = lua_gettop(L); /* depth of the stack */
	for (i = 1; i <= top; i++) { /* repeat for each level */
		int t = lua_type(L, i);
		switch (t) {
			case LUA_TSTRING: { /* strings */
								  printf("'%s'", lua_tostring(L, i));
								  break;
							  }
			case LUA_TBOOLEAN: { /* booleans */
								   printf(lua_toboolean(L, i) ? "true" : "false");
								   break;
							   }
			case LUA_TNUMBER: { /* numbers */
								  printf("%g", lua_tonumber(L, i));
								  break;
							  }
			default: { /* other values */
						 printf("%s", lua_typename(L, t));
						 break;
					 }
		}
		printf(" "); /* put a separator */
	}
	printf("\n"); /* end the listing */
}

static void PrintGlobalTable(lua_State* l) {
	lua_pushglobaltable(l);
	printf("Global table\n");
	PrintTable(l);
	lua_pop(l, 1);
}

static void CopyTableAtTo(lua_State* l, int t, int newTableIndex){
	t = lua_absindex(l, t);
	newTableIndex = lua_absindex(l, newTableIndex);
	printf("t is %d, newTableIndex is %d\n", t, newTableIndex);
	lua_pushnil(l);
	while(lua_next(l, t) != 0){
		lua_pushvalue(l,-2); //copies key to top so lua_next is happy
		//swaps value and key on top of stack.
		//Above function adds a value onto stack so -2 is now value
		lua_insert(l,-2);
		//Set the value in the new stack. Consuming the top value and key
		lua_settable(l,newTableIndex);

	}

}

void LuaHook(lua_State *l, lua_Debug *ar) {
	if(lua_getstack(l,0,ar) == 0){
		fprintf(stderr, "%s\n", "Error calling get stack");
	}
	if(lua_getinfo(l, "Snlf", ar) == 0){
		fprintf(stderr, "%s\n", "Error calling get info");
	}else{
		printf("Event %d\tLine %d\t\t",ar->event, ar->currentline);
		if(strcmp(ar->namewhat, "global") == 0){
			printf("Type: %s\tName %s",ar->namewhat,ar->name);
		}
		printf("%s\n","");
	}

}

int main(int argc, char* argv[]) {
	lua_State *l;
	l = luaL_newstate();
	luaL_openlibs(l);
	//PrintGlobalTable(l);
	luaL_newlib(l, doglib);
	lua_setglobal(l, "dog");

	lua_Debug ar;

	lua_newtable(l);
	lua_pushglobaltable(l);
	int globalTableIndex = lua_absindex(l,-2);
	CopyTableAtTo(l, -1, -2);

	//lua_sethook(l, LuaHook, LUA_MASKLINE | LUA_MASKCALL | LUA_MASKRET, 0);
//	lua_sethook(l, LuaHook, LUA_MASKLINE | LUA_MASKCALL, 0);
	if (luaL_loadfile(l, concat(xstr(SCRIPTS_DIR), "/test.lua")) != 0) {
		fprintf(stderr, "lua couldn't parse '%s': %s.\n", "test.lua", lua_tostring(l, -1));
	}
	else {
		lua_pcall(l, 0, 0, 0);
		lua_getglobal(l, "uupdate");
		stackDump(l);
		if (lua_pcall(l, 0, 0, 0) != 0) {
			fprintf(stderr, "lua couldn't call update in '%s': %s.\n", "test.lua", lua_tostring(l, -1));
		}
	}

	int i = 0;
	char in = 'e';//(char)getchar();

	while (in != 'e') {

		for (i = 0; i < 1; i++) {

			int indexStart = lua_gettop(l);
			//lua_rawseti(l, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
			if (luaL_loadfile(l, concat(xstr(SCRIPTS_DIR), "/test.lua")) != 0) {
				fprintf(stderr, "lua couldn't parse '%s': %s.\n", "test.lua", lua_tostring(l, -1));
			}
			else {
				PrintTableAt(l, globalTableIndex);
				lua_pcall(l, 0, 0, 0);
				lua_getglobal(l, "update");
				if (lua_pcall(l, 0, 0, 0) != 0) {
					fprintf(stderr, "lua couldn't call update in '%s': %s.\n", "test.lua", lua_tostring(l, -1));
				}
				lua_getglobal(l, "createDog");
				if (lua_pcall(l, 0, 0, 0) != 0) {
					fprintf(stderr, "lua couldn't call createDog in '%s': %s.\n", "test.lua", lua_tostring(l, -1));
				}
				lua_pop(l, lua_gettop(l) - indexStart);
			}
			/*
			if (luaL_loadfile(l, concat(xstr(SCRIPTS_DIR), "/hello.lua")) != 0) {
				fprintf(stderr, "lua couldn't parse '%s': %s.\n", "hello.lua", lua_tostring(l, -1));
			}
			else {
				lua_pcall(l, 0, 0, 0);
				lua_getglobal(l, "update");
				if (lua_pcall(l, 0, 0, 0) != 0) {
					fprintf(stderr, "lua couldn't call update in '%s': %s.\n", "hello.lua", lua_tostring(l, -1));
				}
				lua_pop(l, lua_gettop(l));
			}
			//PrintGlobalTable(l);
			//calls the loaded code
			lua_pcall(l, 0, 1, 0);
			if(lua_isnumber(l, lua_gettop(l)) != 0){
				lua_Integer returnCode = lua_tointeger(l, lua_gettop(l));
				printf("Return code %d\n", (int)returnCode);
			}
			lua_getglobal(l, "add");
			lua_pushnumber(l, 10);
			lua_pushnumber(l, 20);
			if(lua_pcall(l,2,1,0) != 0){
				fprintf(stderr, "Couldn't call add error:\t%s\n", lua_tostring(l, -1));
			}else{
				int result = (int)lua_tonumber(l, -1);
				printf("Add result of 10 + 20 = %d\n", result);
				//clear the result
				lua_pop(l,1);
			}
			lua_getglobal(l, "createDog");
			if (lua_pcall(l, 0, 0, 0) != 0) {
				fprintf(stderr, "Couldn't call function error:\t%s\n", lua_tostring(l, -1));
			}
			*/

		}
		in = (char)getchar();
	}
	return 0;
}
<commit_msg>Added metatable/OO lua access example<commit_after>#include <terrian_config.hpp>
#include <lua/lua.hpp>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//For stringifying preprocessor values
#define xstr(s) str(s)
#define str(s) #s
#define concat(first, second) first second

int l_ink(lua_State *L) {
	int x;
	if (lua_gettop(L) >= 0) {
		x = (int)lua_tonumber(L, -1);
		lua_pushnumber(L, x + 1);
	}
	return 1;
}

struct Dog
{
	int age;
	int height;
	const char* breed;
};

static int newDog(lua_State* l) {
	Dog* bella = (Dog*)lua_newuserdata(l, sizeof(Dog));
	luaL_getmetatable(l, "Dog");
	    // assert(lua_istable(L, -1)) if you're paranoid
	lua_setmetatable(l, -2);
	srand((unsigned int)time(NULL));
	bella->age = rand() % 100;
	bella->height = 1;

	return 1;
}

static int DogGetAge(lua_State* l) {
	Dog *bella = (Dog*)lua_touserdata(l, 1);
	luaL_argcheck(l, bella != NULL, 1, "Dog expected");
	lua_pushinteger(l, bella->age);
	return 1;
}

static const struct luaL_Reg doglib[] = {
	{"new", newDog},
	{NULL, NULL}

};
static const struct luaL_Reg doglibMember[] = {
	{"age", DogGetAge},
	{NULL, NULL}

};

static void PrintLuaTypeAt(lua_State* l, const int i) {

	int type = lua_type(l, i);
	printf("Stack index %d\t\t", lua_absindex(l, i));
	switch (type) {

	case LUA_TNIL:
		printf("Value is nil.\n");
		break;
	case LUA_TBOOLEAN:
		printf("Value is boolean: %d\n", (int)lua_toboolean(l, i));
		break;
	case LUA_TLIGHTUSERDATA:
		printf("Value is light user data (just a pointer)\n");
		break;
	case LUA_TNUMBER:
		printf("Value is a number of: %d\n", (int)lua_tonumber(l, i));
		break;
	case LUA_TSTRING:
		printf("Value is a string of: %s\n", lua_tostring(l, i));
		break;
	case LUA_TTABLE:
		printf("Value is a table.\n");
		break;
	case LUA_TFUNCTION:
		printf("Value is a function.\n");
		break;
	case LUA_TUSERDATA:
		printf("Value is userdata\n");
		break;
	default:
		printf("Value is not printable\n");
		break;
	}
}

static void PrintTableAt(lua_State* l, int index){
	int tableIndex = lua_absindex(l, index);
	if (lua_istable(l, tableIndex) == 1) {
		lua_pushnil(l);               // pushes the first key (which is nil for whatever reason) onto the stack
		while (lua_next(l, tableIndex) != 0) { // key(-1) is replaced by the next key(-1) in table(tableIndex)
			PrintLuaTypeAt(l, -2);
			PrintLuaTypeAt(l, -1);
			lua_pop(l, 1);               // remove value(-1), now key on top at(-1)
			//leaves key(-1) at top for next interation
		}
	}
	else {
		fprintf(stderr, "Object at %d on stack is not a table\n", tableIndex);
	}

}
static void PrintTable(lua_State* l) {
	PrintTableAt(l, -1);
}

//From Programming in Lua 3rd Edition
static void stackDump (lua_State *L) {
	int i;
	int top = lua_gettop(L); /* depth of the stack */
	for (i = 1; i <= top; i++) { /* repeat for each level */
		int t = lua_type(L, i);
		switch (t) {
			case LUA_TSTRING: { /* strings */
								  printf("'%s'", lua_tostring(L, i));
								  break;
							  }
			case LUA_TBOOLEAN: { /* booleans */
								   printf(lua_toboolean(L, i) ? "true" : "false");
								   break;
							   }
			case LUA_TNUMBER: { /* numbers */
								  printf("%g", lua_tonumber(L, i));
								  break;
							  }
			default: { /* other values */
						 printf("%s", lua_typename(L, t));
						 break;
					 }
		}
		printf(" "); /* put a separator */
	}
	printf("\n"); /* end the listing */
}

static void PrintGlobalTable(lua_State* l) {
	lua_pushglobaltable(l);
	printf("Global table\n");
	PrintTable(l);
	lua_pop(l, 1);
}

static void CopyTableAtTo(lua_State* l, int t, int newTableIndex){
	t = lua_absindex(l, t);
	newTableIndex = lua_absindex(l, newTableIndex);
	printf("t is %d, newTableIndex is %d\n", t, newTableIndex);
	lua_pushnil(l);
	while(lua_next(l, t) != 0){
		lua_pushvalue(l,-2); //copies key to top so lua_next is happy
		//swaps value and key on top of stack.
		//Above function adds a value onto stack so -2 is now value
		lua_insert(l,-2);
		//Set the value in the new stack. Consuming the top value and key
		lua_settable(l,newTableIndex);

	}

}

void LuaHook(lua_State *l, lua_Debug *ar) {
	if(lua_getstack(l,0,ar) == 0){
		fprintf(stderr, "%s\n", "Error calling get stack");
	}
	if(lua_getinfo(l, "Snlf", ar) == 0){
		fprintf(stderr, "%s\n", "Error calling get info");
	}else{
		printf("Event %d\tLine %d\t\t",ar->event, ar->currentline);
		if(strcmp(ar->namewhat, "global") == 0){
			printf("Type: %s\tName %s",ar->namewhat,ar->name);
		}
		printf("%s\n","");
	}

}

int main(int argc, char* argv[]) {
	lua_State *l;
	l = luaL_newstate();
	luaL_openlibs(l);
	//PrintGlobalTable(l);
	//Creates a metatable and registers in Lua's registery
	luaL_newmetatable(l, "Dog");
	//Sets functions against the meta table
	luaL_setfuncs(l, doglibMember, 0);
	//Adds __index 	to the meta table so we can use functions against
	/*
	 * Lua uses : syntax which causes an index lookup
	 * It uses the following function name to look in the meta table
	 * By adding __index we ensure that it always looks at its self
	 *
	 * I.E __index becomes the metatable itself which contains our functions
	*/
	lua_setfield(l, -1, "__index");
	luaL_getmetatable(l, "Dog");
	PrintTable(l);
	luaL_newlib(l, doglib);
	lua_setglobal(l, "dog");

	lua_Debug ar;

	lua_newtable(l);
	lua_pushglobaltable(l);
	int globalTableIndex = lua_absindex(l,-2);
	CopyTableAtTo(l, -1, -2);

	//lua_sethook(l, LuaHook, LUA_MASKLINE | LUA_MASKCALL | LUA_MASKRET, 0);
//	lua_sethook(l, LuaHook, LUA_MASKLINE | LUA_MASKCALL, 0);
	if (luaL_loadfile(l, concat(xstr(SCRIPTS_DIR), "/test.lua")) != 0) {
		fprintf(stderr, "lua couldn't parse '%s': %s.\n", "test.lua", lua_tostring(l, -1));
	}
	else {
		lua_pcall(l, 0, 0, 0);
		lua_getglobal(l, "update");
		if (lua_pcall(l, 0, 0, 0) != 0) {
			fprintf(stderr, "lua couldn't call update in '%s': %s.\n", "test.lua", lua_tostring(l, -1));
		}
	}

	int i = 0;
	char in = 'e';//(char)getchar();

	while (in != 'e') {

		for (i = 0; i < 1; i++) {

			int indexStart = lua_gettop(l);
			//lua_rawseti(l, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
			if (luaL_loadfile(l, concat(xstr(SCRIPTS_DIR), "/test.lua")) != 0) {
				fprintf(stderr, "lua couldn't parse '%s': %s.\n", "test.lua", lua_tostring(l, -1));
			}
			else {
				PrintTableAt(l, globalTableIndex);
				lua_pcall(l, 0, 0, 0);
				lua_getglobal(l, "update");
				if (lua_pcall(l, 0, 0, 0) != 0) {
					fprintf(stderr, "lua couldn't call update in '%s': %s.\n", "test.lua", lua_tostring(l, -1));
				}
				lua_getglobal(l, "createDog");
				if (lua_pcall(l, 0, 0, 0) != 0) {
					fprintf(stderr, "lua couldn't call createDog in '%s': %s.\n", "test.lua", lua_tostring(l, -1));
				}
				lua_pop(l, lua_gettop(l) - indexStart);
			}
			/*
			if (luaL_loadfile(l, concat(xstr(SCRIPTS_DIR), "/hello.lua")) != 0) {
				fprintf(stderr, "lua couldn't parse '%s': %s.\n", "hello.lua", lua_tostring(l, -1));
			}
			else {
				lua_pcall(l, 0, 0, 0);
				lua_getglobal(l, "update");
				if (lua_pcall(l, 0, 0, 0) != 0) {
					fprintf(stderr, "lua couldn't call update in '%s': %s.\n", "hello.lua", lua_tostring(l, -1));
				}
				lua_pop(l, lua_gettop(l));
			}
			//PrintGlobalTable(l);
			//calls the loaded code
			lua_pcall(l, 0, 1, 0);
			if(lua_isnumber(l, lua_gettop(l)) != 0){
				lua_Integer returnCode = lua_tointeger(l, lua_gettop(l));
				printf("Return code %d\n", (int)returnCode);
			}
			lua_getglobal(l, "add");
			lua_pushnumber(l, 10);
			lua_pushnumber(l, 20);
			if(lua_pcall(l,2,1,0) != 0){
				fprintf(stderr, "Couldn't call add error:\t%s\n", lua_tostring(l, -1));
			}else{
				int result = (int)lua_tonumber(l, -1);
				printf("Add result of 10 + 20 = %d\n", result);
				//clear the result
				lua_pop(l,1);
			}
			lua_getglobal(l, "createDog");
			if (lua_pcall(l, 0, 0, 0) != 0) {
				fprintf(stderr, "Couldn't call function error:\t%s\n", lua_tostring(l, -1));
			}
			*/

		}
		in = (char)getchar();
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#ifdef Q_OS_ANDROID
#include "zmc/NotificationClient.h"
#include "zmc/Notification.h"
#include "zmc/android/AndroidUtils.h"
#endif // Q_OS_ANDROID
#include "zmc/ScreenHelper.h"
#include "zmc/QMLRefresh.h"
#include "zmc/Macros.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    zmc::ScreenHelper screenHelper;
    engine.rootContext()->setContextProperty("SH", &screenHelper);

#ifdef Q_OS_ANDROID
    qmlRegisterType<zmc::NotificationClient>("NotificationClient", 1, 0, "NotificationClient");
    qmlRegisterType<zmc::Notification>("NotificationClient", 1, 0, "Notification");
    qmlRegisterType<zmc::AndroidUtils>("qutils.AndroidUtils", 1, 0, "AndroidUtils");
#endif // Q_OS_ANDROID

#if defined(QT_DEBUG) && defined(Q_OS_DESKTOP)
    zmc::QMLRefresh manager(&engine);
    manager.setMainQMLFile("file:///E:/Development/SourceTree/GitHub/qutils/qutils_demo/qml/main.qml");
    engine.rootContext()->setContextProperty("QM", &manager);
    engine.rootContext()->setContextProperty("QML_DEBUG", QVariant::fromValue<bool>(true));
    engine.rootContext()->setContextProperty("Q_OS_DESKTOP", QVariant::fromValue<int>(1));
    engine.load(QUrl("file:///E:/Development/SourceTree/GitHub/qutils/qutils_demo/qml/main.qml"));
#else
    engine.rootContext()->setContextProperty("QM", nullptr);
    engine.rootContext()->setContextProperty("QML_DEBUG", QVariant::fromValue<bool>(false));
    engine.rootContext()->setContextProperty("Q_OS_DESKTOP", QVariant::fromValue<int>(0));
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
#endif // QT_DEBUG

    return app.exec();
}
<commit_msg>Fix include paths<commit_after>#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#ifdef Q_OS_ANDROID
#include "qutils/NotificationClient.h"
#include "qutils/Notification.h"
#include "qutils/android/AndroidUtils.h"
#endif // Q_OS_ANDROID
#include "qutils/ScreenHelper.h"
#include "qutils/QMLRefresh.h"
#include "qutils/Macros.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    zmc::ScreenHelper screenHelper;
    engine.rootContext()->setContextProperty("SH", &screenHelper);

#ifdef Q_OS_ANDROID
    qmlRegisterType<zmc::NotificationClient>("NotificationClient", 1, 0, "NotificationClient");
    qmlRegisterType<zmc::Notification>("NotificationClient", 1, 0, "Notification");
    qmlRegisterType<zmc::AndroidUtils>("qutils.AndroidUtils", 1, 0, "AndroidUtils");
#endif // Q_OS_ANDROID

#if defined(QT_DEBUG) && defined(Q_OS_DESKTOP)
    zmc::QMLRefresh manager(&engine);
    manager.setMainQMLFile("file:///E:/Development/SourceTree/GitHub/qutils/qutils_demo/qml/main.qml");
    engine.rootContext()->setContextProperty("QM", &manager);
    engine.rootContext()->setContextProperty("QML_DEBUG", QVariant::fromValue<bool>(true));
    engine.rootContext()->setContextProperty("Q_OS_DESKTOP", QVariant::fromValue<int>(1));
    engine.load(QUrl("file:///E:/Development/SourceTree/GitHub/qutils/qutils_demo/qml/main.qml"));
#else
    engine.rootContext()->setContextProperty("QM", nullptr);
    engine.rootContext()->setContextProperty("QML_DEBUG", QVariant::fromValue<bool>(false));
    engine.rootContext()->setContextProperty("Q_OS_DESKTOP", QVariant::fromValue<int>(0));
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
#endif // QT_DEBUG

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


<commit_before>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Nathan Binkert
 */

#include <Python.h>
#include <signal.h>

#include <iostream>
#include <string>

#include "base/cprintf.hh"
#include "base/misc.hh"
#include "config/pythonhome.hh"
#include "python/swig/init.hh"
#include "sim/async.hh"
#include "sim/host.hh"
#include "sim/core.hh"

using namespace std;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_statdump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_statdump = true;
    async_statreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    ccprintf(cerr, "Program aborted at cycle %d\n", curTick);
}

int
main(int argc, char **argv)
{
    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    Py_SetProgramName(argv[0]);

    // default path to m5 python code is the currently executing
    // file... Python ZipImporter will find embedded zip archive.
    // The M5_ARCHIVE environment variable can be used to override this.
    char *m5_archive = getenv("M5_ARCHIVE");
    string pythonpath = m5_archive ? m5_archive : argv[0];

    char *oldpath = getenv("PYTHONPATH");
    if (oldpath != NULL) {
        pythonpath += ":";
        pythonpath += oldpath;
    }

    if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1)
        fatal("setenv: %s\n", strerror(errno));

    char *python_home = getenv("PYTHONHOME");
    if (!python_home)
        python_home = PYTHONHOME;
    Py_SetPythonHome(python_home);

    // initialize embedded Python interpreter
    Py_Initialize();
    PySys_SetArgv(argc, argv);

    // initialize SWIG modules
    init_swig();

    PyRun_SimpleString("import m5.main");
    PyRun_SimpleString("m5.main.main()");

    // clean up Python intepreter.
    Py_Finalize();
}
<commit_msg>main: return an an exit code of 1 when we exit due to a python exception. This requires us to not use PyRun_SimpleString, but PyRun_String since the latter actually returns a result<commit_after>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Nathan Binkert
 */

#include <Python.h>
#include <signal.h>

#include <iostream>
#include <string>

#include "base/cprintf.hh"
#include "base/misc.hh"
#include "config/pythonhome.hh"
#include "python/swig/init.hh"
#include "sim/async.hh"
#include "sim/host.hh"
#include "sim/core.hh"

using namespace std;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_statdump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_statdump = true;
    async_statreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    ccprintf(cerr, "Program aborted at cycle %d\n", curTick);
}

int
python_main()
{
    PyObject *module;
    PyObject *dict;
    PyObject *result;

    module = PyImport_AddModule("__main__");
    if (module == NULL)
        fatal("Could not import __main__");

    dict = PyModule_GetDict(module);

    result = PyRun_String("import m5.main", Py_file_input, dict, dict);
    if (!result) {
        PyErr_Print();
        return 1;
    }
    Py_DECREF(result);

    result = PyRun_String("m5.main.main()", Py_file_input, dict, dict);
    if (!result) {
        PyErr_Print();
        return 1;
    }
    Py_DECREF(result);

    if (Py_FlushLine())
        PyErr_Clear();

    return 0;
}

int
main(int argc, char **argv)
{
    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    Py_SetProgramName(argv[0]);

    // default path to m5 python code is the currently executing
    // file... Python ZipImporter will find embedded zip archive.
    // The M5_ARCHIVE environment variable can be used to override this.
    char *m5_archive = getenv("M5_ARCHIVE");
    string pythonpath = m5_archive ? m5_archive : argv[0];

    char *oldpath = getenv("PYTHONPATH");
    if (oldpath != NULL) {
        pythonpath += ":";
        pythonpath += oldpath;
    }

    if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1)
        fatal("setenv: %s\n", strerror(errno));

    char *python_home = getenv("PYTHONHOME");
    if (!python_home)
        python_home = PYTHONHOME;
    Py_SetPythonHome(python_home);

    // initialize embedded Python interpreter
    Py_Initialize();
    PySys_SetArgv(argc, argv);

    // initialize SWIG modules
    init_swig();

    int ret = python_main();

    // clean up Python intepreter.
    Py_Finalize();

    return ret;
}
<|endoftext|>


<commit_before>//
// (c) 2014 Raphael Bialon <Raphael.Bialon@hhu.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
//

#include "SqliteDatabaseHandler.h"
#include "DatabaseHandler.h"
#include "TbusQueueControl.h"
#include "ModuleAccess.h"
#include "TbusQueueDatarateValue.h"
#include "TbusQueueDelayValue.h"

Define_Module(TbusQueueControl);

/**
 * Empty constructor.
 */
TbusQueueControl::TbusQueueControl() {}

/**
 * Get references to the modules' queues and the global database handler and coordinate converter.
 */
void TbusQueueControl::initialize() {
	// Get references to "our" queues
	cdrq = ModuleAccess<TbusCDRQ>("cdrq").get();
	crrq = ModuleAccess<TbusCRRQ>("crrq").get();
	crsq = ModuleAccess<TbusCRSQ>("crsq").get();
	cdsq = ModuleAccess<TbusCDSQ>("cdsq").get();

	dbHandler = DatabaseHandler::getInstance<SqliteDatabaseHandler>();
	converter = TbusCoordinateConverter::getInstance();
}

/**
 * Translates the given coordinates into latitute/longitude.
 * Then retrieves the belonging datarate, droprate and delay values from the database Handler.
 * Then the new values are updated on the belonging queue.
 * @see TbusCoordinateConverter::translate(const Coord&)
 * @see DatabaseHandler::getUploadDatarate(const Coord&)
 * @see DatabaseHandler::getDownloadDatarate(const Coord&)
 * @see DatabaseHandler::getUploadDelay(const Coord&)
 * @see DatabaseHandler::getDownloadDelay(const Coord&)
 * @param newCoords The new node position
 */
void TbusQueueControl::updateQueues(const Coord& newCoords) {
	// Act like this is part of our PHY layer
	Enter_Method_Silent();

	EV << "TbusQueueControl updating queues for coordinates " << newCoords << endl;

	Coord translated = converter->translate(&newCoords);

	TbusQueueDatarateValue* sendDatarate = dbHandler->getUploadDatarate(translated);
	TbusQueueDatarateValue* receiveDatarate = dbHandler->getDownloadDatarate(translated);
	TbusQueueDelayValue* sendDelay = dbHandler->getUploadDelay(translated);
	TbusQueueDelayValue* receiveDelay = dbHandler->getDownloadDelay(translated);

	std::cout << "sda:" << sendDatarate->datarate << " rda:" << receiveDatarate->datarate << " sde:" << sendDelay->delay << " rde:" << receiveDelay->delay << std::endl;

	cdrq->updateValue(receiveDelay);
	crrq->updateValue(receiveDatarate);
	crsq->updateValue(sendDatarate);
	cdsq->updateValue(sendDelay);
}
<commit_msg>Silenced debug output in QueueControl<commit_after>//
// (c) 2014 Raphael Bialon <Raphael.Bialon@hhu.de>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
//

#include "SqliteDatabaseHandler.h"
#include "DatabaseHandler.h"
#include "TbusQueueControl.h"
#include "ModuleAccess.h"
#include "TbusQueueDatarateValue.h"
#include "TbusQueueDelayValue.h"

Define_Module(TbusQueueControl);

/**
 * Empty constructor.
 */
TbusQueueControl::TbusQueueControl() {}

/**
 * Get references to the modules' queues and the global database handler and coordinate converter.
 */
void TbusQueueControl::initialize() {
	// Get references to "our" queues
	cdrq = ModuleAccess<TbusCDRQ>("cdrq").get();
	crrq = ModuleAccess<TbusCRRQ>("crrq").get();
	crsq = ModuleAccess<TbusCRSQ>("crsq").get();
	cdsq = ModuleAccess<TbusCDSQ>("cdsq").get();

	dbHandler = DatabaseHandler::getInstance<SqliteDatabaseHandler>();
	converter = TbusCoordinateConverter::getInstance();
}

/**
 * Translates the given coordinates into latitute/longitude.
 * Then retrieves the belonging datarate, droprate and delay values from the database Handler.
 * Then the new values are updated on the belonging queue.
 * @see TbusCoordinateConverter::translate(const Coord&)
 * @see DatabaseHandler::getUploadDatarate(const Coord&)
 * @see DatabaseHandler::getDownloadDatarate(const Coord&)
 * @see DatabaseHandler::getUploadDelay(const Coord&)
 * @see DatabaseHandler::getDownloadDelay(const Coord&)
 * @param newCoords The new node position
 */
void TbusQueueControl::updateQueues(const Coord& newCoords) {
	// Act like this is part of our PHY layer
	Enter_Method_Silent();

	EV << "TbusQueueControl updating queues for coordinates " << newCoords << endl;

	Coord translated = converter->translate(&newCoords);

	TbusQueueDatarateValue* sendDatarate = dbHandler->getUploadDatarate(translated);
	TbusQueueDatarateValue* receiveDatarate = dbHandler->getDownloadDatarate(translated);
	TbusQueueDelayValue* sendDelay = dbHandler->getUploadDelay(translated);
	TbusQueueDelayValue* receiveDelay = dbHandler->getDownloadDelay(translated);

	//std::cout << "sda:" << sendDatarate->datarate << " rda:" << receiveDatarate->datarate << " sde:" << sendDelay->delay << " rde:" << receiveDelay->delay << std::endl;

	cdrq->updateValue(receiveDelay);
	crrq->updateValue(receiveDatarate);
	crsq->updateValue(sendDatarate);
	cdsq->updateValue(sendDelay);
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "executefilter.h"

#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/variablemanager.h>

#include <QMessageBox>

using namespace Core;
using namespace Locator;
using namespace Locator::Internal;

ExecuteFilter::ExecuteFilter()
{
    setId("Execute custom commands");
    setDisplayName(tr("Execute Custom Commands"));
    setShortcutString(QString(QLatin1Char('!')));
    setIncludedByDefault(false);

    m_process = new Utils::QtcProcess(this);
    m_process->setEnvironment(Utils::Environment::systemEnvironment());
    connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this,
            SLOT(finished(int,QProcess::ExitStatus)));
    connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
    connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));

    m_runTimer.setSingleShot(true);
    connect(&m_runTimer, SIGNAL(timeout()), this, SLOT(runHeadCommand()));
}

QList<FilterEntry> ExecuteFilter::matchesFor(QFutureInterface<Locator::FilterEntry> &future,
                                             const QString &entry)
{
    QList<FilterEntry> value;
    if (!entry.isEmpty()) // avoid empty entry
        value.append(FilterEntry(this, entry, QVariant()));
    QList<FilterEntry> others;
    const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
    foreach (const QString &i, m_commandHistory) {
        if (future.isCanceled())
            break;
        if (i == entry) // avoid repeated entry
            continue;
        if (i.startsWith(entry, caseSensitivityForPrefix))
            value.append(FilterEntry(this, i, QVariant()));
        else
            others.append(FilterEntry(this, i, QVariant()));
    }
    value.append(others);
    return value;
}

void ExecuteFilter::accept(FilterEntry selection) const
{
    ExecuteFilter *p = const_cast<ExecuteFilter *>(this);

    const QString value = selection.displayName.trimmed();
    const int index = m_commandHistory.indexOf(value);
    if (index != -1 && index != 0)
        p->m_commandHistory.removeAt(index);
    if (index != 0)
        p->m_commandHistory.prepend(value);

    bool found;
    QString workingDirectory = Core::VariableManager::value("CurrentDocument:Path", &found);
    if (!found || workingDirectory.isEmpty())
        workingDirectory = Core::VariableManager::value("CurrentProject:Path", &found);

    ExecuteData d;
    d.workingDirectory = workingDirectory;
    const int pos = value.indexOf(QLatin1Char(' '));
    if (pos == -1) {
        d.executable = value;
    } else {
        d.executable = value.left(pos);
        d.arguments = value.right(value.length() - pos - 1);
    }

    if (m_process->state() != QProcess::NotRunning) {
        const QString info(tr("Previous command is still running ('%1').\nDo you want to kill it?")
                           .arg(p->headCommand()));
        int r = QMessageBox::question(0, tr("Kill Previous Process?"), info,
                                      QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
                                      QMessageBox::Yes);
        if (r == QMessageBox::Yes)
            m_process->kill();
        if (r != QMessageBox::Cancel)
            p->m_taskQueue.enqueue(d);
        return;
    }

    p->m_taskQueue.enqueue(d);
    p->runHeadCommand();
}

void ExecuteFilter::finished(int exitCode, QProcess::ExitStatus status)
{
    const QString commandName = headCommand();
    QString message;
    if (status == QProcess::NormalExit && exitCode == 0)
        message = tr("Command '%1' finished").arg(commandName);
    else
        message = tr("Command '%1' failed").arg(commandName);
    MessageManager::write(message);

    m_taskQueue.dequeue();
    if (!m_taskQueue.isEmpty())
        m_runTimer.start(500);
}

void ExecuteFilter::readStandardOutput()
{
    QByteArray data = m_process->readAllStandardOutput();
    MessageManager::write(QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(),
                                                                  &m_stdoutState));
}

void ExecuteFilter::readStandardError()
{
    static QTextCodec::ConverterState state;
    QByteArray data = m_process->readAllStandardError();
    MessageManager::write(QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(),
                                                                  &m_stderrState));
}

void ExecuteFilter::runHeadCommand()
{
    if (!m_taskQueue.isEmpty()) {
        const ExecuteData &d = m_taskQueue.head();
        const QString fullPath = Utils::Environment::systemEnvironment().searchInPath(d.executable);
        if (fullPath.isEmpty()) {
            MessageManager::write(tr("Could not find executable for '%1'").arg(d.executable));
            m_taskQueue.dequeue();
            runHeadCommand();
            return;
        }
        MessageManager::write(tr("Starting command '%1'").arg(headCommand()));
        m_process->setWorkingDirectory(d.workingDirectory);
        m_process->setCommand(fullPath, d.arguments);
        m_process->start();
        m_process->closeWriteChannel();
    }
}

QString ExecuteFilter::headCommand() const
{
    if (m_taskQueue.isEmpty())
        return QString();
    const ExecuteData &data = m_taskQueue.head();
    if (data.arguments.isEmpty())
        return data.executable;
    else
        return data.executable + QLatin1Char(' ') + data.arguments;
}
<commit_msg>Locator: fix UI text punctuation<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "executefilter.h"

#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/variablemanager.h>

#include <QMessageBox>

using namespace Core;
using namespace Locator;
using namespace Locator::Internal;

ExecuteFilter::ExecuteFilter()
{
    setId("Execute custom commands");
    setDisplayName(tr("Execute Custom Commands"));
    setShortcutString(QString(QLatin1Char('!')));
    setIncludedByDefault(false);

    m_process = new Utils::QtcProcess(this);
    m_process->setEnvironment(Utils::Environment::systemEnvironment());
    connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this,
            SLOT(finished(int,QProcess::ExitStatus)));
    connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
    connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));

    m_runTimer.setSingleShot(true);
    connect(&m_runTimer, SIGNAL(timeout()), this, SLOT(runHeadCommand()));
}

QList<FilterEntry> ExecuteFilter::matchesFor(QFutureInterface<Locator::FilterEntry> &future,
                                             const QString &entry)
{
    QList<FilterEntry> value;
    if (!entry.isEmpty()) // avoid empty entry
        value.append(FilterEntry(this, entry, QVariant()));
    QList<FilterEntry> others;
    const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
    foreach (const QString &i, m_commandHistory) {
        if (future.isCanceled())
            break;
        if (i == entry) // avoid repeated entry
            continue;
        if (i.startsWith(entry, caseSensitivityForPrefix))
            value.append(FilterEntry(this, i, QVariant()));
        else
            others.append(FilterEntry(this, i, QVariant()));
    }
    value.append(others);
    return value;
}

void ExecuteFilter::accept(FilterEntry selection) const
{
    ExecuteFilter *p = const_cast<ExecuteFilter *>(this);

    const QString value = selection.displayName.trimmed();
    const int index = m_commandHistory.indexOf(value);
    if (index != -1 && index != 0)
        p->m_commandHistory.removeAt(index);
    if (index != 0)
        p->m_commandHistory.prepend(value);

    bool found;
    QString workingDirectory = Core::VariableManager::value("CurrentDocument:Path", &found);
    if (!found || workingDirectory.isEmpty())
        workingDirectory = Core::VariableManager::value("CurrentProject:Path", &found);

    ExecuteData d;
    d.workingDirectory = workingDirectory;
    const int pos = value.indexOf(QLatin1Char(' '));
    if (pos == -1) {
        d.executable = value;
    } else {
        d.executable = value.left(pos);
        d.arguments = value.right(value.length() - pos - 1);
    }

    if (m_process->state() != QProcess::NotRunning) {
        const QString info(tr("Previous command is still running ('%1').\nDo you want to kill it?")
                           .arg(p->headCommand()));
        int r = QMessageBox::question(0, tr("Kill Previous Process?"), info,
                                      QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
                                      QMessageBox::Yes);
        if (r == QMessageBox::Yes)
            m_process->kill();
        if (r != QMessageBox::Cancel)
            p->m_taskQueue.enqueue(d);
        return;
    }

    p->m_taskQueue.enqueue(d);
    p->runHeadCommand();
}

void ExecuteFilter::finished(int exitCode, QProcess::ExitStatus status)
{
    const QString commandName = headCommand();
    QString message;
    if (status == QProcess::NormalExit && exitCode == 0)
        message = tr("Command '%1' finished.").arg(commandName);
    else
        message = tr("Command '%1' failed.").arg(commandName);
    MessageManager::write(message);

    m_taskQueue.dequeue();
    if (!m_taskQueue.isEmpty())
        m_runTimer.start(500);
}

void ExecuteFilter::readStandardOutput()
{
    QByteArray data = m_process->readAllStandardOutput();
    MessageManager::write(QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(),
                                                                  &m_stdoutState));
}

void ExecuteFilter::readStandardError()
{
    static QTextCodec::ConverterState state;
    QByteArray data = m_process->readAllStandardError();
    MessageManager::write(QTextCodec::codecForLocale()->toUnicode(data.constData(), data.size(),
                                                                  &m_stderrState));
}

void ExecuteFilter::runHeadCommand()
{
    if (!m_taskQueue.isEmpty()) {
        const ExecuteData &d = m_taskQueue.head();
        const QString fullPath = Utils::Environment::systemEnvironment().searchInPath(d.executable);
        if (fullPath.isEmpty()) {
            MessageManager::write(tr("Could not find executable for '%1'").arg(d.executable));
            m_taskQueue.dequeue();
            runHeadCommand();
            return;
        }
        MessageManager::write(tr("Starting command '%1'").arg(headCommand()));
        m_process->setWorkingDirectory(d.workingDirectory);
        m_process->setCommand(fullPath, d.arguments);
        m_process->start();
        m_process->closeWriteChannel();
    }
}

QString ExecuteFilter::headCommand() const
{
    if (m_taskQueue.isEmpty())
        return QString();
    const ExecuteData &data = m_taskQueue.head();
    if (data.arguments.isEmpty())
        return data.executable;
    else
        return data.executable + QLatin1Char(' ') + data.arguments;
}
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */

/*
 * Copyright (C) 2016 ScyllaDB.
 */
#include <vector>
#include <algorithm>

#include <seastar/core/do_with.hh>
#include <seastar/testing/test_case.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/do_with.hh>
#include <seastar/net/dns.hh>
#include <seastar/net/inet_address.hh>

using namespace seastar;
using namespace seastar::net;

static const sstring seastar_name = "seastar.io";

static future<> test_resolve(dns_resolver::options opts) {
    auto d = ::make_lw_shared<dns_resolver>(std::move(opts));
    return d->get_host_by_name(seastar_name, inet_address::family::INET).then([d](hostent e) {
        return d->get_host_by_addr(e.addr_list.front()).then([d, a = e.addr_list.front()](hostent e) {
            return d->get_host_by_name(e.names.front(), inet_address::family::INET).then([a](hostent e) {
                BOOST_REQUIRE(std::count(e.addr_list.begin(), e.addr_list.end(), a));
            });
        });
    }).finally([d]{
        return d->close();
    });
}

static future<> test_bad_name(dns_resolver::options opts) {
    auto d = ::make_lw_shared<dns_resolver>(std::move(opts));
    return d->get_host_by_name("apa.ninja.gnu", inet_address::family::INET).then_wrapped([d](future<hostent> f) {
        try {
            f.get();
            BOOST_FAIL("should not succeed");
        } catch (...) {
            // ok.
        }
    }).finally([d]{
        return d->close();
    });
}

SEASTAR_TEST_CASE(test_resolve_udp) {
    return test_resolve(dns_resolver::options());
}

SEASTAR_TEST_CASE(test_bad_name_udp) {
    return test_bad_name(dns_resolver::options());
}

SEASTAR_TEST_CASE(test_timeout_udp) {
    dns_resolver::options opts;
    opts.servers = std::vector<inet_address>({ inet_address("1.2.3.4") }); // not a server
    opts.udp_port = 29953; // not a dns port
    opts.timeout = std::chrono::milliseconds(500);

    auto d = ::make_lw_shared<dns_resolver>(engine().net(), opts);
    return d->get_host_by_name(seastar_name, inet_address::family::INET).then_wrapped([d](future<hostent> f) {
        try {
            f.get();
            BOOST_FAIL("should not succeed");
        } catch (...) {
            // ok.
        }
    }).finally([d]{
        return d->close();
    });
}

// NOTE: cannot really test timeout in TCP mode, because seastar sockets do not support
// connect with timeout -> cannot complete connect future in dns::do_connect in reasonable
// time.

// But we can test for connection refused working as expected.
SEASTAR_TEST_CASE(test_connection_refused_tcp) {
    dns_resolver::options opts;
    opts.servers = std::vector<inet_address>({ inet_address("127.0.0.1") });
    opts.use_tcp_query = true;
    opts.tcp_port = 29953; // not a dns port

    auto d = ::make_lw_shared<dns_resolver>(engine().net(), opts);
    return d->get_host_by_name(seastar_name, inet_address::family::INET).then_wrapped([d](future<hostent> f) {
        try {
            f.get();
            BOOST_FAIL("should not succeed");
        } catch (...) {
            // ok.
        }
    }).finally([d]{
        return d->close();
    });
}

SEASTAR_TEST_CASE(test_resolve_tcp) {
    dns_resolver::options opts;
    opts.use_tcp_query = true;
    return test_resolve(opts);
}

SEASTAR_TEST_CASE(test_bad_name_tcp) {
    dns_resolver::options opts;
    opts.use_tcp_query = true;
    return test_bad_name(opts);
}

static const sstring imaps_service = "imaps";
static const sstring gmail_domain = "gmail.com";

static future<> test_srv() {
    auto d = ::make_lw_shared<dns_resolver>();
    return d->get_srv_records(dns_resolver::srv_proto::tcp,
                              imaps_service,
                              gmail_domain).then([d](dns_resolver::srv_records records) {
        BOOST_REQUIRE(!records.empty());
        for (auto& record : records) {
            // record.target should end with "gmail.com"
            BOOST_REQUIRE_GT(record.target.size(), gmail_domain.size());
            BOOST_REQUIRE_EQUAL(record.target.compare(record.target.size() - gmail_domain.size(),
                                                      gmail_domain.size(),
                                                      gmail_domain),
                                0);
        }
    }).finally([d]{
        return d->close();
    });
}

SEASTAR_TEST_CASE(test_srv_tcp) {
    return test_srv();
}
<commit_msg>dns_test: Add test for overlapping/simulatneous queries (both tcp+udp)<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */

/*
 * Copyright (C) 2016 ScyllaDB.
 */
#include <vector>
#include <algorithm>

#include <seastar/core/do_with.hh>
#include <seastar/testing/test_case.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/do_with.hh>
#include <seastar/core/when_all.hh>
#include <seastar/net/dns.hh>
#include <seastar/net/inet_address.hh>

using namespace seastar;
using namespace seastar::net;

static const sstring seastar_name = "seastar.io";

static future<> test_resolve(dns_resolver::options opts) {
    auto d = ::make_lw_shared<dns_resolver>(std::move(opts));
    return d->get_host_by_name(seastar_name, inet_address::family::INET).then([d](hostent e) {
        return d->get_host_by_addr(e.addr_list.front()).then([d, a = e.addr_list.front()](hostent e) {
            return d->get_host_by_name(e.names.front(), inet_address::family::INET).then([a](hostent e) {
                BOOST_REQUIRE(std::count(e.addr_list.begin(), e.addr_list.end(), a));
            });
        });
    }).finally([d]{
        return d->close();
    });
}

static future<> test_bad_name(dns_resolver::options opts) {
    auto d = ::make_lw_shared<dns_resolver>(std::move(opts));
    return d->get_host_by_name("apa.ninja.gnu", inet_address::family::INET).then_wrapped([d](future<hostent> f) {
        try {
            f.get();
            BOOST_FAIL("should not succeed");
        } catch (...) {
            // ok.
        }
    }).finally([d]{
        return d->close();
    });
}

SEASTAR_TEST_CASE(test_resolve_udp) {
    return test_resolve(dns_resolver::options());
}

SEASTAR_TEST_CASE(test_bad_name_udp) {
    return test_bad_name(dns_resolver::options());
}

SEASTAR_TEST_CASE(test_timeout_udp) {
    dns_resolver::options opts;
    opts.servers = std::vector<inet_address>({ inet_address("1.2.3.4") }); // not a server
    opts.udp_port = 29953; // not a dns port
    opts.timeout = std::chrono::milliseconds(500);

    auto d = ::make_lw_shared<dns_resolver>(engine().net(), opts);
    return d->get_host_by_name(seastar_name, inet_address::family::INET).then_wrapped([d](future<hostent> f) {
        try {
            f.get();
            BOOST_FAIL("should not succeed");
        } catch (...) {
            // ok.
        }
    }).finally([d]{
        return d->close();
    });
}

// NOTE: cannot really test timeout in TCP mode, because seastar sockets do not support
// connect with timeout -> cannot complete connect future in dns::do_connect in reasonable
// time.

// But we can test for connection refused working as expected.
SEASTAR_TEST_CASE(test_connection_refused_tcp) {
    dns_resolver::options opts;
    opts.servers = std::vector<inet_address>({ inet_address("127.0.0.1") });
    opts.use_tcp_query = true;
    opts.tcp_port = 29953; // not a dns port

    auto d = ::make_lw_shared<dns_resolver>(engine().net(), opts);
    return d->get_host_by_name(seastar_name, inet_address::family::INET).then_wrapped([d](future<hostent> f) {
        try {
            f.get();
            BOOST_FAIL("should not succeed");
        } catch (...) {
            // ok.
        }
    }).finally([d]{
        return d->close();
    });
}

SEASTAR_TEST_CASE(test_resolve_tcp) {
    dns_resolver::options opts;
    opts.use_tcp_query = true;
    return test_resolve(opts);
}

SEASTAR_TEST_CASE(test_bad_name_tcp) {
    dns_resolver::options opts;
    opts.use_tcp_query = true;
    return test_bad_name(opts);
}

static const sstring imaps_service = "imaps";
static const sstring gmail_domain = "gmail.com";

static future<> test_srv() {
    auto d = ::make_lw_shared<dns_resolver>();
    return d->get_srv_records(dns_resolver::srv_proto::tcp,
                              imaps_service,
                              gmail_domain).then([d](dns_resolver::srv_records records) {
        BOOST_REQUIRE(!records.empty());
        for (auto& record : records) {
            // record.target should end with "gmail.com"
            BOOST_REQUIRE_GT(record.target.size(), gmail_domain.size());
            BOOST_REQUIRE_EQUAL(record.target.compare(record.target.size() - gmail_domain.size(),
                                                      gmail_domain.size(),
                                                      gmail_domain),
                                0);
        }
    }).finally([d]{
        return d->close();
    });
}

SEASTAR_TEST_CASE(test_srv_tcp) {
    return test_srv();
}

SEASTAR_TEST_CASE(test_parallel_resolve_name) {
    dns_resolver::options opts;
    opts.use_tcp_query = true;

    auto d = ::make_lw_shared<dns_resolver>(std::move(opts));
    return when_all(
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com")
    ).finally([d](auto&&...) {}).discard_result();
}

SEASTAR_TEST_CASE(test_parallel_resolve_name_udp) {
    dns_resolver::options opts;

    auto d = ::make_lw_shared<dns_resolver>(std::move(opts));
    return when_all(
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com"),
        d->resolve_name("www.google.com")
    ).finally([d](auto&...) {}).discard_result();
}
<|endoftext|>


<commit_before>#include "MorphScene.h"
#include <gl/glew.h>
#include <gl/GL.h>

#include "FrameBufferObjects.h"

#include <Model.h>
#include "GeometryObject.h"
#include <Texture2D.h>

#include "settings.h"
#include "input.h"

#include <Shader.h>
#include <ShaderProgram.h>
#include "Camera.h"
#include "Player.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>

#define BUFFER_OFFSET(i) ((char *)nullptr + (i))

MorphScene::MorphScene() {
	state = 0;

	diffuse = new Texture2D("Resources/Models/rock01/diffuse.tga");
	normal = new Texture2D("Resources/Models/rock01/normal.tga");
	specular = new Texture2D("Resources/Models/rock01/specular.tga");

	vertexShader = new Shader("morph_vertex.glsl", GL_VERTEX_SHADER);
	geometryShader = new Shader("default_geometry.glsl", GL_GEOMETRY_SHADER);
	fragmentShader = new Shader("normalspecularmap_fragment.glsl", GL_FRAGMENT_SHADER);
	shaderProgram = new ShaderProgram({ vertexShader, geometryShader, fragmentShader });

	deferredVertexShader = new Shader("deferred_vertex.glsl", GL_VERTEX_SHADER);
	deferredFragmentShader = new Shader("deferred_fragment.glsl", GL_FRAGMENT_SHADER);
	deferredShaderProgram = new ShaderProgram({ deferredVertexShader, deferredFragmentShader });

	geometry = new Model("Resources/Models/Rock.bin");

	geometryObject = new GeometryObject(geometry);
	geometryObject->setScale(0.01f, 0.01f, 0.01f);

	targetPositions = new glm::vec3[geometryObject->geometry()->vertexCount()];
	glm::mat4 targetScaleRotation = glm::scale(glm::vec3(0.1f, 0.1f, 0.1f))*glm::rotate(90.f, glm::vec3(0.f, 1.f, 0.f));

	for (unsigned int i = 0; i < geometryObject->geometry()->vertexCount(); i++) {
		targetPositions[i] = glm::vec3(targetScaleRotation*glm::vec4(geometryObject->geometry()->vertices()[i].position, 1.f));
	}

	GLuint targetBuffer;
	// Generate target buffer
	glGenBuffers(1, &targetBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, targetBuffer);
	glBufferData(GL_ARRAY_BUFFER, geometryObject->geometry()->vertexCount() * sizeof(glm::vec3), targetPositions, GL_STATIC_DRAW);

	// Target vertex layout (adds to geometry objects current layout)
	glBindVertexArray(geometryObject->geometry()->vertexArray());
	glEnableVertexAttribArray(4);
	glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);

	glBindVertexArray(0);
	direction = true;
	t = 0;
	player = new Player();
	player->setMovementSpeed(2.0f);
	multipleRenderTargets = new FrameBufferObjects(deferredShaderProgram, settings::displayWidth(), settings::displayHeight());
}

MorphScene::~MorphScene() {
	delete diffuse;
	delete normal;
	delete specular;

	delete multipleRenderTargets;
	delete deferredShaderProgram;
	delete shaderProgram;

	delete deferredVertexShader;
	delete deferredFragmentShader;
	delete[] targetPositions;

	delete vertexShader;
	delete geometryShader;
	delete fragmentShader;

	delete geometryObject;
	delete geometry;
	delete player;
}

Scene::SceneEnd* MorphScene::update(double time) {
	player->update(time);

	if (input::triggered(input::CHANGE_RENDER_STATE))
		state = !state;

	return nullptr;
}

void MorphScene::render(int width, int height) {
	multipleRenderTargets->bindForWriting();

	glViewport(0, 0, width, height);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	shaderProgram->use();

	// Texture unit 0 is for base images.
	glUniform1i(shaderProgram->uniformLocation("baseImage"), 0);
	// Texture unit 1 is for normal map.
	glUniform1i(shaderProgram->uniformLocation("normalMap"), 1);
	// Texture unit 0 is for specular map.
	glUniform1i(shaderProgram->uniformLocation("specularMap"), 2);

	glBindVertexArray(geometryObject->geometry()->vertexArray());

	if (direction == true) {
		if (t < 1.f)
			t += 0.0001f*time;
		else
			direction = false;
	}
	else if (direction == false){
		if (t > 0.f)
			t -= 0.0001f;
		else
			direction = true;
	}
	//T value, used for interpolation
	glUniform1f(shaderProgram->uniformLocation("tValue"), t);

	// Base image texture
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, diffuse->textureID());

	// Normal map
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, normal->textureID());

	// Specular map
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, specular->textureID());

	// Model matrix, unique for each model.
	glm::mat4 model = geometryObject->modelMatrix();

	// Send the matrices to the shader.
	glm::mat4 view = player->camera()->view();
	glm::mat4 MV = view * model;
	glm::mat4 N = glm::transpose(glm::inverse(MV));

	glUniformMatrix4fv(shaderProgram->uniformLocation("modelMatrix"), 1, GL_FALSE, &model[0][0]);
	glUniformMatrix4fv(shaderProgram->uniformLocation("viewMatrix"), 1, GL_FALSE, &view[0][0]);
	glUniformMatrix3fv(shaderProgram->uniformLocation("normalMatrix"), 1, GL_FALSE, &glm::mat3(N)[0][0]);
	glUniformMatrix4fv(shaderProgram->uniformLocation("projectionMatrix"), 1, GL_FALSE, &player->camera()->projection(width, height)[0][0]);

	// Draw the triangles
	glDrawElements(GL_TRIANGLES, geometryObject->geometry()->indexCount(), GL_UNSIGNED_INT, (void*)0);

	if (state == 1) {
		multipleRenderTargets->showTextures(width, height);
	}
	else if (state == 0) {
		multipleRenderTargets->render(player->camera(), width, height);
	}
}<commit_msg>Moved morph algorithm from render to update.<commit_after>#include "MorphScene.h"
#include <gl/glew.h>
#include <gl/GL.h>

#include "FrameBufferObjects.h"

#include <Model.h>
#include "GeometryObject.h"
#include <Texture2D.h>

#include "settings.h"
#include "input.h"

#include <Shader.h>
#include <ShaderProgram.h>
#include "Camera.h"
#include "Player.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>

#define BUFFER_OFFSET(i) ((char *)nullptr + (i))

MorphScene::MorphScene() {
	state = 0;

	diffuse = new Texture2D("Resources/Models/rock01/diffuse.tga");
	normal = new Texture2D("Resources/Models/rock01/normal.tga");
	specular = new Texture2D("Resources/Models/rock01/specular.tga");

	vertexShader = new Shader("morph_vertex.glsl", GL_VERTEX_SHADER);
	geometryShader = new Shader("default_geometry.glsl", GL_GEOMETRY_SHADER);
	fragmentShader = new Shader("normalspecularmap_fragment.glsl", GL_FRAGMENT_SHADER);
	shaderProgram = new ShaderProgram({ vertexShader, geometryShader, fragmentShader });

	deferredVertexShader = new Shader("deferred_vertex.glsl", GL_VERTEX_SHADER);
	deferredFragmentShader = new Shader("deferred_fragment.glsl", GL_FRAGMENT_SHADER);
	deferredShaderProgram = new ShaderProgram({ deferredVertexShader, deferredFragmentShader });

	geometry = new Model("Resources/Models/Rock.bin");

	geometryObject = new GeometryObject(geometry);
	geometryObject->setScale(0.01f, 0.01f, 0.01f);

	targetPositions = new glm::vec3[geometryObject->geometry()->vertexCount()];
	glm::mat4 targetScaleRotation = glm::scale(glm::vec3(0.1f, 0.1f, 0.1f))*glm::rotate(90.f, glm::vec3(0.f, 1.f, 0.f));

	for (unsigned int i = 0; i < geometryObject->geometry()->vertexCount(); i++) {
		targetPositions[i] = glm::vec3(targetScaleRotation*glm::vec4(geometryObject->geometry()->vertices()[i].position, 1.f));
	}

	GLuint targetBuffer;
	// Generate target buffer
	glGenBuffers(1, &targetBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, targetBuffer);
	glBufferData(GL_ARRAY_BUFFER, geometryObject->geometry()->vertexCount() * sizeof(glm::vec3), targetPositions, GL_STATIC_DRAW);

	// Target vertex layout (adds to geometry objects current layout)
	glBindVertexArray(geometryObject->geometry()->vertexArray());
	glEnableVertexAttribArray(4);
	glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0);

	glBindVertexArray(0);
	direction = true;
	t = 0;
	player = new Player();
	player->setMovementSpeed(2.0f);
	multipleRenderTargets = new FrameBufferObjects(deferredShaderProgram, settings::displayWidth(), settings::displayHeight());
}

MorphScene::~MorphScene() {
	delete diffuse;
	delete normal;
	delete specular;

	delete multipleRenderTargets;
	delete deferredShaderProgram;
	delete shaderProgram;

	delete deferredVertexShader;
	delete deferredFragmentShader;
	delete[] targetPositions;

	delete vertexShader;
	delete geometryShader;
	delete fragmentShader;

	delete geometryObject;
	delete geometry;
	delete player;
}

Scene::SceneEnd* MorphScene::update(double time) {
	player->update(time);

	if (input::triggered(input::CHANGE_RENDER_STATE))
		state = !state;

	if (direction == true) {
		if (t < 1.f)
			t += 0.3*time;
		else
			direction = false;
	}
	else if (direction == false){
		if (t > 0.f)
			t -= 0.3*time;
		else
			direction = true;
	}

	return nullptr;
}

void MorphScene::render(int width, int height) {
	multipleRenderTargets->bindForWriting();

	glViewport(0, 0, width, height);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	shaderProgram->use();

	// Texture unit 0 is for base images.
	glUniform1i(shaderProgram->uniformLocation("baseImage"), 0);
	// Texture unit 1 is for normal map.
	glUniform1i(shaderProgram->uniformLocation("normalMap"), 1);
	// Texture unit 0 is for specular map.
	glUniform1i(shaderProgram->uniformLocation("specularMap"), 2);

	glBindVertexArray(geometryObject->geometry()->vertexArray());

	//T value, used for interpolation
	glUniform1f(shaderProgram->uniformLocation("tValue"), t);

	// Base image texture
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, diffuse->textureID());

	// Normal map
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, normal->textureID());

	// Specular map
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, specular->textureID());

	// Model matrix, unique for each model.
	glm::mat4 model = geometryObject->modelMatrix();

	// Send the matrices to the shader.
	glm::mat4 view = player->camera()->view();
	glm::mat4 MV = view * model;
	glm::mat4 N = glm::transpose(glm::inverse(MV));

	glUniformMatrix4fv(shaderProgram->uniformLocation("modelMatrix"), 1, GL_FALSE, &model[0][0]);
	glUniformMatrix4fv(shaderProgram->uniformLocation("viewMatrix"), 1, GL_FALSE, &view[0][0]);
	glUniformMatrix3fv(shaderProgram->uniformLocation("normalMatrix"), 1, GL_FALSE, &glm::mat3(N)[0][0]);
	glUniformMatrix4fv(shaderProgram->uniformLocation("projectionMatrix"), 1, GL_FALSE, &player->camera()->projection(width, height)[0][0]);

	// Draw the triangles
	glDrawElements(GL_TRIANGLES, geometryObject->geometry()->indexCount(), GL_UNSIGNED_INT, (void*)0);

	if (state == 1) {
		multipleRenderTargets->showTextures(width, height);
	}
	else if (state == 0) {
		multipleRenderTargets->render(player->camera(), width, height);
	}
}<|endoftext|>