<commit_before>#include "mmcore/CoreInstance.h"
#include "mmcore/MegaMolGraph.h"

#include "mmcore/utility/log/Log.h"
#include "mmcore/utility/log/StreamTarget.h"

#include "AbstractFrontendService.hpp"
#include "FrontendServiceCollection.hpp"
#include "GUI_Service.hpp"
#include "OpenGL_GLFW_Service.hpp"
#include "Lua_Service_Wrapper.hpp"

#include "mmcore/view/AbstractView_EventConsumption.h"

#include <cxxopts.hpp>
#include "mmcore/LuaAPI.h"

// Filesystem
#if defined(_HAS_CXX17) || ((defined(_MSC_VER) && (_MSC_VER > 1916))) // C++2017 or since VS2019
#    include <filesystem>
namespace stdfs = std::filesystem;
#else
// WINDOWS
#    ifdef _WIN32
#        include <filesystem>
namespace stdfs = std::experimental::filesystem;
#    else
// LINUX
#        include <experimental/filesystem>
namespace stdfs = std::experimental::filesystem;
#    endif
#endif

struct CLIConfig {
    std::vector<std::string> project_files;
    std::string lua_host_address = "tcp://127.0.0.1:33333";
};

CLIConfig handle_cli_inputs(int argc, char* argv[]);

bool set_up_graph(megamol::core::MegaMolGraph& graph);

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

    auto config = handle_cli_inputs(argc, argv);

    // setup log
    megamol::core::utility::log::Log::DefaultLog.SetLogFileName(static_cast<const char*>(NULL), false);
    megamol::core::utility::log::Log::DefaultLog.SetLevel(megamol::core::utility::log::Log::LEVEL_ALL);
    megamol::core::utility::log::Log::DefaultLog.SetEchoLevel(megamol::core::utility::log::Log::LEVEL_ALL);
    megamol::core::utility::log::Log::DefaultLog.SetEchoTarget(
        std::make_shared<megamol::core::utility::log::StreamTarget>(
            std::cout, megamol::core::utility::log::Log::LEVEL_ALL));

    megamol::core::CoreInstance core;
    core.Initialise(false); // false makes core not start his own lua service (else we collide on default port)

    const megamol::core::factories::ModuleDescriptionManager& moduleProvider = core.GetModuleDescriptionManager();
    const megamol::core::factories::CallDescriptionManager& callProvider = core.GetCallDescriptionManager();

    megamol::frontend::OpenGL_GLFW_Service gl_service;
    megamol::frontend::OpenGL_GLFW_Service::Config openglConfig;
    openglConfig.windowTitlePrefix = openglConfig.windowTitlePrefix + " ~ Main3000";
    openglConfig.versionMajor = 4;
    openglConfig.versionMinor = 5;
    gl_service.setPriority(1);

    megamol::frontend::GUI_Service gui_service;
    megamol::frontend::GUI_Service::Config guiConfig;
    guiConfig.imgui_api = megamol::frontend::GUI_Service::ImGuiAPI::OPEN_GL;
    guiConfig.core_instance = &core;
    // priority must be higher than priority of gl_service (=1)
    // service callbacks get called in order of priority of the service.
    // postGraphRender() and close() are called in reverse order of priorities.
    gui_service.setPriority(23);

    megamol::core::MegaMolGraph graph(core, moduleProvider, callProvider);

    bool lua_imperative_only = false; // allow mmFlush, mmList* and mmGetParam*
    megamol::core::LuaAPI lua_api(graph, lua_imperative_only);
    megamol::frontend::Lua_Service_Wrapper lua_service_wrapper;
    megamol::frontend::Lua_Service_Wrapper::Config luaConfig;
    luaConfig.lua_api_ptr = &lua_api;
    luaConfig.host_address = config.lua_host_address;
    lua_service_wrapper.setPriority(0);

    // the main loop is organized around services that can 'do something' in different parts of the main loop
    // a service is something that implements the AbstractFrontendService interface from 'megamol\frontend_services\include'
    // a central mechanism that allows services to communicate with each other and with graph modules are _resources_
    // (see ModuleResource in 'megamol\module_resources\include') services may provide resources to the system and they may
    // request resources they need themselves for functioning. think of a resource as a struct (or some type of your
    // choice) that gets wrapped by a helper structure and gets a name attached to it. the fronend makes sure (at least
    // attempts to) to hand each service the resources it requested, or else fail execution of megamol with an error
    // message. resource assignment is done by the name of the resource, so this is a very loose interface based on
    // trust. type safety of resources is ensured in the sense that extracting the wrong type from a ModuleResource will
    // lead to an unhandled bad type cast exception, leading to the shutdown of megamol.
    bool run_megamol = true;
    megamol::frontend::FrontendServiceCollection services;
    services.add(gl_service, &openglConfig);
    services.add(gui_service, &guiConfig);
    services.add(lua_service_wrapper, &luaConfig);

    const bool init_ok = services.init(); // runs init(config_ptr) on all services with provided config sructs

    if (!init_ok) {
        std::cout << "ERROR: some frontend service could not be initialized successfully. abort. " << std::endl;
        services.close();
        return 1;
    }

    // graph is also a resource that may be accessed by services
    // TODO: how to solve const and non-const resources?
    // TODO: graph manipulation during execution of graph modules is problematic, undefined?
    services.getProvidedResources().push_back({"MegaMolGraph", graph});

    // distribute registered resources among registered services.
    const bool resources_ok = services.assignRequestedResources();
    // for each service we call their resource callbacks here:
    //    std::vector<ModuleResource>& getProvidedResources()
    //    std::vector<std::string> getRequestedResourceNames()
    //    void setRequestedResources(std::vector<ModuleResource>& resources)
    if (!resources_ok) {
        std::cout << "ERROR: frontend could not assign requested service resources. abort. " << std::endl;
        run_megamol = false;
    }

    auto module_resources = services.getProvidedResources();
    graph.AddModuleDependencies(module_resources);

    const auto render_next_frame = [&]() -> bool {
        // services: receive inputs (GLFW poll events [keyboard, mouse, window], network, lua)
        services.updateProvidedResources();

        // aka simulation step
        // services: digest new inputs via ModuleResources (GUI digest user inputs, lua digest inputs, network ?)
        // e.g. graph updates, module and call creation via lua and GUI happen here
        services.digestChangedRequestedResources();

        // services tell us wheter we should shut down megamol
        // TODO: service needs to mark intself as shutdown by calling this->setShutdown() during
        // digestChangedRequestedResources()
        if (services.shouldShutdown())
            return false;

        {                              // put this in render function so LUA can call it
            services.preGraphRender(); // e.g. start frame timer, clear render buffers

            graph.RenderNextFrame(); // executes graph views, those digest input events like keyboard/mouse, then render

            services.postGraphRender(); // render GUI, glfw swap buffers, stop frame timer
            // problem: guarantee correct order of pre- and post-render jobs, i.e. render gui before swapping buffers
        }

        services.resetProvidedResources(); // clear buffers holding glfw keyboard+mouse input

        return true;
    };

    // lua can issue rendering of frames
    lua_api.setFlushCallback(render_next_frame);

	if (config.project_files.empty()) {
		const bool graph_ok = set_up_graph(graph); // fill graph with modules and calls
		if (!graph_ok) {
		    std::cout << "ERROR: frontend could not build graph. abort. " << std::endl;
		    run_megamol = false;
		}
    } else {
        // load project files via lua
        for (auto& file : config.project_files) {
		    std::string result;
            if (!lua_api.RunFile(file, result)) {
                std::cout << "Project file \"" << file << "\" did not execute correctly: " << result << std::endl;
		        run_megamol = false;
            }
        }
    }

    while (run_megamol) {
        run_megamol = render_next_frame();
    }

    // close glfw context, network connections, other system resources
    services.close();

    // clean up modules, calls in graph
    // TODO: implement graph destructor

    return 0;
}

CLIConfig handle_cli_inputs(int argc, char* argv[]) {
    CLIConfig config;

    cxxopts::Options options(argv[0], "MegaMol Frontend 3000");

    // parse input project files
    options.positional_help("<additional project files>");
    options.add_options()
        ("project-files", "projects to load", cxxopts::value<std::vector<std::string>>())
        ("host", "address of lua host server, default: "+config.lua_host_address, cxxopts::value<std::string>())
        ;
    options.parse_positional({"project-files"});

    auto parsed_options = options.parse(argc, argv);
    std::string res;

	// verify project files exist in file system
    if (parsed_options.count("project-files")) {
        const auto& v = parsed_options["project-files"].as<std::vector<std::string>>();
        for (const auto& p : v) {
            if (!stdfs::exists(p)) {
                std::cout << "Project file \"" << p << "\" does not exist!" << std::endl;
                std::exit(1);
            }
        }

        config.project_files = v;
    }

    if (parsed_options.count("host")) {
        config.lua_host_address = parsed_options["host"].as<std::string>();
    }

    return config;
}

bool set_up_graph(megamol::core::MegaMolGraph& graph) {
#define check(X) \
    if (!X) return false;

    check(graph.CreateModule("View3D_2", "::view"));
    check(graph.CreateModule("SphereRenderer", "::spheres"));
    check(graph.CreateModule("TestSpheresDataSource", "::datasource"));
    check(graph.CreateCall("CallRender3D_2", "::view::rendering", "::spheres::rendering"));
    check(graph.CreateCall("MultiParticleDataCall", "::spheres::getdata", "::datasource::getData"));

    check(graph.SetGraphEntryPoint("::view", megamol::core::view::get_gl_view_runtime_resources_requests(), megamol::core::view::view_rendering_execution));

    std::string parameter_name("::datasource::numSpheres");
    auto parameterPtr = graph.FindParameter(parameter_name);
    if (parameterPtr) {
        parameterPtr->ParseValue("23");
    } else {
        std::cout << "ERROR: could not find parameter: " << parameter_name << std::endl;
        return false;
    }

    return true;
}
<commit_msg>main3000: option to not load example project<commit_after>#include "mmcore/CoreInstance.h"
#include "mmcore/MegaMolGraph.h"

#include "mmcore/utility/log/Log.h"
#include "mmcore/utility/log/StreamTarget.h"

#include "AbstractFrontendService.hpp"
#include "FrontendServiceCollection.hpp"
#include "GUI_Service.hpp"
#include "OpenGL_GLFW_Service.hpp"
#include "Lua_Service_Wrapper.hpp"

#include "mmcore/view/AbstractView_EventConsumption.h"

#include <cxxopts.hpp>
#include "mmcore/LuaAPI.h"

// Filesystem
#if defined(_HAS_CXX17) || ((defined(_MSC_VER) && (_MSC_VER > 1916))) // C++2017 or since VS2019
#    include <filesystem>
namespace stdfs = std::filesystem;
#else
// WINDOWS
#    ifdef _WIN32
#        include <filesystem>
namespace stdfs = std::experimental::filesystem;
#    else
// LINUX
#        include <experimental/filesystem>
namespace stdfs = std::experimental::filesystem;
#    endif
#endif

struct CLIConfig {
    std::vector<std::string> project_files;
    std::string lua_host_address = "tcp://127.0.0.1:33333";
    bool load_example_project = true;
};

CLIConfig handle_cli_inputs(int argc, char* argv[]);

bool set_up_example_graph(megamol::core::MegaMolGraph& graph);

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

    auto config = handle_cli_inputs(argc, argv);

    // setup log
    megamol::core::utility::log::Log::DefaultLog.SetLogFileName(static_cast<const char*>(NULL), false);
    megamol::core::utility::log::Log::DefaultLog.SetLevel(megamol::core::utility::log::Log::LEVEL_ALL);
    megamol::core::utility::log::Log::DefaultLog.SetEchoLevel(megamol::core::utility::log::Log::LEVEL_ALL);
    megamol::core::utility::log::Log::DefaultLog.SetEchoTarget(
        std::make_shared<megamol::core::utility::log::StreamTarget>(
            std::cout, megamol::core::utility::log::Log::LEVEL_ALL));

    megamol::core::CoreInstance core;
    core.Initialise(false); // false makes core not start his own lua service (else we collide on default port)

    const megamol::core::factories::ModuleDescriptionManager& moduleProvider = core.GetModuleDescriptionManager();
    const megamol::core::factories::CallDescriptionManager& callProvider = core.GetCallDescriptionManager();

    megamol::frontend::OpenGL_GLFW_Service gl_service;
    megamol::frontend::OpenGL_GLFW_Service::Config openglConfig;
    openglConfig.windowTitlePrefix = openglConfig.windowTitlePrefix + " ~ Main3000";
    openglConfig.versionMajor = 4;
    openglConfig.versionMinor = 5;
    gl_service.setPriority(1);

    megamol::frontend::GUI_Service gui_service;
    megamol::frontend::GUI_Service::Config guiConfig;
    guiConfig.imgui_api = megamol::frontend::GUI_Service::ImGuiAPI::OPEN_GL;
    guiConfig.core_instance = &core;
    // priority must be higher than priority of gl_service (=1)
    // service callbacks get called in order of priority of the service.
    // postGraphRender() and close() are called in reverse order of priorities.
    gui_service.setPriority(23);

    megamol::core::MegaMolGraph graph(core, moduleProvider, callProvider);

    bool lua_imperative_only = false; // allow mmFlush, mmList* and mmGetParam*
    megamol::core::LuaAPI lua_api(graph, lua_imperative_only);
    megamol::frontend::Lua_Service_Wrapper lua_service_wrapper;
    megamol::frontend::Lua_Service_Wrapper::Config luaConfig;
    luaConfig.lua_api_ptr = &lua_api;
    luaConfig.host_address = config.lua_host_address;
    lua_service_wrapper.setPriority(0);

    // the main loop is organized around services that can 'do something' in different parts of the main loop
    // a service is something that implements the AbstractFrontendService interface from 'megamol\frontend_services\include'
    // a central mechanism that allows services to communicate with each other and with graph modules are _resources_
    // (see ModuleResource in 'megamol\module_resources\include') services may provide resources to the system and they may
    // request resources they need themselves for functioning. think of a resource as a struct (or some type of your
    // choice) that gets wrapped by a helper structure and gets a name attached to it. the fronend makes sure (at least
    // attempts to) to hand each service the resources it requested, or else fail execution of megamol with an error
    // message. resource assignment is done by the name of the resource, so this is a very loose interface based on
    // trust. type safety of resources is ensured in the sense that extracting the wrong type from a ModuleResource will
    // lead to an unhandled bad type cast exception, leading to the shutdown of megamol.
    bool run_megamol = true;
    megamol::frontend::FrontendServiceCollection services;
    services.add(gl_service, &openglConfig);
    services.add(gui_service, &guiConfig);
    services.add(lua_service_wrapper, &luaConfig);

    const bool init_ok = services.init(); // runs init(config_ptr) on all services with provided config sructs

    if (!init_ok) {
        std::cout << "ERROR: some frontend service could not be initialized successfully. abort. " << std::endl;
        services.close();
        return 1;
    }

    // graph is also a resource that may be accessed by services
    // TODO: how to solve const and non-const resources?
    // TODO: graph manipulation during execution of graph modules is problematic, undefined?
    services.getProvidedResources().push_back({"MegaMolGraph", graph});

    // distribute registered resources among registered services.
    const bool resources_ok = services.assignRequestedResources();
    // for each service we call their resource callbacks here:
    //    std::vector<ModuleResource>& getProvidedResources()
    //    std::vector<std::string> getRequestedResourceNames()
    //    void setRequestedResources(std::vector<ModuleResource>& resources)
    if (!resources_ok) {
        std::cout << "ERROR: frontend could not assign requested service resources. abort. " << std::endl;
        run_megamol = false;
    }

    auto module_resources = services.getProvidedResources();
    graph.AddModuleDependencies(module_resources);

    const auto render_next_frame = [&]() -> bool {
        // services: receive inputs (GLFW poll events [keyboard, mouse, window], network, lua)
        services.updateProvidedResources();

        // aka simulation step
        // services: digest new inputs via ModuleResources (GUI digest user inputs, lua digest inputs, network ?)
        // e.g. graph updates, module and call creation via lua and GUI happen here
        services.digestChangedRequestedResources();

        // services tell us wheter we should shut down megamol
        // TODO: service needs to mark intself as shutdown by calling this->setShutdown() during
        // digestChangedRequestedResources()
        if (services.shouldShutdown())
            return false;

        {                              // put this in render function so LUA can call it
            services.preGraphRender(); // e.g. start frame timer, clear render buffers

            graph.RenderNextFrame(); // executes graph views, those digest input events like keyboard/mouse, then render

            services.postGraphRender(); // render GUI, glfw swap buffers, stop frame timer
            // problem: guarantee correct order of pre- and post-render jobs, i.e. render gui before swapping buffers
        }

        services.resetProvidedResources(); // clear buffers holding glfw keyboard+mouse input

        return true;
    };

    // lua can issue rendering of frames
    lua_api.setFlushCallback(render_next_frame);

    // load project files via lua
    for (auto& file : config.project_files) {
	    std::string result;
        if (!lua_api.RunFile(file, result)) {
            std::cout << "Project file \"" << file << "\" did not execute correctly: " << result << std::endl;
	        run_megamol = false;
        }
    }
	if (config.load_example_project && config.project_files.empty()) {
		const bool graph_ok = set_up_example_graph(graph); // fill graph with modules and calls
		if (!graph_ok) {
		    std::cout << "ERROR: frontend could not build graph. abort. " << std::endl;
		    run_megamol = false;
		}
    }

    while (run_megamol) {
        run_megamol = render_next_frame();
    }

    // close glfw context, network connections, other system resources
    services.close();

    // clean up modules, calls in graph
    // TODO: implement graph destructor

    return 0;
}

CLIConfig handle_cli_inputs(int argc, char* argv[]) {
    CLIConfig config;

    cxxopts::Options options(argv[0], "MegaMol Frontend 3000");

    // parse input project files
    options.positional_help("<additional project files>");
    options.add_options()
        ("project-files", "projects to load", cxxopts::value<std::vector<std::string>>())
        ("host", "address of lua host server, default: "+config.lua_host_address, cxxopts::value<std::string>())
        ("noexample", "dont load minimal spheres example project", cxxopts::value<bool>())
        ;
    options.parse_positional({"project-files"});

    auto parsed_options = options.parse(argc, argv);
    std::string res;

	// verify project files exist in file system
    if (parsed_options.count("project-files")) {
        const auto& v = parsed_options["project-files"].as<std::vector<std::string>>();
        for (const auto& p : v) {
            if (!stdfs::exists(p)) {
                std::cout << "Project file \"" << p << "\" does not exist!" << std::endl;
                std::exit(1);
            }
        }

        config.project_files = v;
    }

    if (parsed_options.count("host")) {
        config.lua_host_address = parsed_options["host"].as<std::string>();
    }

    if (parsed_options.count("noexample")) {
        config.load_example_project = !parsed_options["noexample"].as<bool>();
    }

    return config;
}

bool set_up_example_graph(megamol::core::MegaMolGraph& graph) {
#define check(X) \
    if (!X) return false;

    check(graph.CreateModule("View3D_2", "::view"));
    check(graph.CreateModule("SphereRenderer", "::spheres"));
    check(graph.CreateModule("TestSpheresDataSource", "::datasource"));
    check(graph.CreateCall("CallRender3D_2", "::view::rendering", "::spheres::rendering"));
    check(graph.CreateCall("MultiParticleDataCall", "::spheres::getdata", "::datasource::getData"));

    check(graph.SetGraphEntryPoint("::view", megamol::core::view::get_gl_view_runtime_resources_requests(), megamol::core::view::view_rendering_execution));

    std::string parameter_name("::datasource::numSpheres");
    auto parameterPtr = graph.FindParameter(parameter_name);
    if (parameterPtr) {
        parameterPtr->ParseValue("23");
    } else {
        std::cout << "ERROR: could not find parameter: " << parameter_name << std::endl;
        return false;
    }

    return true;
}
<|endoftext|>


<commit_before>#include <initializer_list>
#include <sstream>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "phpcxx/module.h"
#include "phpcxx/function.h"
#include "phpcxx/fcall.h"
#include "phpcxx/types.h"
#include "phpcxx/vector.h"
#include "testsapi.h"
#include "globals.h"

extern "C" {
#include <Zend/zend.h>
#include <Zend/zend_exceptions.h>
}

namespace {

class MyModule : public phpcxx::Module {
public:
    using phpcxx::Module::Module;

protected:
    virtual std::vector<phpcxx::Function> functions() override
    {
        return {
            phpcxx::createFunction<&MyModule::test_parameters>(
                "test_parameters",
                9,
                {
                    phpcxx::byValue("a", phpcxx::ArgumentType::Any),
                    phpcxx::byValue("b", phpcxx::ArgumentType::Bool),
                    phpcxx::byValue("c", phpcxx::ArgumentType::Integer),
                    phpcxx::byValue("d", phpcxx::ArgumentType::Double),
                    phpcxx::byValue("e", phpcxx::ArgumentType::String),
                    phpcxx::byValue("f", phpcxx::ArgumentType::Array),
                    phpcxx::byValue("g", phpcxx::ArgumentType::Object),
                    phpcxx::byValue("h", phpcxx::ArgumentType::Resource),
                    phpcxx::byValue("i", phpcxx::ArgumentType::Callable)
                }
            )
        };
    }

private:
    static void test_parameters(phpcxx::Parameters& p)
    {
        if (!p.verify()) {
            return;
        }

        ASSERT_EQ(9, p.size());
        EXPECT_TRUE(phpcxx::Type::True == p[1].type() || phpcxx::Type::False == p[1].type());
        EXPECT_EQ(phpcxx::Type::Integer,  p[2].type());
        EXPECT_EQ(phpcxx::Type::Double,   p[3].type());
        EXPECT_EQ(phpcxx::Type::String,   p[4].type());
        EXPECT_EQ(phpcxx::Type::Array,    p[5].type());
        EXPECT_EQ(phpcxx::Type::Object,   p[6].type());
        EXPECT_EQ(phpcxx::Type::Resource, p[7].type());
        EXPECT_TRUE(phpcxx::Type::String == p[8].type() || phpcxx::Type::Array == p[8].type() || phpcxx::Type::Object == p[8].type());
    }
};

}

TEST(Parameters, TestCoercion)
{
    MyModule module("Parameters", "0.0");

    std::stringstream out;
    std::stringstream err;
    std::string o;
    std::string e;

    {
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([]() {
            runPhpCode(R"___(
$a = 0;
$b = true;
$c = 1;
$d = 4.0;
$e = "";
$f = array();
$g = new stdClass();
$h = tmpfile();
$i = 'sort';

test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$d = 4;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$d = "4";
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$b = 0;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$b = 2;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$c = false;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$e = false;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$b = "aaa";
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);
)___");
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_EQ("", e);
    }
}

TEST(Parameters, TestVerify)
{
    std::stringstream out;
    std::stringstream err;
    std::string o;
    std::string e;

    {
        MyModule module("Parameters", "0.0");
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([&err]() {
            DummyStackFrame dummy;

            try {
                phpcxx::call("test_parameters", 0, 0, 0, 0, 0, 0, 0, 0, 0);
                ADD_FAILURE();
            }
            catch (const phpcxx::PhpException& ex) {
                EXPECT_STREQ("Argument 6 passed to test_parameters() must be of the type array, integer given", ex.what());
                err << ex.what() << std::endl;
            }
            catch (const std::exception& e) {
                ADD_FAILURE();
            }

            try {
                runPhpCode(R"___(
function exception_error_handler($severity, $message, $file, $line)
{
    throw new ErrorException($message, 0, $severity, $file, $line);
}

set_error_handler("exception_error_handler");
)___");
                phpcxx::call("test_parameters", 0);
                ADD_FAILURE();
            }
            catch (const phpcxx::PhpException& ex) {
                EXPECT_STREQ("test_parameters() expects exactly 9 parameters, 1 given", ex.what());
                err << ex.what() << std::endl;
            }
            catch (const std::exception& e) {
                ADD_FAILURE();
            }
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_EQ(
            "Argument 6 passed to test_parameters() must be of the type array, integer given\n"
            "test_parameters() expects exactly 9 parameters, 1 given\n"
            ,
            e
        );
    }

    {
        MyModule module("Parameters", "0.0");
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([]() {
            DummyStackFrame dummy;
            phpcxx::call("test_parameters", 0);
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_NE(std::string::npos, e.find("test_parameters() expects exactly 9 parameters, 1 given"));
    }
}

TEST(Parameters, TestInitialization)
{
    std::stringstream out;
    std::stringstream err;
    std::string o;
    std::string e;

    {
        MyModule module("Parameters", "0.0");
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([]() {
            DummyStackFrame dummy;

            phpcxx::Value v1 = true;
            phpcxx::Value v2 = false;
            phpcxx::Value v3 = nullptr;

            phpcxx::vector<phpcxx::Value*> v{ &v1, &v2, &v3 };
            phpcxx::Parameters p1(v);
            phpcxx::Parameters p2({ &v1, &v2, &v3 });

            ASSERT_EQ(p1.size(), p2.size());
            ASSERT_EQ(3, p1.size());
            EXPECT_EQ(v1, p1[0]);
            EXPECT_EQ(v2, p1[1]);
            EXPECT_EQ(v3, p1[2]);
            EXPECT_EQ(v1, p2[0]);
            EXPECT_EQ(v2, p2[1]);
            EXPECT_EQ(v3, p2[2]);
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_EQ("", e);
    }
}
<commit_msg>Bug fix for PHP 7.1: explicitly mark parameters as non-null<commit_after>#include <initializer_list>
#include <sstream>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "phpcxx/module.h"
#include "phpcxx/function.h"
#include "phpcxx/fcall.h"
#include "phpcxx/types.h"
#include "phpcxx/vector.h"
#include "testsapi.h"
#include "globals.h"

extern "C" {
#include <Zend/zend.h>
#include <Zend/zend_exceptions.h>
}

namespace {

class MyModule : public phpcxx::Module {
public:
    using phpcxx::Module::Module;

protected:
    virtual std::vector<phpcxx::Function> functions() override
    {
        return {
            phpcxx::createFunction<&MyModule::test_parameters>(
                "test_parameters",
                9,
                {
                    phpcxx::byValue("a", phpcxx::ArgumentType::Any, false),
                    phpcxx::byValue("b", phpcxx::ArgumentType::Bool, false),
                    phpcxx::byValue("c", phpcxx::ArgumentType::Integer, false),
                    phpcxx::byValue("d", phpcxx::ArgumentType::Double, false),
                    phpcxx::byValue("e", phpcxx::ArgumentType::String, false),
                    phpcxx::byValue("f", phpcxx::ArgumentType::Array, false),
                    phpcxx::byValue("g", phpcxx::ArgumentType::Object, false),
                    phpcxx::byValue("h", phpcxx::ArgumentType::Resource, false),
                    phpcxx::byValue("i", phpcxx::ArgumentType::Callable, false)
                }
            )
        };
    }

private:
    static void test_parameters(phpcxx::Parameters& p)
    {
        if (!p.verify()) {
            return;
        }

        ASSERT_EQ(9, p.size());
        EXPECT_TRUE(phpcxx::Type::True == p[1].type() || phpcxx::Type::False == p[1].type());
        EXPECT_EQ(phpcxx::Type::Integer,  p[2].type());
        EXPECT_EQ(phpcxx::Type::Double,   p[3].type());
        EXPECT_EQ(phpcxx::Type::String,   p[4].type());
        EXPECT_EQ(phpcxx::Type::Array,    p[5].type());
        EXPECT_EQ(phpcxx::Type::Object,   p[6].type());
        EXPECT_EQ(phpcxx::Type::Resource, p[7].type());
        EXPECT_TRUE(phpcxx::Type::String == p[8].type() || phpcxx::Type::Array == p[8].type() || phpcxx::Type::Object == p[8].type());
    }
};

}

TEST(Parameters, TestCoercion)
{
    MyModule module("Parameters", "0.0");

    std::stringstream out;
    std::stringstream err;
    std::string o;
    std::string e;

    {
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([]() {
            runPhpCode(R"___(
$a = 0;
$b = true;
$c = 1;
$d = 4.0;
$e = "";
$f = array();
$g = new stdClass();
$h = tmpfile();
$i = 'sort';

test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$d = 4;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$d = "4";
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$b = 0;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$b = 2;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$c = false;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$e = false;
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);

$b = "aaa";
test_parameters($a, $b, $c, $d, $e, $f, $g, $h, $i);
)___");
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_EQ("", e);
    }
}

TEST(Parameters, TestVerify)
{
    std::stringstream out;
    std::stringstream err;
    std::string o;
    std::string e;

    {
        MyModule module("Parameters", "0.0");
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([&err]() {
            DummyStackFrame dummy;

            try {
                phpcxx::call("test_parameters", 0, 0, 0, 0, 0, 0, 0, 0, 0);
                ADD_FAILURE();
            }
            catch (const phpcxx::PhpException& ex) {
                EXPECT_STREQ("Argument 6 passed to test_parameters() must be of the type array, integer given", ex.what());
                err << ex.what() << std::endl;
            }
            catch (const std::exception& e) {
                ADD_FAILURE();
            }

            try {
                runPhpCode(R"___(
function exception_error_handler($severity, $message, $file, $line)
{
    throw new ErrorException($message, 0, $severity, $file, $line);
}

set_error_handler("exception_error_handler");
)___");
                phpcxx::call("test_parameters", 0);
                ADD_FAILURE();
            }
            catch (const phpcxx::PhpException& ex) {
                EXPECT_STREQ("test_parameters() expects exactly 9 parameters, 1 given", ex.what());
                err << ex.what() << std::endl;
            }
            catch (const std::exception& e) {
                ADD_FAILURE();
            }
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_EQ(
            "Argument 6 passed to test_parameters() must be of the type array, integer given\n"
            "test_parameters() expects exactly 9 parameters, 1 given\n"
            ,
            e
        );
    }

    {
        MyModule module("Parameters", "0.0");
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([]() {
            DummyStackFrame dummy;
            phpcxx::call("test_parameters", 0);
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_NE(std::string::npos, e.find("test_parameters() expects exactly 9 parameters, 1 given"));
    }
}

TEST(Parameters, TestInitialization)
{
    std::stringstream out;
    std::stringstream err;
    std::string o;
    std::string e;

    {
        MyModule module("Parameters", "0.0");
        TestSAPI sapi(out, err);
        sapi.addModule(module);
        sapi.initialize();

        sapi.run([]() {
            DummyStackFrame dummy;

            phpcxx::Value v1 = true;
            phpcxx::Value v2 = false;
            phpcxx::Value v3 = nullptr;

            phpcxx::vector<phpcxx::Value*> v{ &v1, &v2, &v3 };
            phpcxx::Parameters p1(v);
            phpcxx::Parameters p2({ &v1, &v2, &v3 });

            ASSERT_EQ(p1.size(), p2.size());
            ASSERT_EQ(3, p1.size());
            EXPECT_EQ(v1, p1[0]);
            EXPECT_EQ(v2, p1[1]);
            EXPECT_EQ(v3, p1[2]);
            EXPECT_EQ(v1, p2[0]);
            EXPECT_EQ(v2, p2[1]);
            EXPECT_EQ(v3, p2[2]);
        });

        o = out.str(); out.str(std::string());
        e = err.str(); err.str(std::string());
        EXPECT_EQ("", o);
        EXPECT_EQ("", e);
    }
}
<|endoftext|>


<commit_before>#include "SkCanvas.h"
#include "SkDocument.h"
#include "SkFontMgr.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTextBlob.h"
#include "SkTypeface.h"
#include <hb.h>
#include <hb-ft.h>
#include <cairo.h>
#include <cairo-ft.h>

struct Config {
  double page_width;
  double page_height;

  SkString title;
  SkString author;
  SkString subject;
  SkString keywords;
  SkString creator;

  std::string font_file;
  double font_size;

  Config(int argc, char **argv) :
    page_width(800.f), page_height(600.f),
    title("..."), author("..."), subject("..."), keywords("..."), creator("..."),
    font_file("fonts/NotoNastaliqUrdu-Regular.ttf"), font_size(24.0f) {
    for (int i = 1; i < argc; i++) {
      printf("Config arg[%d]=%s\n", argc, argv[i]);
      if (*argv[i] == '-') {
        char option_char = *(argv[i] + 1);
        if (i >= argc) {
          break;
        }
        const char *option_value = argv[i + 1];
        printf("\toption_char=%c\n", option_char);
        printf("\toption_value=%s\n", option_value);
        switch (option_char) {
          case 'w':
            page_width = atof(option_value);
            i++;
            break;
          case 'h':
            page_height = atof(option_value);
            i++;
            break;
          case 't':
            title = option_value;
            i++;
            break;
          case 'a':
            author = option_value;
            i++;
            break;
          case 's':
            subject = option_value;
            i++;
            break;
          case 'k':
            keywords = option_value;
            i++;
            break;
          case 'c':
            creator = option_value;
            i++;
            break;

          case 'f':
            font_file = option_value;
            i++;
            break;
          case 'z':
            font_size = atof(option_value);
            i++;
            break;
          default:
            printf("Unrecognized option: %c. Skipping.\n", option_char);
        }
      }
    }

  } // end of Config::Config
};

class Placement {
  Config config;

  FT_Library ft_library;
  FT_Face ft_face;
  hb_font_t *hb_font;
  hb_buffer_t *hb_buffer;

  const char *text;
  unsigned len;

  hb_glyph_position_t *pos;
  hb_glyph_info_t *info;

 public:
  Placement(Config &_config, const char *_text) : config(_config) {
    text = _text;
    FT_Error ft_error;

    if ((ft_error = FT_Init_FreeType (&ft_library)))
      abort();
    if ((ft_error = FT_New_Face (ft_library, config.font_file.c_str(), 0, &ft_face)))
      abort();
    if ((ft_error = FT_Set_Char_Size (ft_face, config.font_size*64,
        config.font_size*64, 0, 0)))
      abort();

    /* Create hb-ft font. */
    hb_font = hb_ft_font_create (ft_face, NULL);

    /* Create hb-buffer and populate. */
    hb_buffer = hb_buffer_create ();
    hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);
    hb_buffer_guess_segment_properties (hb_buffer);

    /* Shape it! */
    hb_shape (hb_font, hb_buffer, NULL, 0);

    dump_hb_buffer(hb_buffer);
  } // end of Placement

  ~Placement() {
    hb_buffer_destroy (hb_buffer);
    hb_font_destroy (hb_font);

    FT_Done_Face (ft_face);
    FT_Done_FreeType (ft_library);
  }

  void DrawGlyphsUsingCairo(double margin) {
    /* Draw, using cairo. */
    double width = 2 * margin;
    double height = 2 * margin;
    for (unsigned int i = 0; i < len; i++)
    {
      width  += pos[i].x_advance / 64.;
      height -= pos[i].y_advance / 64.;
    }
    if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer)))
      height += config.font_size;
    else
      width  += config.font_size;

    /* Set up cairo surface. */
    cairo_surface_t *cairo_surface;
    cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                            ceil(width),
                            ceil(height));
    cairo_t *cr;
    cr = cairo_create (cairo_surface);
    cairo_set_source_rgba (cr, 1., 1., 1., 1.);
    cairo_paint (cr);
    cairo_set_source_rgba (cr, 0., 0., 0., 1.);
    cairo_translate (cr, margin, margin);

    /* Set up cairo font face. */
    cairo_font_face_t *cairo_face;
    cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
    cairo_set_font_face (cr, cairo_face);
    cairo_set_font_size (cr, config.font_size);

    /* Set up baseline. */
    if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer)))
    {
      cairo_font_extents_t font_extents;
      cairo_font_extents (cr, &font_extents);
      double baseline = (config.font_size - font_extents.height) * .5 + font_extents.ascent;
      cairo_translate (cr, 0, baseline);
    }
    else
    {
      cairo_translate (cr, config.font_size * .5, 0);
    }

    cairo_glyph_t *cairo_glyphs = cairo_glyph_allocate (len);
    double current_x = 0;
    double current_y = 0;
    for (unsigned int i = 0; i < len; i++)
    {
      cairo_glyphs[i].index = info[i].codepoint;
      cairo_glyphs[i].x = current_x + pos[i].x_offset / 64.;
      cairo_glyphs[i].y = -(current_y + pos[i].y_offset / 64.);
      current_x += pos[i].x_advance / 64.;
      current_y += pos[i].y_advance / 64.;
    }
    cairo_show_glyphs (cr, cairo_glyphs, len);
    cairo_glyph_free (cairo_glyphs);

    cairo_surface_write_to_png (cairo_surface, "out-cairo.png");

    cairo_font_face_destroy (cairo_face);
    cairo_destroy (cr);
    cairo_surface_destroy (cairo_surface);
  } // end of DrawGlyphsUsingCairo

  bool DrawGlyphsUsingSkia(SkWStream* outputStream) {
    sk_sp<SkDocument> pdfDocument(SkDocument::CreatePDF(outputStream));
    typedef SkDocument::Attribute Attr;
    Attr pdf_info[] = {
        Attr(SkString("Title"),    config.title),
        Attr(SkString("Author"),   config.author),
        Attr(SkString("Subject"),  config.subject),
        Attr(SkString("Keywords"), config.keywords),
        Attr(SkString("Creator"),  config.creator),
    };
    int pdf_infoCount = sizeof(pdf_info) / sizeof(pdf_info[0]);
    std::unique_ptr<SkTime::DateTime> now = GetCurrentDateTime();

    pdfDocument->setMetadata(pdf_info, pdf_infoCount, now.get(), now.get());

    int numberOfPages = 1;
    for (int page = 0; page < numberOfPages; ++page) {
      SkScalar pageWidth = SkIntToScalar(800);
      SkScalar pageHeight = SkIntToScalar(600);
      SkCanvas* pageCanvas = pdfDocument->beginPage(pageWidth, pageHeight);

      SkScalar s = SkIntToScalar(600);
      static const SkPoint     kPts0[] = { { 0, 0 }, { s, s } };
      static const SkScalar    kPos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
      static const SkColor kColors0[] = {0x80F00080, 0xF0F08000, 0x800080F0 };

      SkPaint paint;
      paint.setShader(SkGradientShader::MakeLinear(
          kPts0, kColors0, kPos, SK_ARRAY_COUNT(kColors0),
          SkShader::kClamp_TileMode));
      pageCanvas->drawPaint(paint);

      SkPaint textPaint;
      // Draw a message with a nice black paint.
      textPaint.setFlags(
          SkPaint::kAntiAlias_Flag |
          SkPaint::kSubpixelText_Flag | // ... avoid waggly text when rotating.
          SkPaint::kUnderlineText_Flag);
      textPaint.setColor(SK_ColorBLACK);
      textPaint.setTextSize(config.font_size);
      pageCanvas->save();
      pageCanvas->translate(40, 20);
      pageCanvas->rotate(45.0f);
      SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
      SkTypeface * typeface = SkTypeface::CreateFromFile(config.font_file.c_str(), 0);
      textPaint.setTypeface(typeface);

      pageCanvas->drawText(text, strlen(text), 0, 0, textPaint);

      double current_x = 10;
      double current_y = 50;

      SkPaint glyphPaint(textPaint);
      glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

      SkTextBlobBuilder textBlobBuilder;
      auto runBuffer = textBlobBuilder.allocRunPos(glyphPaint, len);
      for (unsigned int i = 0; i < len; i++)
      {
        runBuffer.glyphs[i] = info[i].codepoint;
        ((SkPoint*)runBuffer.pos)[i] = SkPoint::Make(
          current_x + pos[i].x_offset / 64.,
          current_y - pos[i].y_offset / 64.);
        current_x += pos[i].x_advance / 64.;
        current_y += pos[i].y_advance / 64.;
      }

      pageCanvas->drawTextBlob(textBlobBuilder.build(), 0, 0, glyphPaint);

      pageCanvas->restore();

      pdfDocument->endPage();
    }
    return pdfDocument->close();
  } // end of DrawGlyphsUsingSkia

private:
  void dump_hb_buffer(hb_buffer_t *hb_buffer) {
    /* Get glyph information and positions out of the buffer. */
    len = hb_buffer_get_length (hb_buffer);
    info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
    pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);

    /* Print them out as is. */
    printf ("Raw buffer contents:\n");
    for (unsigned int i = 0; i < len; i++)
    {
      hb_codepoint_t gid   = info[i].codepoint;
      unsigned int cluster = info[i].cluster;
      double x_advance = pos[i].x_advance / 64.;
      double y_advance = pos[i].y_advance / 64.;
      double x_offset  = pos[i].x_offset / 64.;
      double y_offset  = pos[i].y_offset / 64.;

      char glyphname[32];
      hb_font_get_glyph_name (hb_font, gid, glyphname, sizeof (glyphname));

      printf ("glyph='%s' cluster=%d  advance=(%g,%g) offset=(%g,%g)\n",
              glyphname, cluster, x_advance, y_advance, x_offset, y_offset);
    }
  }

  std::unique_ptr<SkTime::DateTime> GetCurrentDateTime() {
    time_t m_time;
    time(&m_time);
    struct tm* tstruct;
    tstruct = gmtime(&m_time);

    std::unique_ptr<SkTime::DateTime> now(new SkTime::DateTime());
    now->fTimeZoneMinutes = 0;
    now->fYear       = tstruct->tm_year + 1900;
    now->fMonth      = SkToU8(tstruct->tm_mon + 1);
    now->fDayOfWeek  = SkToU8(tstruct->tm_wday);
    now->fDay        = SkToU8(tstruct->tm_mday);
    now->fHour       = SkToU8(tstruct->tm_hour);
    now->fMinute     = SkToU8(tstruct->tm_min);
    now->fSecond     = SkToU8(tstruct->tm_sec);
    return now;
  }
}; // end of Placement class

int main(int argc, char** argv) {
    Config config(argc, argv);

    SkPaint paint;
    paint.setColor(SK_ColorRED);

    SkString* str = new SkString();
    paint.toString(str);

    fprintf(stdout, "%s\n", str->c_str());

    // CreateAndPlaceGlyphs(36, 36 * .5, "fonts/TSCu_SaiIndira.ttf", "டஉடு");
    // CreateAndPlaceGlyphs(36, 36 * .5, "fonts/DejaVuSans.ttf", "حرف‌باز");
    // Placement placement("fonts/NotoNastaliqUrdu-Regular.ttf", "حرف‌باز Привет, Вася! Hello, world! டஉடு", 24 /* font_size */);
    Placement placement(config, "حرف‌باز");
    placement.DrawGlyphsUsingCairo(24 * .5 /* margin */);
    placement.DrawGlyphsUsingSkia(new SkFILEWStream("out-skiahf.pdf"));

    return 0;
}
<commit_msg>Takes input from stdin. Support config options.<commit_after>#include "SkCanvas.h"
#include "SkDocument.h"
#include "SkFontMgr.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTextBlob.h"
#include "SkTypeface.h"
#include <hb.h>
#include <hb-ft.h>

#include <iostream>
#include <map>

struct BaseOption {
  std::string selector;
  std::string description;
  virtual void set(std::string _value) = 0;
  virtual std::string valueToString() = 0;

  BaseOption(std::string _selector, std::string _description) :
    selector(_selector),
    description(_description) {}
};

template <class T> struct Option : BaseOption {
  T value;
  Option(std::string selector, std::string description, T defaultValue) :
    BaseOption(selector, description),
    value(defaultValue) {}
};

struct DoubleOption : Option<double> {
  virtual void set(std::string _value) {
    value = atof(_value.c_str());
  }
  virtual std::string valueToString() {
    return std::to_string(value);
  }
  DoubleOption(std::string selector, std::string description, double defaultValue) :
    Option<double>(selector, description, defaultValue) {}
};

struct SkStringOption : Option<SkString> {
  virtual void set(std::string _value) {
    value = _value.c_str();
  }
  virtual std::string valueToString() {
    return value.c_str();
  }
  SkStringOption(std::string selector, std::string description, SkString defaultValue) :
    Option<SkString>(selector, description, defaultValue) {}
};

struct StdStringOption : Option<std::string> {
  virtual void set(std::string _value) {
    value = _value;
  }
  virtual std::string valueToString() {
    return value;
  }
  StdStringOption(std::string selector, std::string description, std::string defaultValue) :
    Option<std::string>(selector, description, defaultValue) {}
};

struct Config {
  DoubleOption *page_width = new DoubleOption("-w", "Page width", 600.0f);
  DoubleOption *page_height = new DoubleOption("-h", "Page height", 800.0f);
  SkStringOption *title = new SkStringOption("-t", "PDF title", SkString("---"));
  SkStringOption *author = new SkStringOption("-a", "PDF author", SkString("---"));
  SkStringOption *subject = new SkStringOption("-k", "PDF subject", SkString("---"));
  SkStringOption *keywords = new SkStringOption("-c", "PDF keywords", SkString("---"));
  SkStringOption *creator = new SkStringOption("-t", "PDF creator", SkString("---"));
  StdStringOption *font_file = new StdStringOption("-f", ".ttf font file", "fonts/DejaVuSans.ttf");
  DoubleOption *font_size = new DoubleOption("-z", "Font size", 8.0f);
  DoubleOption *left_margin = new DoubleOption("-m", "Page height", 20.0f);
  DoubleOption *line_spacing_ratio = new DoubleOption("-h", "Line spacing ratio", 1.5f);
  StdStringOption *output_file_name = new StdStringOption("-o", ".pdf output file name", "out-skiahf.pdf");

  std::map<std::string, BaseOption*> options = {
    { page_width->selector, page_width },
    { page_height->selector, page_height },
    { title->selector, title },
    { author->selector, author },
    { subject->selector, subject },
    { keywords->selector, keywords },
    { creator->selector, creator },
    { font_file->selector, font_file },
    { font_size->selector, font_size },
    { left_margin->selector, left_margin },
    { line_spacing_ratio->selector, line_spacing_ratio },
    { output_file_name->selector, output_file_name },
  };

  Config(int argc, char **argv) {
    for (int i = 1; i < argc; i++) {
      std::string option_selector(argv[i]);
      auto it = options.find(option_selector);
      if (it != options.end()) {
        if (i >= argc) {
          break;
        }
        const char *option_value = argv[i + 1];
        it->second->set(option_value);
        i++;
      } else {
        printf("Ignoring unrecognized option: %s.\n", argv[i]);
        printf("Usage: %s {option value}\n", argv[0]);
        printf("Supported options:\n");
        for (auto it = options.begin(); it != options.end(); ++it) {
          printf("\t%s\t%s (%s)\n", it->first.c_str(),
            it->second->description.c_str(),
            it->second->valueToString().c_str());
        }
        exit(-1);
      }
    }
  } // end of Config::Config
};

const double FONT_SIZE_SCALE = 64.0f;

class Placement {
 public:
  Placement(Config &_config, SkWStream* outputStream) : config(_config),
    pdfDocument(SkDocument::CreatePDF(outputStream)) {
    FT_Error ft_error;

    if ((ft_error = FT_Init_FreeType (&ft_library)))
      abort();
    if ((ft_error = FT_New_Face (ft_library, config.font_file->value.c_str(), 0 /* face_index */, &ft_face)))
      abort();
    if ((ft_error = FT_Set_Char_Size (ft_face, config.font_size->value * FONT_SIZE_SCALE /* char_width */,
        config.font_size->value * FONT_SIZE_SCALE /* char_height */, 0 /* horz_resolution */, 0 /* vert_resolution */)))
      abort();
    hb_font = hb_ft_font_create (ft_face, NULL);

    typedef SkDocument::Attribute Attr;
    Attr pdf_info[] = {
        Attr(SkString("Title"),    config.title->value),
        Attr(SkString("Author"),   config.author->value),
        Attr(SkString("Subject"),  config.subject->value),
        Attr(SkString("Keywords"), config.keywords->value),
        Attr(SkString("Creator"),  config.creator->value),
    };
    int pdf_infoCount = sizeof(pdf_info) / sizeof(pdf_info[0]);
    std::unique_ptr<SkTime::DateTime> now = GetCurrentDateTime();

    pdfDocument->setMetadata(pdf_info, pdf_infoCount, now.get(), now.get());

    white_paint.setColor(SK_ColorWHITE);

    glyph_paint.setFlags(
        SkPaint::kAntiAlias_Flag |
        SkPaint::kSubpixelText_Flag);  // ... avoid waggly text when rotating.
    glyph_paint.setColor(SK_ColorBLACK);
    glyph_paint.setTextSize(config.font_size->value);
    SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
    SkTypeface *typeface = SkTypeface::CreateFromFile(config.font_file->value.c_str(), 0);
    glyph_paint.setTypeface(typeface);
    glyph_paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

    NewPage();
  } // end of Placement

  ~Placement() {
    hb_font_destroy (hb_font);

    FT_Done_Face (ft_face);
    FT_Done_FreeType (ft_library);
  }

  void WriteLine(const char *text) {
    /* Create hb-buffer and populate. */
    hb_buffer_t *hb_buffer = hb_buffer_create ();
    hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1);
    hb_buffer_guess_segment_properties (hb_buffer);

    /* Shape it! */
    hb_shape (hb_font, hb_buffer, NULL, 0);

    DrawGlyphs(hb_buffer);

    hb_buffer_destroy (hb_buffer);

    // Advance to the next line.
    current_y += config.line_spacing_ratio->value * config.font_size->value;
    if (current_y > config.page_height->value) {
      pdfDocument->endPage();
      NewPage();
    }
  }

  bool Close() {
    return pdfDocument->close();
  }

private:
  Config config;

  FT_Library ft_library;
  FT_Face ft_face;
  hb_font_t *hb_font;

  sk_sp<SkDocument> pdfDocument;

  SkCanvas* pageCanvas;

  SkPaint white_paint;
  SkPaint glyph_paint;

  double current_x;
  double current_y;

  void NewPage() {
    pageCanvas = pdfDocument->beginPage(config.page_width->value, config.page_height->value);

    pageCanvas->drawPaint(white_paint);

    current_x = config.left_margin->value;
    current_y = config.line_spacing_ratio->value * config.font_size->value;
  }

  bool DrawGlyphs(hb_buffer_t *hb_buffer) {
    SkTextBlobBuilder textBlobBuilder;
    unsigned len = hb_buffer_get_length (hb_buffer);
    hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
    hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);
    auto runBuffer = textBlobBuilder.allocRunPos(glyph_paint, len);

    double x = 0;
    double y = 0;
    for (unsigned int i = 0; i < len; i++)
    {
      runBuffer.glyphs[i] = info[i].codepoint;
      reinterpret_cast<SkPoint*>(runBuffer.pos)[i] = SkPoint::Make(
        x + pos[i].x_offset / FONT_SIZE_SCALE,
        y - pos[i].y_offset / FONT_SIZE_SCALE);
      x += pos[i].x_advance / FONT_SIZE_SCALE;
      y += pos[i].y_advance / FONT_SIZE_SCALE;
    }

    pageCanvas->drawTextBlob(textBlobBuilder.build(), current_x, current_y, glyph_paint);
  } // end of DrawGlyphs

  std::unique_ptr<SkTime::DateTime> GetCurrentDateTime() {
    time_t m_time;
    time(&m_time);
    struct tm* tstruct;
    tstruct = gmtime(&m_time);

    std::unique_ptr<SkTime::DateTime> now(new SkTime::DateTime());
    now->fTimeZoneMinutes = 0;
    now->fYear       = tstruct->tm_year + 1900;
    now->fMonth      = SkToU8(tstruct->tm_mon + 1);
    now->fDayOfWeek  = SkToU8(tstruct->tm_wday);
    now->fDay        = SkToU8(tstruct->tm_mday);
    now->fHour       = SkToU8(tstruct->tm_hour);
    now->fMinute     = SkToU8(tstruct->tm_min);
    now->fSecond     = SkToU8(tstruct->tm_sec);
    return now;
  }
}; // end of Placement class

int main(int argc, char** argv) {
    Config config(argc, argv);

    Placement placement(config, new SkFILEWStream(config.output_file_name->value.c_str()));
    for (std::string line; std::getline(std::cin, line);) {
      placement.WriteLine(line.c_str());
    }
    placement.Close();

    return 0;
}
<|endoftext|>


<commit_before>//It is our future main class

#include <iostream>
#include "graph.h"
#include "minion.h"

/**
* Classe qui représente la classe principale .
*/
using namespace std;

int getRandValue(int min, int max) {
    return (rand()/(int)RAND_MAX)*(max-min)+min;
}

/**
 * Méthode de commencement de la partie de chasse aux minions
 */
int main() {

    //Parametrage
    const int nbMinion = 29; // en minion
    const int nbVille = 29; // en minion
    //int tpsVisite = 30;// en min
    //double evapPheromone = 10;
    const int nbIteration = 0;

    Graph* graph = new Graph();

    Minion* lesMinions[nbMinion];

    for(int nbMimi = 0; nbMimi < nbMinion; ++nbMimi) {
        int firstPt = getRandValue(0, 29);
        Minion* mimi = new Minion("Serge", firstPt);
        lesMinions[nbMimi] = mimi;
    }

    while(nbIteration != 100){

        for(int lieu = 0; lieu < nbVille; ++lieu) {
            do {
                int pt = getRandValue(0, 29);
            }while(!mimi->addPts(pt));

        }

        //eVAPORATION DE LA BANANE
        evapoBanane();
        ++nbIteration;
    }

    return 0;
}
<commit_msg>Ajout de machin chose<commit_after>//It is our future main class

#include <iostream>
#include "graph.h"
#include "minion.h"

/**
* Classe qui représente la classe principale .
*/
using namespace std;

int getRandValue(int min, int max) {
    return (rand()/(int)RAND_MAX)*(max-min)+min;
}

/**
 * Méthode de commencement de la partie de chasse aux minions
 */
int main() {

    //Parametrage
    const int nbMinion = 29; // en minion
    const int nbVille = 29; // en minion
    //int tpsVisite = 30;// en min
    //double evapPheromone = 10;
    const int nbIteration = 0;

    cout << "BANANA !" << endl;

    Graph* graph = new Graph();

    Minion* lesMinions[nbMinion];

    for(int nbMimi = 0; nbMimi < nbMinion; ++nbMimi) {
        int firstPt = getRandValue(0, 29);
        Minion* mimi = new Minion("Serge", firstPt);
        lesMinions[nbMimi] = mimi;
    }

    while(nbIteration != 100){

        for(int lieu = 0; lieu < nbVille; ++lieu) {
            do {
                int pt = getRandValue(0, 29);
            }while(!mimi->addPts(pt));

        }

        //eVAPORATION DE LA BANANE
        evapoBanane();
        ++nbIteration;
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <pthread.h>

#include <tbb/tbb_thread.h>

#include "../../cvmfs/util.h"

//
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
//

class ThreadDummy {
 public:
  ThreadDummy(int canary_value) : result_value(0), value_(canary_value) {}

  void OtherThread() {
    result_value = value_;
  }

  int result_value;

 private:
  const int value_;
};

TEST(T_Util, ThreadProxy) {
  const int canary = 1337;

  ThreadDummy dummy(canary);
  tbb::tbb_thread thread(&ThreadProxy<ThreadDummy>,
                         &dummy,
                         &ThreadDummy::OtherThread);
  thread.join();

  EXPECT_EQ (canary, dummy.result_value);
}

TEST(T_Util, IsAbsolutePath) {
  const bool empty = IsAbsolutePath("");
  EXPECT_FALSE (empty) << "empty path string treated as absolute";

  const bool relative = IsAbsolutePath("foo.bar");
  EXPECT_FALSE (relative) << "relative path treated as absolute";
  const bool absolute = IsAbsolutePath("/tmp/foo.bar");
  EXPECT_TRUE (absolute) << "absolute path not recognized";
}

//
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
//

void CallbackFn(bool* const &param) { *param = true; }

static int callback_fn_void_calls = 0;
void CallbackFnVoid() { ++callback_fn_void_calls; }

TEST(T_Util, SimpleCallback) {
  bool callback_called = false;

  Callback<bool*> callback(&CallbackFn);
  callback(&callback_called);
  EXPECT_TRUE (callback_called);
}

const int closure_data_item = 93142;
struct ClosureData {
  ClosureData() : data(closure_data_item) {}
  int data;
};

class DummyCallbackDelegate {
 public:
  DummyCallbackDelegate() : callback_result(-1) {}
  void CallbackMd(const int &value) { callback_result = value; }
  void CallbackMdVoid() { ++callback_result; }
  void CallbackClosureMd(const int &value, ClosureData data) {
    callback_result = value + data.data;
  }
  void CallbackClosureMdVoid(ClosureData data) {
    callback_result = data.data;
  }

 public:
  int callback_result;
};

TEST(T_Util, BoundCallback) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  BoundCallback<int, DummyCallbackDelegate> callback(
                              &DummyCallbackDelegate::CallbackMd,
                              &delegate);
  callback(42);
  EXPECT_EQ (42, delegate.callback_result);
}

TEST(T_Util, BoundClosure) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  ClosureData closure_data;
  ASSERT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  BoundClosure<int, DummyCallbackDelegate, ClosureData> closure(
                              &DummyCallbackDelegate::CallbackClosureMd,
                              &delegate,
                               closure_data);
  EXPECT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  closure(1337);
  EXPECT_EQ (closure_data_item, closure_data.data); // didn't change (closure captured copy)
  EXPECT_EQ (closure_data_item + 1337, delegate.callback_result);
}

TEST(T_Util, VoidCallback) {
  Callback<void> callback(&CallbackFnVoid);
  EXPECT_EQ (0, callback_fn_void_calls);
  callback();
  EXPECT_EQ (1, callback_fn_void_calls);
  callback();
  EXPECT_EQ (2, callback_fn_void_calls);
}

TEST(T_Util, VoidBoundCallback) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  BoundCallback<void, DummyCallbackDelegate> callback(
                              &DummyCallbackDelegate::CallbackMdVoid,
                              &delegate);
  EXPECT_EQ (-1, delegate.callback_result);
  callback();
  EXPECT_EQ (0, delegate.callback_result);
  callback();
  EXPECT_EQ (1, delegate.callback_result);
  callback();
  EXPECT_EQ (2, delegate.callback_result);
}

TEST(T_Util, VoidBoundClosure) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  ClosureData closure_data;
  ASSERT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  BoundClosure<void, DummyCallbackDelegate, ClosureData> closure(
                              &DummyCallbackDelegate::CallbackClosureMdVoid,
                              &delegate,
                               closure_data);
  EXPECT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  closure();
  EXPECT_EQ (closure_data_item, closure_data.data); // didn't change (closure captured copy)
  EXPECT_EQ (closure_data_item, delegate.callback_result);
}

//
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
//

class DummyCallbackable : public Callbackable<int> {
 public:
  DummyCallbackable() : callback_result(-1) {}
  static void CallbackFn(const int &value) { g_callback_result = value; }
         void CallbackMd(const int &value) { callback_result = value; }
         void CallbackClosureMd(const int &value, ClosureData data) {
    callback_result = value + data.data;
  }

 public:
         int   callback_result;
  static int g_callback_result;
};
int DummyCallbackable::g_callback_result = -1;

TEST(T_Util, CallbackableCallback) {
  ASSERT_EQ (-1, DummyCallbackable::g_callback_result);

  DummyCallbackable::callback_t *callback =
    DummyCallbackable::MakeCallback(&DummyCallbackable::CallbackFn);
  EXPECT_EQ (-1, DummyCallbackable::g_callback_result);

  (*callback)(1337);

  EXPECT_EQ (1337, DummyCallbackable::g_callback_result);
  DummyCallbackable::g_callback_result = -1;
  ASSERT_EQ (-1, DummyCallbackable::g_callback_result);
}

TEST(T_Util, CallbackableBoundCallback) {
  DummyCallbackable callbackable;
  ASSERT_EQ (-1, callbackable.callback_result);

  DummyCallbackable::callback_t *callback =
    DummyCallbackable::MakeCallback(&DummyCallbackable::CallbackMd,
                                    &callbackable);
  (*callback)(1337);

  EXPECT_EQ (1337, callbackable.callback_result);
}

TEST(T_Util, CallbackableBoundClosure) {
  DummyCallbackable callbackable;
  ASSERT_EQ (-1, callbackable.callback_result);

  ClosureData closure_data;
  ASSERT_EQ (closure_data_item, closure_data.data);

  DummyCallbackable::callback_t *callback =
    DummyCallbackable::MakeClosure(&DummyCallbackable::CallbackClosureMd,
                                   &callbackable,
                                    closure_data);
  EXPECT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, callbackable.callback_result);

  (*callback)(1337);

  EXPECT_EQ (closure_data_item, closure_data.data); // didn't change (closure captured copy)
  EXPECT_EQ (1337 + closure_data_item, callbackable.callback_result);
}
<commit_msg>code cosmetics<commit_after>#include <gtest/gtest.h>
#include <pthread.h>

#include <tbb/tbb_thread.h>

#include "../../cvmfs/util.h"

//
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
//

class ThreadDummy {
 public:
  ThreadDummy(int canary_value) : result_value(0), value_(canary_value) {}

  void OtherThread() {
    result_value = value_;
  }

  int result_value;

 private:
  const int value_;
};

TEST(T_Util, ThreadProxy) {
  const int canary = 1337;

  ThreadDummy dummy(canary);
  tbb::tbb_thread thread(&ThreadProxy<ThreadDummy>,
                         &dummy,
                         &ThreadDummy::OtherThread);
  thread.join();

  EXPECT_EQ (canary, dummy.result_value);
}

TEST(T_Util, IsAbsolutePath) {
  const bool empty = IsAbsolutePath("");
  EXPECT_FALSE (empty) << "empty path string treated as absolute";

  const bool relative = IsAbsolutePath("foo.bar");
  EXPECT_FALSE (relative) << "relative path treated as absolute";
  const bool absolute = IsAbsolutePath("/tmp/foo.bar");
  EXPECT_TRUE (absolute) << "absolute path not recognized";
}

//
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
//

void CallbackFn(bool* const &param) { *param = true; }

static int callback_fn_void_calls = 0;
void CallbackFnVoid() { ++callback_fn_void_calls; }

TEST(T_Util, SimpleCallback) {
  bool callback_called = false;

  Callback<bool*> callback(&CallbackFn);
  callback(&callback_called);
  EXPECT_TRUE (callback_called);
}

const int closure_data_item = 93142;
struct ClosureData {
  ClosureData() : data(closure_data_item) {}
  int data;
};

class DummyCallbackDelegate {
 public:
  DummyCallbackDelegate() : callback_result(-1) {}
  void CallbackMd(const int &value) { callback_result = value; }
  void CallbackMdVoid() { ++callback_result; }
  void CallbackClosureMd(const int &value, ClosureData data) {
    callback_result = value + data.data;
  }
  void CallbackClosureMdVoid(ClosureData data) {
    callback_result = data.data;
  }

 public:
  int callback_result;
};

TEST(T_Util, BoundCallback) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  BoundCallback<int, DummyCallbackDelegate> callback(
                              &DummyCallbackDelegate::CallbackMd,
                              &delegate);
  callback(42);
  EXPECT_EQ (42, delegate.callback_result);
}

TEST(T_Util, BoundClosure) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  ClosureData closure_data;
  ASSERT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  BoundClosure<int, DummyCallbackDelegate, ClosureData> closure(
                              &DummyCallbackDelegate::CallbackClosureMd,
                              &delegate,
                               closure_data);
  EXPECT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  closure(1337);
  EXPECT_EQ (closure_data_item, closure_data.data); // didn't change (closure captured copy)
  EXPECT_EQ (closure_data_item + 1337, delegate.callback_result);
}

TEST(T_Util, VoidCallback) {
  Callback<void> callback(&CallbackFnVoid);
  EXPECT_EQ (0, callback_fn_void_calls);
  callback();
  EXPECT_EQ (1, callback_fn_void_calls);
  callback();
  EXPECT_EQ (2, callback_fn_void_calls);
}

TEST(T_Util, VoidBoundCallback) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  BoundCallback<void, DummyCallbackDelegate> callback(
                              &DummyCallbackDelegate::CallbackMdVoid,
                              &delegate);
  EXPECT_EQ (-1, delegate.callback_result);
  callback();
  EXPECT_EQ (0, delegate.callback_result);
  callback();
  EXPECT_EQ (1, delegate.callback_result);
  callback();
  EXPECT_EQ (2, delegate.callback_result);
}

TEST(T_Util, VoidBoundClosure) {
  DummyCallbackDelegate delegate;
  ASSERT_EQ (-1, delegate.callback_result);

  ClosureData closure_data;
  ASSERT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  BoundClosure<void, DummyCallbackDelegate, ClosureData> closure(
                              &DummyCallbackDelegate::CallbackClosureMdVoid,
                              &delegate,
                               closure_data);
  EXPECT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, delegate.callback_result);

  closure();
  EXPECT_EQ (closure_data_item, closure_data.data); // didn't change (closure captured copy)
  EXPECT_EQ (closure_data_item, delegate.callback_result);
}

//
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
//

class DummyCallbackable : public Callbackable<int> {
 public:
  DummyCallbackable() : callback_result(-1) {}
  static void CallbackFn(const int &value) { g_callback_result = value; }
         void CallbackMd(const int &value) { callback_result = value; }
         void CallbackClosureMd(const int &value, ClosureData data) {
    callback_result = value + data.data;
  }

 public:
         int callback_result;
  static int g_callback_result;
};
int DummyCallbackable::g_callback_result = -1;

TEST(T_Util, CallbackableCallback) {
  ASSERT_EQ (-1, DummyCallbackable::g_callback_result);

  DummyCallbackable::callback_t *callback =
    DummyCallbackable::MakeCallback(&DummyCallbackable::CallbackFn);
  EXPECT_EQ (-1, DummyCallbackable::g_callback_result);

  (*callback)(1337);

  EXPECT_EQ (1337, DummyCallbackable::g_callback_result);
  DummyCallbackable::g_callback_result = -1;
  ASSERT_EQ (-1, DummyCallbackable::g_callback_result);
}

TEST(T_Util, CallbackableBoundCallback) {
  DummyCallbackable callbackable;
  ASSERT_EQ (-1, callbackable.callback_result);

  DummyCallbackable::callback_t *callback =
    DummyCallbackable::MakeCallback(&DummyCallbackable::CallbackMd,
                                    &callbackable);
  (*callback)(1337);

  EXPECT_EQ (1337, callbackable.callback_result);
}

TEST(T_Util, CallbackableBoundClosure) {
  DummyCallbackable callbackable;
  ASSERT_EQ (-1, callbackable.callback_result);

  ClosureData closure_data;
  ASSERT_EQ (closure_data_item, closure_data.data);

  DummyCallbackable::callback_t *callback =
    DummyCallbackable::MakeClosure(&DummyCallbackable::CallbackClosureMd,
                                   &callbackable,
                                    closure_data);
  EXPECT_EQ (closure_data_item, closure_data.data);
  EXPECT_EQ (-1, callbackable.callback_result);

  (*callback)(1337);

  EXPECT_EQ (closure_data_item, closure_data.data); // didn't change (closure captured copy)
  EXPECT_EQ (1337 + closure_data_item, callbackable.callback_result);
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

// User med en key (tilsvarer cookie-id)
//
// Brukeridentifisering
//
// Starte med:
// Sette en favorittdyr = hest: kommer opp hest på siden

// Se squirrel.hpp

#pragma once
#ifndef MODEL_USER_HPP
#define MODEL_USER_HPP

#include "json.hpp"
//#include <locale>

namespace acorn {

// struct or class?

/**
 *
 */
struct User : json::Serializable {
  size_t key;

  /**
   *
   */
  User() : key{0} {}

  // More constructors here

  /**
   *
   */
  std::string json() const;

  friend std::ostream & operator<< (std::ostream &out, const User& u);

  /**
   *
   */
  virtual void serialize(rapidjson::Writer<rapidjson::StringBuffer>&) const override;

  /**
   *
   */
  virtual bool deserialize(const rapidjson::Document&) override;

  /**
   *
   */
  bool is_equal(const User&) const;

  /**
   *
   */
  static bool is_equal(const User&, const User&);

};

// -------------------- Implementation ------------------------

std::ostream & operator<< (std::ostream &out, const User& u) {
  out << u.json();
  return out;
}

void User::serialize(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
  writer.StartObject();

  writer.Key("key");
  writer.Uint(key);

  // Write more variables here

  writer.EndObject();
}

bool User::deserialize(const rapidjson::Document& doc) {
  key = doc["key"].GetUint();

  // set more variables here

  return true;
}

std::string User::json() const {
  using namespace rapidjson;
  StringBuffer sb;
  Writer<StringBuffer> writer(sb);
  serialize(writer);
  return sb.GetString();
}

bool User::is_equal(const User& u) const {
  if(key == u.key)
    return false;

  return true;
}

bool User::is_equal(const User& u1, const User& u2) {
  return u1.is_equal(u2);
}

} // < namespace acorn

#endif
<commit_msg>Removed unneccesary friendship<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

// User med en key (tilsvarer cookie-id)
//
// Brukeridentifisering
//
// Starte med:
// Sette en favorittdyr = hest: kommer opp hest på siden

// Se squirrel.hpp

#pragma once
#ifndef MODEL_USER_HPP
#define MODEL_USER_HPP

#include "json.hpp"
//#include <locale>

namespace acorn {

// struct or class?

/**
 *
 */
struct User : json::Serializable {
  size_t key;

  /**
   *
   */
  User() : key{0} {}

  // More constructors here

  /**
   *
   */
  std::string json() const;

  /**
   *
   */
  virtual void serialize(rapidjson::Writer<rapidjson::StringBuffer>&) const override;

  /**
   *
   */
  virtual bool deserialize(const rapidjson::Document&) override;

  /**
   *
   */
  bool is_equal(const User&) const;

  /**
   *
   */
  static bool is_equal(const User&, const User&);

};

// -------------------- Implementation ------------------------

inline std::ostream& operator << (std::ostream& output_device, const User& u) {
  return output_device << u.json();
}

void User::serialize(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
  writer.StartObject();

  writer.Key("key");
  writer.Uint(key);

  // Write more variables here

  writer.EndObject();
}

bool User::deserialize(const rapidjson::Document& doc) {
  key = doc["key"].GetUint();

  // set more variables here

  return true;
}

std::string User::json() const {
  using namespace rapidjson;
  StringBuffer sb;
  Writer<StringBuffer> writer(sb);
  serialize(writer);
  return sb.GetString();
}

bool User::is_equal(const User& u) const {
  if(key == u.key)
    return false;

  return true;
}

bool User::is_equal(const User& u1, const User& u2) {
  return u1.is_equal(u2);
}

} // < namespace acorn

#endif
<|endoftext|>


<commit_before>#include <webdriverxx/wait_match.h>
#include <gtest/gtest.h>

using namespace webdriverxx;
using namespace webdriverxx::detail;

bool FunctionMatcher(int) { return true; }

struct FunctorMatcher {
	bool operator () (int) const {
		return true;
	}
};

TEST(WaitForMatch, CanBeUsedWithFunctionFunctorAndLambda) {
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctionMatcher));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctorMatcher()));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));
}

TEST(WaitForMatch, ReturnsMatchedValue) {
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));
}

TEST(WaitForMatch, DoesNotWaitIfValueIsMatched) {
	Duration timeout = 1000;
	const TimePoint start = Now();
	WaitForMatch([]{ return 0; }, [](int){ return true; }, timeout);
	ASSERT_TRUE(Now() - start < timeout/2);
}

TEST(WaitForMatch, WaitsUntilValueIsMatched) {
	Duration timeout = 1000;
	Duration interval = 0;
	int counter = 0;
	WaitForMatch([]{ return 0; }, [&counter](int){ return ++counter == 10; }, timeout, interval);
	ASSERT_EQ(10, counter);
}

TEST(WaitForMatch, ThrowsExceptionOnTimeout) {
	Duration timeout = 0;
	ASSERT_THROW(WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout), WebDriverException);
}

TEST(WaitForMatch, ExplainsTimeout) {
	try {
		Duration timeout = 0;
		WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout);
		FAIL();
	} catch (const std::exception& e) {
		std::string message = e.what();
		const auto npos = std::string::npos;
		ASSERT_NE(npos, message.find("imeout"));
	}
}

TEST(WaitForMatch, CanUseGMockMatchers) {
	using namespace ::testing;
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, Eq(123)));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, 123));
	ASSERT_EQ("abc", WaitForMatch([]{ return std::string("abc"); }, "abc"));
	ASSERT_EQ("abc", WaitForMatch([]{ return std::string("abc"); }, Eq("abc")));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, _));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, An<int>()));
	std::vector<int> v(1, 123);
	ASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Contains(123)));
	ASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Not(Contains(456))));
	Duration timeout = 0;
	ASSERT_THROW(WaitForMatch([&v]{ return v; }, Not(Contains(123)), timeout), WebDriverException);
}

TEST(WaitForMatch, ExplainsGMockMatcherMismatch) {
	try {
		Duration timeout = 0;
		using namespace ::testing;
		WaitForMatch([]{ return 123; }, Eq(456), timeout);
		FAIL();
	} catch (const std::exception& e) {
		std::string message = e.what();
		const auto npos = std::string::npos;
		ASSERT_NE(npos, message.find("123"));
		ASSERT_NE(npos, message.find("456"));
		ASSERT_NE(npos, message.find("imeout"));
	}
}
<commit_msg>*EXPERIMENTAL* Test ADL in GCC/clang<commit_after>#include <webdriverxx/wait_match.h>
#include <gtest/gtest.h>

using namespace webdriverxx;
using namespace webdriverxx::detail;

bool FunctionMatcher(int) { return true; }

struct FunctorMatcher {
	bool operator () (int) const {
		return true;
	}
};

TEST(WaitForMatch, CanBeUsedWithFunctionFunctorAndLambda) {
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctionMatcher));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, FunctorMatcher()));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));
}

TEST(WaitForMatch, ReturnsMatchedValue) {
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, [](int){ return true; }));
}

TEST(WaitForMatch, DoesNotWaitIfValueIsMatched) {
	Duration timeout = 1000;
	const TimePoint start = Now();
	WaitForMatch([]{ return 0; }, [](int){ return true; }, timeout);
	ASSERT_TRUE(Now() - start < timeout/2);
}

TEST(WaitForMatch, WaitsUntilValueIsMatched) {
	Duration timeout = 1000;
	Duration interval = 0;
	int counter = 0;
	WaitForMatch([]{ return 0; }, [&counter](int){ return ++counter == 10; }, timeout, interval);
	ASSERT_EQ(10, counter);
}

TEST(WaitForMatch, ThrowsExceptionOnTimeout) {
	Duration timeout = 0;
	ASSERT_THROW(WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout), WebDriverException);
}

TEST(WaitForMatch, ExplainsTimeout) {
	try {
		Duration timeout = 0;
		WaitForMatch([]{ return 0; }, [](int){ return false; }, timeout);
		FAIL();
	} catch (const std::exception& e) {
		std::string message = e.what();
		const auto npos = std::string::npos;
		ASSERT_NE(npos, message.find("imeout"));
	}
}

TEST(WaitForMatch, CanUseGMockMatchers) {
	using namespace ::testing;
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, Eq(123)));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, 123));
	ASSERT_EQ("abc", WaitForMatch([]{ return std::string("abc"); }, "abc"));
	ASSERT_EQ("abc", WaitForMatch([]{ return std::string("abc"); }, Eq("abc")));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, _));
	ASSERT_EQ(123, WaitForMatch([]{ return 123; }, An<int>()));
	std::vector<int> v(1, 123);
	ASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Contains(123)));
	ASSERT_EQ(v, WaitForMatch([&v]{ return v; }, Not(Contains(456))));
	Duration timeout = 0;
	ASSERT_THROW(WaitForMatch([&v]{ return v; }, Not(Contains(123)), timeout), WebDriverException);
}

TEST(WaitForMatch, ExplainsGMockMatcherMismatch) {
	try {
		Duration timeout = 0;
		using namespace ::testing;
		WaitForMatch([]{ return 123; }, Eq(456), timeout);
		FAIL();
	} catch (const std::exception& e) {
		std::string message = e.what();
		const auto npos = std::string::npos;
		ASSERT_NE(npos, message.find("123"));
		ASSERT_NE(npos, message.find("456"));
		ASSERT_NE(npos, message.find("imeout"));
	}
}

struct type1 {};
struct type2 {};

int foo(type1)
{
	return 1;
}

template<typename T>
int bar() {
	return foo(T());
}

TEST(WaitForMatch, ADL) {
	ASSERT_EQ(1, bar<type1>());
	ASSERT_EQ(2, bar<type2>());
}

int foo(type2)
{
	return 2;
}
<|endoftext|>


<commit_before>/**
 * @file Matrix.hpp
 *
 * A quaternion class.
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once
#include <Vector.hpp>
#include <Dcm.hpp>
#include <Euler.hpp>

namespace matrix
{

template <typename Type>
class Dcm;

template <typename Type>
class Euler;

template<typename Type>
class Quaternion : public Vector<Type, 4>
{
public:
    virtual ~Quaternion() {};

    Quaternion() :
        Vector<Type, 4>()
    {
        Quaternion &q = *this;
        q(0) = 1;
        q(1) = 2;
        q(2) = 3;
        q(3) = 4;
    }

    Quaternion(const Dcm<Type> & dcm) :
        Vector<Type, 4>()
    {
        Quaternion &q = *this;
        q(0) = 0.5 * sqrt(1 + dcm(0, 0) +
                          dcm(1, 1) + dcm(2, 2));
        q(1) = (dcm(2, 1) - dcm(1, 2)) /
               (4 * q(0));
        q(2) = (dcm(0, 2) - dcm(2, 0)) /
               (4 * q(0));
        q(3) = (dcm(1, 0) - dcm(0, 1)) /
               (4 * q(0));
    }

    Quaternion(const Euler<Type> & euler) {
        Quaternion &q = *this;
        Type cosPhi_2 = cos(euler.phi() / 2.0);
        Type cosTheta_2 = cos(euler.theta() / 2.0);
        Type cosPsi_2 = cos(euler.psi() / 2.0);
        Type sinPhi_2 = sin(euler.phi() / 2.0);
        Type sinTheta_2 = sin(euler.theta() / 2.0);
        Type sinPsi_2 = sin(euler.psi() / 2.0);
        q(0) = cosPhi_2 * cosTheta_2 * cosPsi_2 +
               sinPhi_2 * sinTheta_2 * sinPsi_2;
        q(1) = sinPhi_2 * cosTheta_2 * cosPsi_2 -
               cosPhi_2 * sinTheta_2 * sinPsi_2;
        q(2) = cosPhi_2 * sinTheta_2 * cosPsi_2 +
               sinPhi_2 * cosTheta_2 * sinPsi_2;
        q(3) = cosPhi_2 * cosTheta_2 * sinPsi_2 +
               sinPhi_2 * sinTheta_2 * cosPsi_2;
    }

    Quaternion(Type a, Type b, Type c, Type d) : Vector<Type, 4>()
    {
        Quaternion &q = *this;
        q(0) = a;
        q(1) = b;
        q(2) = c;
        q(3) = d;
    }

    Quaternion operator*(const Quaternion &q) const
    {
        const Quaternion &p = *this;
        Quaternion r;
        r(0) = p(0)*q(0) - p(1)*q(1) - p(2)*q(2) - p(3)*q(3);
        r(1) = p(0)*q(1) + p(1)*q(0) - p(2)*q(3) + p(3)*q(2);
        r(2) = p(0)*q(2) + p(1)*q(3) + p(2)*q(0) - p(3)*q(1);
        r(3) = p(0)*q(3) - p(1)*q(2) + p(2)*q(1) + p(3)*q(0);
        return r;
    }

    Matrix<Type, 4, 1> derivative(const Matrix<Type, 3, 1> & w) const {
        const Quaternion &q = *this;
        Type dataQ[] = {
            q(0), -q(1), -q(2), -q(3),
            q(1),  q(0), -q(3),  q(2),
            q(2),  q(3),  q(0), -q(1),
            q(3), -q(2),  q(1),  q(0)
        };
        Matrix<Type, 4, 4> Q(dataQ);
        Vector<Type, 4> v;
        v(0) = 0;
        v(1) = w(0);
        v(2) = w(1);
        v(3) = w(2);
        return Q * v * 0.5;
    }
};

typedef Quaternion<float> Quatf;

}; // namespace matrix
<commit_msg>Fixed default.<commit_after>/**
 * @file Matrix.hpp
 *
 * A quaternion class.
 *
 * @author James Goppert <james.goppert@gmail.com>
 */

#pragma once
#include <Vector.hpp>
#include <Dcm.hpp>
#include <Euler.hpp>

namespace matrix
{

template <typename Type>
class Dcm;

template <typename Type>
class Euler;

template<typename Type>
class Quaternion : public Vector<Type, 4>
{
public:
    virtual ~Quaternion() {};

    Quaternion() :
        Vector<Type, 4>()
    {
        Quaternion &q = *this;
        q(0) = 1;
        q(1) = 0;
        q(2) = 0;
        q(3) = 0;
    }

    Quaternion(const Dcm<Type> & dcm) :
        Vector<Type, 4>()
    {
        Quaternion &q = *this;
        q(0) = 0.5 * sqrt(1 + dcm(0, 0) +
                          dcm(1, 1) + dcm(2, 2));
        q(1) = (dcm(2, 1) - dcm(1, 2)) /
               (4 * q(0));
        q(2) = (dcm(0, 2) - dcm(2, 0)) /
               (4 * q(0));
        q(3) = (dcm(1, 0) - dcm(0, 1)) /
               (4 * q(0));
    }

    Quaternion(const Euler<Type> & euler) {
        Quaternion &q = *this;
        Type cosPhi_2 = cos(euler.phi() / 2.0);
        Type cosTheta_2 = cos(euler.theta() / 2.0);
        Type cosPsi_2 = cos(euler.psi() / 2.0);
        Type sinPhi_2 = sin(euler.phi() / 2.0);
        Type sinTheta_2 = sin(euler.theta() / 2.0);
        Type sinPsi_2 = sin(euler.psi() / 2.0);
        q(0) = cosPhi_2 * cosTheta_2 * cosPsi_2 +
               sinPhi_2 * sinTheta_2 * sinPsi_2;
        q(1) = sinPhi_2 * cosTheta_2 * cosPsi_2 -
               cosPhi_2 * sinTheta_2 * sinPsi_2;
        q(2) = cosPhi_2 * sinTheta_2 * cosPsi_2 +
               sinPhi_2 * cosTheta_2 * sinPsi_2;
        q(3) = cosPhi_2 * cosTheta_2 * sinPsi_2 +
               sinPhi_2 * sinTheta_2 * cosPsi_2;
    }

    Quaternion(Type a, Type b, Type c, Type d) : Vector<Type, 4>()
    {
        Quaternion &q = *this;
        q(0) = a;
        q(1) = b;
        q(2) = c;
        q(3) = d;
    }

    Quaternion operator*(const Quaternion &q) const
    {
        const Quaternion &p = *this;
        Quaternion r;
        r(0) = p(0)*q(0) - p(1)*q(1) - p(2)*q(2) - p(3)*q(3);
        r(1) = p(0)*q(1) + p(1)*q(0) - p(2)*q(3) + p(3)*q(2);
        r(2) = p(0)*q(2) + p(1)*q(3) + p(2)*q(0) - p(3)*q(1);
        r(3) = p(0)*q(3) - p(1)*q(2) + p(2)*q(1) + p(3)*q(0);
        return r;
    }

    Matrix<Type, 4, 1> derivative(const Matrix<Type, 3, 1> & w) const {
        const Quaternion &q = *this;
        Type dataQ[] = {
            q(0), -q(1), -q(2), -q(3),
            q(1),  q(0), -q(3),  q(2),
            q(2),  q(3),  q(0), -q(1),
            q(3), -q(2),  q(1),  q(0)
        };
        Matrix<Type, 4, 4> Q(dataQ);
        Vector<Type, 4> v;
        v(0) = 0;
        v(1) = w(0);
        v(2) = w(1);
        v(3) = w(2);
        return Q * v * 0.5;
    }
};

typedef Quaternion<float> Quatf;

}; // namespace matrix
<|endoftext|>


<commit_before>void calcPoint(){
    game.getItemZRState(itemState, targetNumber);
    if(itemState[3] <= 0.1 && itemState[4] <= 0.1 && itemState[5] <= 0.1){
        game.getItemLoc(actualTarget, targetNumber);
        for(int i=0; i<3; i++){
            itemAtt[i] = itemState[i+6];
            pointAtt[i] = -itemAtt[i];
        }
        mathVecNormalize(itemAtt, 3);
        float length = mathVecMagnitude(itemAtt, 3);
        for(int i=0; i<3; i++)
            virtualTarget[i] = itemAtt[i] * distFromTarget/length*0.99 + actualTarget[i];
        calculated = true;
    }
}

/*this function calculates the docking point based on the position, attitude and type of item*/

void approachPack(){
    if(!compareVector(myPos, virtualTarget, 0.005)){
        float dis_to_point_near = dist(myPos, virtualTarget);
        float dis_to_center = dist(myPos, actualTarget);
        if ((dis_to_point_near>dis_to_center) && (dis_to_point_near<=0.4)){
            goAround();
        }
            else{
            api.setPositionTarget(virtualTarget);
        }
    }
}

/*we go to the docking point*/

void goAround(){
    float dist[3];
    float max=-1;
    int max_num=-1;
    for(int i = 0; i<3; ++i){
        dist[i] = fabsf(myState[i]-itemState[i]);
        if (dist[i]>max){
            max = dist[i];
            max_num = i;
        }
    }

    float force_point[3];
    for(int i =0; i<3;++i)
        force_point[i] = itemAtt[i];
    force_point[max_num]*=-1;
    counter++;
    if (counter % 2 == 0) api.setForces(force_point);
}

/*this function let us fly around an item to avoid collision*/<commit_msg>Edited distance multiplicatort for ranking<commit_after>void worthyPack() {
    for(int i = 0; i < 4; i++) {
        getRank(i);
    }
    getWorthyPackInfo();
    setDist();
}

/*cumulative function to learn which pack is the worthiest*/

int itemStat(int num) {
    if(game.itemInZone(num))
        return 3;

    if(packInTheirZone(num) && game.hasItem(num) == 0)
        return 4;

    return(game.hasItem(num));
}

/* we check if the pack is in our or their zone to calculate the real rating of the item*/

void getRank(int num) {
    float target[3];
    getMyPos();
    game.getItemLoc(target, num);
    ranking[num] = 1/((dist(myPos, target))*(dist(myPos, target)));
    switch(num){
        case 0:   //large
        case 1:
            ranking[num]*=4.5;
            break;
        case 2:   //medium
        case 3:
            ranking[num]*=2.5;
            break;
    }
    switch(itemStat(num)){
        case 0:
            ranking[num]*=1;
            break;
        case 4:
            ranking[num]*=1.75;
            break;
        default:
            ranking[num]*=-100;
            break;
    }
}

/* the rating is based on distance and points/second that the item gives*/

void getWorthyPackInfo(){
    targetNumber = 0;
    float max = ranking[0];
    for(int i = 0; i < 4; i++){
        if(ranking[i] > max){
            targetNumber = i;
            max = ranking[i];
        }
    }
    game.getItemLoc(actualTarget, targetNumber);
}

/*calculates the max valued pack */

void setDist(){
    switch(targetNumber){
        case 0:
        case 1:
            //distFromTarget = .182;
            distFromTarget = .162;
            distMin = 0.151;
            distMax = 0.173;
            break;
        case 2:
        case 3:
            //distFromTarget = .1725;
            distFromTarget = .143;
            distMin = 0.138;
            distMax = 0.160;
            break;
    }
}

/*set docking distances based on pack. (probably useless with the new functions we're using) */<|endoftext|>