<commit_before>/*
 * Copyright (c) 2016, Egor Pugin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     1. Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *     2. 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.
 *     3. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "access_table.h"
#include "config.h"
#include "database.h"
#include "directories.h"
#include "hash.h"
#include "hasher.h"
#include "log.h"
#include "templates.h"
#include "stamp.h"

#include <boost/algorithm/string.hpp>

#include "logger.h"
DECLARE_STATIC_LOGGER(logger, "settings");

const Remotes default_remotes{
    {
        DEFAULT_REMOTE_NAME,
        "https://cppan.org/",
        "data"
    },
};

Settings::Settings()
{
    build_dir = temp_directory_path() / "build";
    storage_dir = get_root_directory() / STORAGE_DIR;
}

void Settings::load(const path &p, const ConfigType type)
{
    auto root = YAML::LoadFile(p.string());
    load(root, type);
}

void Settings::load(const yaml &root, const ConfigType type)
{
    load_main(root, type);

    auto get_storage_dir = [this](ConfigType type)
    {
        switch (type)
        {
        case ConfigType::Local:
            return cppan_dir / STORAGE_DIR;
        case ConfigType::User:
            return Config::get_user_config().settings.storage_dir;
        case ConfigType::System:
            return Config::get_system_config().settings.storage_dir;
        default:
            return storage_dir;
        }
    };

    auto get_build_dir = [this](const path &p, ConfigType type)
    {
        switch (type)
        {
        case ConfigType::Local:
            return fs::current_path();
        case ConfigType::User:
            return directories.storage_dir_tmp;
        case ConfigType::System:
            return temp_directory_path() / "build";
        default:
            return p;
        }
    };

    Directories dirs;
    dirs.storage_dir_type = storage_dir_type;
    dirs.set_storage_dir(get_storage_dir(storage_dir_type));
    dirs.build_dir_type = build_dir_type;
    dirs.set_build_dir(get_build_dir(build_dir, build_dir_type));
    directories.update(dirs, type);
}

void Settings::load_main(const yaml &root, const ConfigType type)
{
    auto packages_dir_type_from_string = [](const String &s, const String &key)
    {
        if (s == "local")
            return ConfigType::Local;
        if (s == "user")
            return ConfigType::User;
        if (s == "system")
            return ConfigType::System;
        throw std::runtime_error("Unknown '" + key + "'. Should be one of [local, user, system]");
    };

    get_map_and_iterate(root, "remotes", [this](auto &kv)
    {
        auto n = kv.first.template as<String>();
        bool o = n == DEFAULT_REMOTE_NAME; // origin
        Remote rm;
        Remote *prm = o ? &remotes[0] : &rm;
        prm->name = n;
        EXTRACT_VAR(kv.second, prm->url, "url", String);
        EXTRACT_VAR(kv.second, prm->data_dir, "data_dir", String);
        EXTRACT_VAR(kv.second, prm->user, "user", String);
        EXTRACT_VAR(kv.second, prm->token, "token", String);
        if (!o)
            remotes.push_back(*prm);
    });

    EXTRACT_AUTO(disable_update_checks);
    EXTRACT(storage_dir, String);
    EXTRACT(build_dir, String);
    EXTRACT(cppan_dir, String);

    auto &p = root["proxy"];
    if (p.IsDefined())
    {
        if (!p.IsMap())
            throw std::runtime_error("'proxy' should be a map");
        EXTRACT_VAR(p, proxy.host, "host", String);
        EXTRACT_VAR(p, proxy.user, "user", String);
    }

    storage_dir_type = packages_dir_type_from_string(get_scalar<String>(root, "storage_dir_type", "user"), "storage_dir_type");
    if (root["storage_dir"].IsDefined())
        storage_dir_type = ConfigType::None;
    build_dir_type = packages_dir_type_from_string(get_scalar<String>(root, "build_dir_type", "system"), "build_dir_type");
    if (root["build_dir"].IsDefined())
        build_dir_type = ConfigType::None;

    // read these first from local settings
    // and they'll be overriden in bs (if they exist there)
    EXTRACT_AUTO(use_cache);
    EXTRACT_AUTO(show_ide_projects);
    EXTRACT_AUTO(add_run_cppan_target);
    EXTRACT_AUTO(cmake_verbose);

    // read build settings
    if (type == ConfigType::Local)
    {
        // at first, we load bs from current root
        load_build(root);

        // then override settings with specific (or default) config
        yaml current_build;
        if (root["builds"].IsDefined())
        {
            // yaml will not keep sorting of keys in map
            // so we can take 'first' build in document
            if (root["current_build"].IsDefined())
                current_build = root["builds"][root["current_build"].template as<String>()];
        }
        else if (root["build"].IsDefined())
            current_build = root["build"];

        load_build(current_build);
    }
}

void Settings::load_build(const yaml &root)
{
    if (root.IsNull())
        return;

    // extract
    EXTRACT_AUTO(c_compiler);
    EXTRACT_AUTO(cxx_compiler);
    EXTRACT_AUTO(compiler);
    EXTRACT_AUTO(c_compiler_flags);
    if (c_compiler_flags.empty())
        EXTRACT_VAR(root, c_compiler_flags, "c_flags", String);
    EXTRACT_AUTO(cxx_compiler_flags);
    if (cxx_compiler_flags.empty())
        EXTRACT_VAR(root, cxx_compiler_flags, "cxx_flags", String);
    EXTRACT_AUTO(compiler_flags);
    EXTRACT_AUTO(link_flags);
    EXTRACT_AUTO(link_libraries);
    EXTRACT_AUTO(configuration);
    EXTRACT_AUTO(generator);
    EXTRACT_AUTO(toolset);
    EXTRACT_AUTO(use_shared_libs);
    EXTRACT_AUTO(silent);
    EXTRACT_AUTO(use_cache);
    EXTRACT_AUTO(show_ide_projects);
    EXTRACT_AUTO(add_run_cppan_target);
    EXTRACT_AUTO(cmake_verbose);

    for (int i = 0; i < CMakeConfigurationType::Max; i++)
    {
        auto t = configuration_types[i];
        boost::to_lower(t);
        EXTRACT_VAR(root, c_compiler_flags_conf[i], "c_compiler_flags_" + t, String);
        EXTRACT_VAR(root, cxx_compiler_flags_conf[i], "cxx_compiler_flags_" + t, String);
        EXTRACT_VAR(root, compiler_flags_conf[i], "compiler_flags_" + t, String);
        EXTRACT_VAR(root, link_flags_conf[i], "link_flags_" + t, String);
    }

    cmake_options = get_sequence<String>(root["cmake_options"]);
    get_string_map(root, "env", env);

    // process
    if (c_compiler.empty())
        c_compiler = cxx_compiler;
    if (c_compiler.empty())
        c_compiler = compiler;
    if (cxx_compiler.empty())
        cxx_compiler = compiler;

    c_compiler_flags += " " + compiler_flags;
    cxx_compiler_flags += " " + compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
    {
        c_compiler_flags_conf[i] += " " + compiler_flags_conf[i];
        cxx_compiler_flags_conf[i] += " " + compiler_flags_conf[i];
    }
}

bool Settings::is_custom_build_dir() const
{
    return build_dir_type == ConfigType::Local || build_dir_type == ConfigType::None;
}

void Settings::set_build_dirs(const String &name)
{
    filename = name;
    filename_without_ext = name;

    source_directory = directories.build_dir;
    if (directories.build_dir_type == ConfigType::Local ||
        directories.build_dir_type == ConfigType::None)
    {
        source_directory /= (CPPAN_LOCAL_BUILD_PREFIX + filename);
    }
    else
    {
        source_directory_hash = sha256_short(name);
        source_directory /= source_directory_hash;
    }
    binary_directory = source_directory / "build";
}

void Settings::append_build_dirs(const path &p)
{
    source_directory /= p;
    binary_directory = source_directory / "build";
}

String Settings::get_hash() const
{
    Hasher h;
    h |= c_compiler;
    h |= cxx_compiler;
    h |= compiler;
    h |= c_compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= c_compiler_flags_conf[i];
    h |= cxx_compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= cxx_compiler_flags_conf[i];
    h |= compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= compiler_flags_conf[i];
    h |= link_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= link_flags_conf[i];
    h |= link_libraries;
    h |= generator;
    h |= toolset;
    h |= use_shared_libs;
    return h.hash;
}

String Settings::get_fs_generator() const
{
    String g = generator;
    boost::to_lower(g);
    boost::replace_all(g, " ", "-");
    return g;
}

String get_config(const Settings &settings)
{
    // add original config to db
    // but return hashed

    auto &db = getServiceDatabase();
    auto h = settings.get_hash();
    auto c = db.getConfigByHash(h);

    if (!c.empty())
        return hash_config(c);

    c = test_run(settings);
    auto ch = hash_config(c);
    db.addConfigHash(h, c, ch);

    return ch;
}

String test_run(const Settings &settings)
{
    // do a test build to extract config string
    auto src_dir = temp_directory_path() / "temp" / fs::unique_path();
    auto bin_dir = src_dir / "build";

    fs::create_directories(src_dir);
    write_file(src_dir / CPPAN_FILENAME, "");
    SCOPE_EXIT
    {
        // remove test dir
        boost::system::error_code ec;
        fs::remove_all(src_dir, ec);
    };

    // invoke cppan
    Config conf(src_dir);
    conf.process(src_dir);
    conf.settings = settings;
    conf.settings.allow_links = false;
    conf.settings.disable_checks = true;
    conf.settings.source_directory = src_dir;
    conf.settings.binary_directory = bin_dir;

    auto printer = Printer::create(settings.printerType);
    printer->rc = &conf;
    printer->prepare_build();

    LOG("--");
    LOG("-- Performing test run");
    LOG("--");

    auto ret = printer->generate();

    if (ret)
        throw std::runtime_error("There are errors during test run");

    // read cfg
    auto c = read_file(bin_dir / CPPAN_CONFIG_FILENAME);
    auto cmake_version = get_cmake_version();

    // move this to printer some time
    // copy cached cmake config to storage
    copy_dir(
        bin_dir / "CMakeFiles" / cmake_version,
        directories.storage_dir_cfg / hash_config(c) / "CMakeFiles" / cmake_version);

    return c;
}

int Settings::build_packages(Config &c, const String &name)
{
    auto printer = Printer::create(printerType);
    printer->rc = &c;

    config = get_config(*this);

    set_build_dirs(name);
    append_build_dirs(config);

    auto cmake_version = get_cmake_version();
    auto src = directories.storage_dir_cfg / config / "CMakeFiles" / cmake_version;

    // if dir does not exist it means probably we have new cmake version
    // we have config value but there was not a test run with copying cmake prepared files
    // so start unconditional test run
    if (!fs::exists(src))
        test_run(*this);

    // move this to printer some time
    // copy cached cmake config to bin dir
    copy_dir(src, binary_directory / "CMakeFiles" / cmake_version);

    // setup printer config
    c.process(source_directory);
    printer->prepare_build();

    auto ret = generate(c);
    if (ret)
        return ret;
    return build(c);
}

int Settings::generate(Config &c) const
{
    auto printer = Printer::create(printerType);
    printer->rc = &c;
    return printer->generate();
}

int Settings::build(Config &c) const
{
    auto printer = Printer::create(printerType);
    printer->rc = &c;
    return printer->build();
}

bool Settings::checkForUpdates() const
{
    if (disable_update_checks)
        return false;

#ifdef _WIN32
    String stamp_file = "/client/.service/win32.stamp";
#elif __APPLE__
    String stamp_file = "/client/.service/macos.stamp";
#else
    String stamp_file = "/client/.service/linux.stamp";
#endif

    DownloadData dd;
    dd.url = remotes[0].url + stamp_file;
    dd.fn = fs::temp_directory_path() / fs::unique_path();
    download_file(dd);
    auto stamp_remote = boost::trim_copy(read_file(dd.fn));
    boost::replace_all(stamp_remote, "\"", "");
    uint64_t s1 = std::stoull(cppan_stamp);
    uint64_t s2 = std::stoull(stamp_remote);
    if (!(s1 != 0 && s2 != 0 && s2 > s1))
        return false;

    std::cout << "New version of the CPPAN client is available!" << "\n";
    std::cout << "Feel free to upgrade it from website or simply run:" << "\n";
    std::cout << "cppan --self-upgrade" << "\n";
#ifdef _WIN32
    std::cout << "(or the same command but from administrator)" << "\n";
#else
    std::cout << "or" << "\n";
    std::cout << "sudo cppan --self-upgrade" << "\n";
#endif
    std::cout << "\n";
    return true;
}
<commit_msg>Remove unnecessary copying.<commit_after>/*
 * Copyright (c) 2016, Egor Pugin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     1. Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *     2. 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.
 *     3. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "access_table.h"
#include "config.h"
#include "database.h"
#include "directories.h"
#include "hash.h"
#include "hasher.h"
#include "log.h"
#include "templates.h"
#include "stamp.h"

#include <boost/algorithm/string.hpp>

#include "logger.h"
DECLARE_STATIC_LOGGER(logger, "settings");

const Remotes default_remotes{
    {
        DEFAULT_REMOTE_NAME,
        "https://cppan.org/",
        "data"
    },
};

Settings::Settings()
{
    build_dir = temp_directory_path() / "build";
    storage_dir = get_root_directory() / STORAGE_DIR;
}

void Settings::load(const path &p, const ConfigType type)
{
    auto root = YAML::LoadFile(p.string());
    load(root, type);
}

void Settings::load(const yaml &root, const ConfigType type)
{
    load_main(root, type);

    auto get_storage_dir = [this](ConfigType type)
    {
        switch (type)
        {
        case ConfigType::Local:
            return cppan_dir / STORAGE_DIR;
        case ConfigType::User:
            return Config::get_user_config().settings.storage_dir;
        case ConfigType::System:
            return Config::get_system_config().settings.storage_dir;
        default:
            return storage_dir;
        }
    };

    auto get_build_dir = [this](const path &p, ConfigType type)
    {
        switch (type)
        {
        case ConfigType::Local:
            return fs::current_path();
        case ConfigType::User:
            return directories.storage_dir_tmp;
        case ConfigType::System:
            return temp_directory_path() / "build";
        default:
            return p;
        }
    };

    Directories dirs;
    dirs.storage_dir_type = storage_dir_type;
    dirs.set_storage_dir(get_storage_dir(storage_dir_type));
    dirs.build_dir_type = build_dir_type;
    dirs.set_build_dir(get_build_dir(build_dir, build_dir_type));
    directories.update(dirs, type);
}

void Settings::load_main(const yaml &root, const ConfigType type)
{
    auto packages_dir_type_from_string = [](const String &s, const String &key)
    {
        if (s == "local")
            return ConfigType::Local;
        if (s == "user")
            return ConfigType::User;
        if (s == "system")
            return ConfigType::System;
        throw std::runtime_error("Unknown '" + key + "'. Should be one of [local, user, system]");
    };

    get_map_and_iterate(root, "remotes", [this](auto &kv)
    {
        auto n = kv.first.template as<String>();
        bool o = n == DEFAULT_REMOTE_NAME; // origin
        Remote rm;
        Remote *prm = o ? &remotes[0] : &rm;
        prm->name = n;
        EXTRACT_VAR(kv.second, prm->url, "url", String);
        EXTRACT_VAR(kv.second, prm->data_dir, "data_dir", String);
        EXTRACT_VAR(kv.second, prm->user, "user", String);
        EXTRACT_VAR(kv.second, prm->token, "token", String);
        if (!o)
            remotes.push_back(*prm);
    });

    EXTRACT_AUTO(disable_update_checks);
    EXTRACT(storage_dir, String);
    EXTRACT(build_dir, String);
    EXTRACT(cppan_dir, String);

    auto &p = root["proxy"];
    if (p.IsDefined())
    {
        if (!p.IsMap())
            throw std::runtime_error("'proxy' should be a map");
        EXTRACT_VAR(p, proxy.host, "host", String);
        EXTRACT_VAR(p, proxy.user, "user", String);
    }

    storage_dir_type = packages_dir_type_from_string(get_scalar<String>(root, "storage_dir_type", "user"), "storage_dir_type");
    if (root["storage_dir"].IsDefined())
        storage_dir_type = ConfigType::None;
    build_dir_type = packages_dir_type_from_string(get_scalar<String>(root, "build_dir_type", "system"), "build_dir_type");
    if (root["build_dir"].IsDefined())
        build_dir_type = ConfigType::None;

    // read these first from local settings
    // and they'll be overriden in bs (if they exist there)
    EXTRACT_AUTO(use_cache);
    EXTRACT_AUTO(show_ide_projects);
    EXTRACT_AUTO(add_run_cppan_target);
    EXTRACT_AUTO(cmake_verbose);

    // read build settings
    if (type == ConfigType::Local)
    {
        // at first, we load bs from current root
        load_build(root);

        // then override settings with specific (or default) config
        yaml current_build;
        if (root["builds"].IsDefined())
        {
            // yaml will not keep sorting of keys in map
            // so we can take 'first' build in document
            if (root["current_build"].IsDefined())
                current_build = root["builds"][root["current_build"].template as<String>()];
        }
        else if (root["build"].IsDefined())
            current_build = root["build"];

        load_build(current_build);
    }
}

void Settings::load_build(const yaml &root)
{
    if (root.IsNull())
        return;

    // extract
    EXTRACT_AUTO(c_compiler);
    EXTRACT_AUTO(cxx_compiler);
    EXTRACT_AUTO(compiler);
    EXTRACT_AUTO(c_compiler_flags);
    if (c_compiler_flags.empty())
        EXTRACT_VAR(root, c_compiler_flags, "c_flags", String);
    EXTRACT_AUTO(cxx_compiler_flags);
    if (cxx_compiler_flags.empty())
        EXTRACT_VAR(root, cxx_compiler_flags, "cxx_flags", String);
    EXTRACT_AUTO(compiler_flags);
    EXTRACT_AUTO(link_flags);
    EXTRACT_AUTO(link_libraries);
    EXTRACT_AUTO(configuration);
    EXTRACT_AUTO(generator);
    EXTRACT_AUTO(toolset);
    EXTRACT_AUTO(use_shared_libs);
    EXTRACT_AUTO(silent);
    EXTRACT_AUTO(use_cache);
    EXTRACT_AUTO(show_ide_projects);
    EXTRACT_AUTO(add_run_cppan_target);
    EXTRACT_AUTO(cmake_verbose);

    for (int i = 0; i < CMakeConfigurationType::Max; i++)
    {
        auto t = configuration_types[i];
        boost::to_lower(t);
        EXTRACT_VAR(root, c_compiler_flags_conf[i], "c_compiler_flags_" + t, String);
        EXTRACT_VAR(root, cxx_compiler_flags_conf[i], "cxx_compiler_flags_" + t, String);
        EXTRACT_VAR(root, compiler_flags_conf[i], "compiler_flags_" + t, String);
        EXTRACT_VAR(root, link_flags_conf[i], "link_flags_" + t, String);
    }

    cmake_options = get_sequence<String>(root["cmake_options"]);
    get_string_map(root, "env", env);

    // process
    if (c_compiler.empty())
        c_compiler = cxx_compiler;
    if (c_compiler.empty())
        c_compiler = compiler;
    if (cxx_compiler.empty())
        cxx_compiler = compiler;

    c_compiler_flags += " " + compiler_flags;
    cxx_compiler_flags += " " + compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
    {
        c_compiler_flags_conf[i] += " " + compiler_flags_conf[i];
        cxx_compiler_flags_conf[i] += " " + compiler_flags_conf[i];
    }
}

bool Settings::is_custom_build_dir() const
{
    return build_dir_type == ConfigType::Local || build_dir_type == ConfigType::None;
}

void Settings::set_build_dirs(const String &name)
{
    filename = name;
    filename_without_ext = name;

    source_directory = directories.build_dir;
    if (directories.build_dir_type == ConfigType::Local ||
        directories.build_dir_type == ConfigType::None)
    {
        source_directory /= (CPPAN_LOCAL_BUILD_PREFIX + filename);
    }
    else
    {
        source_directory_hash = sha256_short(name);
        source_directory /= source_directory_hash;
    }
    binary_directory = source_directory / "build";
}

void Settings::append_build_dirs(const path &p)
{
    source_directory /= p;
    binary_directory = source_directory / "build";
}

String Settings::get_hash() const
{
    Hasher h;
    h |= c_compiler;
    h |= cxx_compiler;
    h |= compiler;
    h |= c_compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= c_compiler_flags_conf[i];
    h |= cxx_compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= cxx_compiler_flags_conf[i];
    h |= compiler_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= compiler_flags_conf[i];
    h |= link_flags;
    for (int i = 0; i < CMakeConfigurationType::Max; i++)
        h |= link_flags_conf[i];
    h |= link_libraries;
    h |= generator;
    h |= toolset;
    h |= use_shared_libs;
    return h.hash;
}

String Settings::get_fs_generator() const
{
    String g = generator;
    boost::to_lower(g);
    boost::replace_all(g, " ", "-");
    return g;
}

String get_config(const Settings &settings)
{
    // add original config to db
    // but return hashed

    auto &db = getServiceDatabase();
    auto h = settings.get_hash();
    auto c = db.getConfigByHash(h);

    if (!c.empty())
        return hash_config(c);

    c = test_run(settings);
    auto ch = hash_config(c);
    db.addConfigHash(h, c, ch);

    return ch;
}

String test_run(const Settings &settings)
{
    // do a test build to extract config string
    auto src_dir = temp_directory_path() / "temp" / fs::unique_path();
    auto bin_dir = src_dir / "build";

    fs::create_directories(src_dir);
    write_file(src_dir / CPPAN_FILENAME, "");
    SCOPE_EXIT
    {
        // remove test dir
        boost::system::error_code ec;
        fs::remove_all(src_dir, ec);
    };

    // invoke cppan
    Config conf(src_dir);
    conf.process(src_dir);
    conf.settings = settings;
    conf.settings.allow_links = false;
    conf.settings.disable_checks = true;
    conf.settings.source_directory = src_dir;
    conf.settings.binary_directory = bin_dir;

    auto printer = Printer::create(settings.printerType);
    printer->rc = &conf;
    printer->prepare_build();

    LOG("--");
    LOG("-- Performing test run");
    LOG("--");

    auto ret = printer->generate();

    if (ret)
        throw std::runtime_error("There are errors during test run");

    // read cfg
    auto c = read_file(bin_dir / CPPAN_CONFIG_FILENAME);
    auto cmake_version = get_cmake_version();

    // move this to printer some time
    // copy cached cmake config to storage
    copy_dir(
        bin_dir / "CMakeFiles" / cmake_version,
        directories.storage_dir_cfg / hash_config(c) / "CMakeFiles" / cmake_version);

    return c;
}

int Settings::build_packages(Config &c, const String &name)
{
    auto printer = Printer::create(printerType);
    printer->rc = &c;

    config = get_config(*this);

    set_build_dirs(name);
    append_build_dirs(config);

    auto cmake_version = get_cmake_version();
    auto src = directories.storage_dir_cfg / config / "CMakeFiles" / cmake_version;

    // if dir does not exist it means probably we have new cmake version
    // we have config value but there was not a test run with copying cmake prepared files
    // so start unconditional test run
    if (!fs::exists(src))
        test_run(*this);

    // move this to printer some time
    // copy cached cmake config to bin dir
    auto dst = binary_directory / "CMakeFiles" / cmake_version;
    if (!fs::exists(dst))
        copy_dir(src, dst);

    // setup printer config
    c.process(source_directory);
    printer->prepare_build();

    auto ret = generate(c);
    if (ret)
        return ret;
    return build(c);
}

int Settings::generate(Config &c) const
{
    auto printer = Printer::create(printerType);
    printer->rc = &c;
    return printer->generate();
}

int Settings::build(Config &c) const
{
    auto printer = Printer::create(printerType);
    printer->rc = &c;
    return printer->build();
}

bool Settings::checkForUpdates() const
{
    if (disable_update_checks)
        return false;

#ifdef _WIN32
    String stamp_file = "/client/.service/win32.stamp";
#elif __APPLE__
    String stamp_file = "/client/.service/macos.stamp";
#else
    String stamp_file = "/client/.service/linux.stamp";
#endif

    DownloadData dd;
    dd.url = remotes[0].url + stamp_file;
    dd.fn = fs::temp_directory_path() / fs::unique_path();
    download_file(dd);
    auto stamp_remote = boost::trim_copy(read_file(dd.fn));
    boost::replace_all(stamp_remote, "\"", "");
    uint64_t s1 = std::stoull(cppan_stamp);
    uint64_t s2 = std::stoull(stamp_remote);
    if (!(s1 != 0 && s2 != 0 && s2 > s1))
        return false;

    std::cout << "New version of the CPPAN client is available!" << "\n";
    std::cout << "Feel free to upgrade it from website or simply run:" << "\n";
    std::cout << "cppan --self-upgrade" << "\n";
#ifdef _WIN32
    std::cout << "(or the same command but from administrator)" << "\n";
#else
    std::cout << "or" << "\n";
    std::cout << "sudo cppan --self-upgrade" << "\n";
#endif
    std::cout << "\n";
    return true;
}
<|endoftext|>


<commit_before><commit_msg>Bugfix: add missing `#include` line.<commit_after><|endoftext|>


<commit_before>// This file manages project configuration & persisting it to EEPROM.
#include "settings.h"
#include "primitives/string_utils.h"
#include "vive_sensors_pipeline.h"
#include "led_state.h"
#include "print_helpers.h"

constexpr uint32_t current_settings_version = 0xbabe0000 + sizeof(PersistentSettings);
constexpr uint32_t initial_eeprom_addr = 0;

static_assert(sizeof(PersistentSettings) < 1500, "PersistentSettings must fit into EEPROM with some leeway");
static_assert(std::is_trivially_copyable<PersistentSettings>(), "All definitions must be trivially copyable to be bitwise-stored");

/* Example settings
# Comments are prepended by '#'
reset  # Reset all settings to clean state
sensor0 pin 12 positive
base0 origin -1.528180 2.433750 -1.969390 matrix -0.841840 0.332160 -0.425400 -0.046900 0.740190 0.670760 0.537680 0.584630 -0.607540
base1 origin 1.718700 2.543170 0.725060 matrix 0.458350 -0.649590 0.606590 0.028970 0.693060 0.720300 -0.888300 -0.312580 0.336480
object0 sensor0
stream0 position object0 > usb_serial
stream1 angles > usb_serial
serial1 57600
stream2 mavlink object0 ned 110 > serial1
*/

PersistentSettings settings;

PersistentSettings::PersistentSettings() {
    reset();
    read_from_eeprom();
}

bool PersistentSettings::read_from_eeprom() {
    uint32_t eeprom_addr = initial_eeprom_addr, version;
    eeprom_read(eeprom_addr, &version, sizeof(version)); eeprom_addr += sizeof(version);
    if (version == current_settings_version) {
        // Normal initialization: Just copy block of data.
        eeprom_read(eeprom_addr, this, sizeof(*this));
        return true;
    }
    // Unknown version.
    return false;
}

void PersistentSettings::write_to_eeprom() {
    uint32_t version = current_settings_version;
    uint32_t eeprom_addr = initial_eeprom_addr;
    eeprom_write(eeprom_addr, &version, sizeof(version));  eeprom_addr += sizeof(version);
    eeprom_write(eeprom_addr, this, sizeof(*this));
}

void PersistentSettings::restart_in_configuration_mode() {
    is_configured_ = false;
    write_to_eeprom();
    restart_system();
}

// Initialize settings.
void PersistentSettings::reset() {
    memset(this, 0, sizeof(*this));

    // Defaults.
    outputs_.set_size(num_outputs);
    outputs_[0].active = true;
}

bool PersistentSettings::validate_setup(PrintStream &error_stream) {
    try {
        // Try to create the pipeline and then delete it.
        std::unique_ptr<Pipeline> pipeline = create_vive_sensor_pipeline(*this);
        return true;
    }
    catch (const std::exception& e) { // This included bad_alloc, runtime_exception etc.
        error_stream.printf("Validation error: %s\n", e.what());
    }
    catch (...) {
        error_stream.printf("Unknown validation error.\n");
    }
    return false;
}

template<typename T, unsigned arr_len>
void PersistentSettings::set_value(Vector<T, arr_len> &arr, uint32_t idx, HashedWord *input_words, PrintStream &stream) {
    if (idx <= arr.size() && idx < arr_len) {
        T def;
        if (def.parse_def(idx, input_words, stream)) {
            bool push_new = idx == arr.size();
            if (push_new)
                arr.push(def);
            else
                std::swap(arr[idx], def);

            if (validate_setup(stream)) {
                // Success.
                def.print_def(idx, stream);
            } else {
                // Validation failed. Undo.
                if (push_new)
                    arr.pop();
                else
                    std::swap(arr[idx], def);
            }
        }
    } else
        stream.printf("Index too large. Next available index: %d.\n", arr.size());
}

bool PersistentSettings::process_command(char *input_cmd, PrintStream &stream) {
    HashedWord *input_words = hash_words(input_cmd);
    if (*input_words && input_words->word[0] != '#') { // Do nothing on comments and empty lines.
        uint32_t idx = input_words->idx;
        switch (*input_words++) {
        case "view"_hash:
            // Print all current settings.
            stream.printf("# Current configuration. Copy/paste to save/restore.\n",
                        inputs_.size(), base_stations_.size());
            stream.printf("reset\n");
            for (uint32_t i = 0; i < inputs_.size(); i++)
                inputs_[i].print_def(i, stream);
            for (uint32_t i = 0; i < base_stations_.size(); i++)
                base_stations_[i].print_def(i, stream);
            for (uint32_t i = 0; i < geo_builders_.size(); i++)
                geo_builders_[i].print_def(i, stream);
            for (uint32_t i = 0; i < outputs_.size(); i++)
                outputs_[i].print_def(i, stream);
            for (uint32_t i = 0; i < formatters_.size(); i++)
                formatters_[i].print_def(i, stream);
            break;

        case "sensor#"_hash:
            set_value(inputs_, idx, input_words, stream);
            break;

        case "base#"_hash:
            set_value(base_stations_, idx, input_words, stream);
            break;

        case "object#"_hash:
            set_value(geo_builders_, idx, input_words, stream);
            break;

        case "stream#"_hash:
            set_value(formatters_, idx, input_words, stream);
            break;

        case "usb_serial"_hash:
        case "serial#"_hash:
            if (idx == (uint32_t)-1) idx = 0;
            set_value(outputs_, idx, input_words, stream);
            break;

        case "reset"_hash:
            reset();
            stream.printf("Reset successful.\n");
            break;

        case "reload"_hash:
            if (read_from_eeprom())
                stream.printf("Loaded previous configuration from EEPROM.\n");
            else
                stream.printf("No valid configuration found in EEPROM.\n");
            break;

        case "write"_hash:
            if (!validate_setup(stream)) break;
            is_configured_ = true;
            write_to_eeprom();
            stream.printf("Write to EEPROM successful. Type 'continue' to start using it.\n");
            break;

        case "validate"_hash:
            if (validate_setup(stream))
                stream.printf("Validation successful.\n");
            break;

        case "continue"_hash:
            if (!validate_setup(stream)) break;
            is_configured_ = true;
            return false;

        default:
            stream.printf("Unknown command '%s'. Valid commands: view, <module> <settings>, reset, reload, write, validate, continue.\n", (input_words-1)->word);
        }
    }

    // Print prompt for the next command.
    stream.printf("config> ");
    return true;
}

// == Configuration pipeline ==================================================

class SettingsReaderWriterNode
    : public WorkerNode
    , public DataChunkLineSplitter
    , public Producer<DataChunk> {
public:
    SettingsReaderWriterNode(PersistentSettings *settings, Pipeline *pipeline)
            : settings_(settings)
            , pipeline_(pipeline) {
        set_led_state(LedState::kConfigMode);
    }

private:
    virtual void consume_line(char *line, Timestamp time) {
        DataChunkPrintStream stream(this, time);
        if (!settings_->process_command(line, stream))
            pipeline_->stop();
    }

    virtual void do_work(Timestamp cur_time) {
        update_led_pattern(cur_time);
    }

    PersistentSettings *settings_;
    Pipeline *pipeline_;
};

std::unique_ptr<Pipeline> PersistentSettings::create_configuration_pipeline(uint32_t stream_idx) {
    auto pipeline = std::make_unique<Pipeline>();

    auto reader = pipeline->add_back(std::make_unique<SettingsReaderWriterNode>(this, pipeline.get()));
    auto output_node = pipeline->add_back(OutputNode::create(stream_idx, OutputDef{}));
    reader->pipe(output_node);
    output_node->pipe(reader);

    return pipeline;
}
<commit_msg>Minor fix: print new value when changing config<commit_after>// This file manages project configuration & persisting it to EEPROM.
#include "settings.h"
#include "primitives/string_utils.h"
#include "vive_sensors_pipeline.h"
#include "led_state.h"
#include "print_helpers.h"

constexpr uint32_t current_settings_version = 0xbabe0000 + sizeof(PersistentSettings);
constexpr uint32_t initial_eeprom_addr = 0;

static_assert(sizeof(PersistentSettings) < 1500, "PersistentSettings must fit into EEPROM with some leeway");
static_assert(std::is_trivially_copyable<PersistentSettings>(), "All definitions must be trivially copyable to be bitwise-stored");

/* Example settings
# Comments are prepended by '#'
reset  # Reset all settings to clean state
sensor0 pin 12 positive
base0 origin -1.528180 2.433750 -1.969390 matrix -0.841840 0.332160 -0.425400 -0.046900 0.740190 0.670760 0.537680 0.584630 -0.607540
base1 origin 1.718700 2.543170 0.725060 matrix 0.458350 -0.649590 0.606590 0.028970 0.693060 0.720300 -0.888300 -0.312580 0.336480
object0 sensor0
stream0 position object0 > usb_serial
stream1 angles > usb_serial
serial1 57600
stream2 mavlink object0 ned 110 > serial1
*/

PersistentSettings settings;

PersistentSettings::PersistentSettings() {
    reset();
    read_from_eeprom();
}

bool PersistentSettings::read_from_eeprom() {
    uint32_t eeprom_addr = initial_eeprom_addr, version;
    eeprom_read(eeprom_addr, &version, sizeof(version)); eeprom_addr += sizeof(version);
    if (version == current_settings_version) {
        // Normal initialization: Just copy block of data.
        eeprom_read(eeprom_addr, this, sizeof(*this));
        return true;
    }
    // Unknown version.
    return false;
}

void PersistentSettings::write_to_eeprom() {
    uint32_t version = current_settings_version;
    uint32_t eeprom_addr = initial_eeprom_addr;
    eeprom_write(eeprom_addr, &version, sizeof(version));  eeprom_addr += sizeof(version);
    eeprom_write(eeprom_addr, this, sizeof(*this));
}

void PersistentSettings::restart_in_configuration_mode() {
    is_configured_ = false;
    write_to_eeprom();
    restart_system();
}

// Initialize settings.
void PersistentSettings::reset() {
    memset(this, 0, sizeof(*this));

    // Defaults.
    outputs_.set_size(num_outputs);
    outputs_[0].active = true;
}

bool PersistentSettings::validate_setup(PrintStream &error_stream) {
    try {
        // Try to create the pipeline and then delete it.
        std::unique_ptr<Pipeline> pipeline = create_vive_sensor_pipeline(*this);
        return true;
    }
    catch (const std::exception& e) { // This included bad_alloc, runtime_exception etc.
        error_stream.printf("Validation error: %s\n", e.what());
    }
    catch (...) {
        error_stream.printf("Unknown validation error.\n");
    }
    return false;
}

template<typename T, unsigned arr_len>
void PersistentSettings::set_value(Vector<T, arr_len> &arr, uint32_t idx, HashedWord *input_words, PrintStream &stream) {
    if (idx <= arr.size() && idx < arr_len) {
        T def;
        if (def.parse_def(idx, input_words, stream)) {
            bool push_new = idx == arr.size();
            if (push_new)
                arr.push(def);
            else
                std::swap(arr[idx], def);

            if (validate_setup(stream)) {
                // Success.
                stream.printf("Updated: ");
                arr[idx].print_def(idx, stream);
            } else {
                // Validation failed. Undo.
                if (push_new)
                    arr.pop();
                else
                    std::swap(arr[idx], def);
            }
        }
    } else
        stream.printf("Index too large. Next available index: %d.\n", arr.size());
}

bool PersistentSettings::process_command(char *input_cmd, PrintStream &stream) {
    HashedWord *input_words = hash_words(input_cmd);
    if (*input_words && input_words->word[0] != '#') { // Do nothing on comments and empty lines.
        uint32_t idx = input_words->idx;
        switch (*input_words++) {
        case "view"_hash:
            // Print all current settings.
            stream.printf("# Current configuration. Copy/paste to save/restore.\n",
                        inputs_.size(), base_stations_.size());
            stream.printf("reset\n");
            for (uint32_t i = 0; i < inputs_.size(); i++)
                inputs_[i].print_def(i, stream);
            for (uint32_t i = 0; i < base_stations_.size(); i++)
                base_stations_[i].print_def(i, stream);
            for (uint32_t i = 0; i < geo_builders_.size(); i++)
                geo_builders_[i].print_def(i, stream);
            for (uint32_t i = 0; i < outputs_.size(); i++)
                outputs_[i].print_def(i, stream);
            for (uint32_t i = 0; i < formatters_.size(); i++)
                formatters_[i].print_def(i, stream);
            break;

        case "sensor#"_hash:
            set_value(inputs_, idx, input_words, stream);
            break;

        case "base#"_hash:
            set_value(base_stations_, idx, input_words, stream);
            break;

        case "object#"_hash:
            set_value(geo_builders_, idx, input_words, stream);
            break;

        case "stream#"_hash:
            set_value(formatters_, idx, input_words, stream);
            break;

        case "usb_serial"_hash:
        case "serial#"_hash:
            if (idx == (uint32_t)-1) idx = 0;
            set_value(outputs_, idx, input_words, stream);
            break;

        case "reset"_hash:
            reset();
            stream.printf("Reset successful.\n");
            break;

        case "reload"_hash:
            if (read_from_eeprom())
                stream.printf("Loaded previous configuration from EEPROM.\n");
            else
                stream.printf("No valid configuration found in EEPROM.\n");
            break;

        case "write"_hash:
            if (!validate_setup(stream)) break;
            is_configured_ = true;
            write_to_eeprom();
            stream.printf("Write to EEPROM successful. Type 'continue' to start using it.\n");
            break;

        case "validate"_hash:
            if (validate_setup(stream))
                stream.printf("Validation successful.\n");
            break;

        case "continue"_hash:
            if (!validate_setup(stream)) break;
            is_configured_ = true;
            return false;

        default:
            stream.printf("Unknown command '%s'. Valid commands: view, <module> <settings>, reset, reload, write, validate, continue.\n", (input_words-1)->word);
        }
    }

    // Print prompt for the next command.
    stream.printf("config> ");
    return true;
}

// == Configuration pipeline ==================================================

class SettingsReaderWriterNode
    : public WorkerNode
    , public DataChunkLineSplitter
    , public Producer<DataChunk> {
public:
    SettingsReaderWriterNode(PersistentSettings *settings, Pipeline *pipeline)
            : settings_(settings)
            , pipeline_(pipeline) {
        set_led_state(LedState::kConfigMode);
    }

private:
    virtual void consume_line(char *line, Timestamp time) {
        DataChunkPrintStream stream(this, time);
        if (!settings_->process_command(line, stream))
            pipeline_->stop();
    }

    virtual void do_work(Timestamp cur_time) {
        update_led_pattern(cur_time);
    }

    PersistentSettings *settings_;
    Pipeline *pipeline_;
};

std::unique_ptr<Pipeline> PersistentSettings::create_configuration_pipeline(uint32_t stream_idx) {
    auto pipeline = std::make_unique<Pipeline>();

    auto reader = pipeline->add_back(std::make_unique<SettingsReaderWriterNode>(this, pipeline.get()));
    auto output_node = pipeline->add_back(OutputNode::create(stream_idx, OutputDef{}));
    reader->pipe(output_node);
    output_node->pipe(reader);

    return pipeline;
}
<|endoftext|>


<commit_before>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Mathematics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#pragma once

#ifndef NAZARA_ENUMS_MATH_HPP
#define NAZARA_ENUMS_MATH_HPP

enum nzCorner
{
	nzCorner_FarLeftBottom,
	nzCorner_FarLeftTop,
	nzCorner_FarRightBottom,
	nzCorner_FarRightTop,
	nzCorner_NearLeftBottom,
	nzCorner_NearLeftTop,
	nzCorner_NearRightBottom,
	nzCorner_NearRightTop,

	nzCorner_Max = nzCorner_FarRightTop
};

#endif // NAZARA_ENUMS_MATH_HPP
<commit_msg>Fixed Corner_Max<commit_after>// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Mathematics module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#pragma once

#ifndef NAZARA_ENUMS_MATH_HPP
#define NAZARA_ENUMS_MATH_HPP

enum nzCorner
{
	nzCorner_FarLeftBottom,
	nzCorner_FarLeftTop,
	nzCorner_FarRightBottom,
	nzCorner_FarRightTop,
	nzCorner_NearLeftBottom,
	nzCorner_NearLeftTop,
	nzCorner_NearRightBottom,
	nzCorner_NearRightTop,

	nzCorner_Max = nzCorner_NearRightTop
};

#endif // NAZARA_ENUMS_MATH_HPP
<|endoftext|>


<commit_before>#pragma once

// std
#include <map>

// project
#include "Section.hpp"
#include "Type.hpp"

namespace dai
{
namespace bootloader
{

// Memory section structure
struct Structure {
    Structure() = default;
    std::map<Section, long> offset, size;
protected:
    Structure(decltype(offset) a, decltype(size) b) : offset(a), size(b) {}
};

// Structure
struct NetworkBootloaderStructure : Structure {

    constexpr static long HEADER_OFFSET = 0;
    constexpr static long HEADER_SIZE = 512;
    constexpr static long CONFIG_SIZE = 16 * 1024;
    constexpr static long BOOTLOADER_OFFSET = HEADER_OFFSET + HEADER_SIZE;
    constexpr static long BOOTLOADER_SIZE = 8 * 1024 * 1024 - CONFIG_SIZE - HEADER_SIZE;
    constexpr static long CONFIG_OFFSET = BOOTLOADER_OFFSET + BOOTLOADER_SIZE;
    constexpr static long APPLICATION_OFFSET = CONFIG_OFFSET + CONFIG_SIZE;

    NetworkBootloaderStructure() : Structure({
        {Section::HEADER, HEADER_OFFSET},
        {Section::BOOTLOADER_CONFIG, CONFIG_OFFSET},
        {Section::BOOTLOADER, BOOTLOADER_OFFSET},
        {Section::APPLICATION, APPLICATION_OFFSET},
    }, {
        {Section::HEADER, HEADER_SIZE},
        {Section::BOOTLOADER_CONFIG, CONFIG_SIZE},
        {Section::BOOTLOADER, BOOTLOADER_SIZE},
        {Section::APPLICATION, 0},
    }) {}

};

// Structure
struct UsbBootloaderStructure : Structure {

    constexpr static long HEADER_OFFSET = 0;
    constexpr static long HEADER_SIZE = 512;
    constexpr static long CONFIG_SIZE = 16 * 1024;
    constexpr static long BOOTLOADER_OFFSET = HEADER_OFFSET + HEADER_SIZE;
    constexpr static long BOOTLOADER_SIZE = 1 * 1024 * 1024 - CONFIG_SIZE - HEADER_SIZE;
    constexpr static long CONFIG_OFFSET = BOOTLOADER_OFFSET + BOOTLOADER_SIZE;
    constexpr static long APPLICATION_OFFSET = CONFIG_OFFSET + CONFIG_SIZE;

    UsbBootloaderStructure() : Structure({
        {Section::HEADER, HEADER_OFFSET},
        {Section::BOOTLOADER_CONFIG, CONFIG_OFFSET},
        {Section::BOOTLOADER, BOOTLOADER_OFFSET},
        {Section::APPLICATION, APPLICATION_OFFSET},
    }, {
        {Section::HEADER, HEADER_SIZE},
        {Section::BOOTLOADER_CONFIG, CONFIG_SIZE},
        {Section::BOOTLOADER, BOOTLOADER_SIZE},
        {Section::APPLICATION, 0},
    }) {}

};

inline const Structure getStructure(Type type){
    switch(type){
        case Type::AUTO: throw std::invalid_argument("Invalid argument to getStructure function");
        case Type::USB: return UsbBootloaderStructure();
        case Type::NETWORK: return NetworkBootloaderStructure();
    }
    // Default
    return UsbBootloaderStructure();
}

} // namespace bootloader
} // namespace dai

<commit_msg>Added missing header to Structure<commit_after>#pragma once

// std
#include <map>
#include <stdexcept>

// project
#include "Section.hpp"
#include "Type.hpp"

namespace dai
{
namespace bootloader
{

// Memory section structure
struct Structure {
    Structure() = default;
    std::map<Section, long> offset, size;
protected:
    Structure(decltype(offset) a, decltype(size) b) : offset(a), size(b) {}
};

// Structure
struct NetworkBootloaderStructure : Structure {

    constexpr static long HEADER_OFFSET = 0;
    constexpr static long HEADER_SIZE = 512;
    constexpr static long CONFIG_SIZE = 16 * 1024;
    constexpr static long BOOTLOADER_OFFSET = HEADER_OFFSET + HEADER_SIZE;
    constexpr static long BOOTLOADER_SIZE = 8 * 1024 * 1024 - CONFIG_SIZE - HEADER_SIZE;
    constexpr static long CONFIG_OFFSET = BOOTLOADER_OFFSET + BOOTLOADER_SIZE;
    constexpr static long APPLICATION_OFFSET = CONFIG_OFFSET + CONFIG_SIZE;

    NetworkBootloaderStructure() : Structure({
        {Section::HEADER, HEADER_OFFSET},
        {Section::BOOTLOADER_CONFIG, CONFIG_OFFSET},
        {Section::BOOTLOADER, BOOTLOADER_OFFSET},
        {Section::APPLICATION, APPLICATION_OFFSET},
    }, {
        {Section::HEADER, HEADER_SIZE},
        {Section::BOOTLOADER_CONFIG, CONFIG_SIZE},
        {Section::BOOTLOADER, BOOTLOADER_SIZE},
        {Section::APPLICATION, 0},
    }) {}

};

// Structure
struct UsbBootloaderStructure : Structure {

    constexpr static long HEADER_OFFSET = 0;
    constexpr static long HEADER_SIZE = 512;
    constexpr static long CONFIG_SIZE = 16 * 1024;
    constexpr static long BOOTLOADER_OFFSET = HEADER_OFFSET + HEADER_SIZE;
    constexpr static long BOOTLOADER_SIZE = 1 * 1024 * 1024 - CONFIG_SIZE - HEADER_SIZE;
    constexpr static long CONFIG_OFFSET = BOOTLOADER_OFFSET + BOOTLOADER_SIZE;
    constexpr static long APPLICATION_OFFSET = CONFIG_OFFSET + CONFIG_SIZE;

    UsbBootloaderStructure() : Structure({
        {Section::HEADER, HEADER_OFFSET},
        {Section::BOOTLOADER_CONFIG, CONFIG_OFFSET},
        {Section::BOOTLOADER, BOOTLOADER_OFFSET},
        {Section::APPLICATION, APPLICATION_OFFSET},
    }, {
        {Section::HEADER, HEADER_SIZE},
        {Section::BOOTLOADER_CONFIG, CONFIG_SIZE},
        {Section::BOOTLOADER, BOOTLOADER_SIZE},
        {Section::APPLICATION, 0},
    }) {}

};

inline const Structure getStructure(Type type){
    switch(type){
        case Type::AUTO: throw std::invalid_argument("Invalid argument to getStructure function");
        case Type::USB: return UsbBootloaderStructure();
        case Type::NETWORK: return NetworkBootloaderStructure();
    }
    // Default
    return UsbBootloaderStructure();
}

} // namespace bootloader
} // namespace dai

<|endoftext|>


<commit_before>#include <opencv2/highgui.hpp>  // for imshow
#include <opencv2/imgproc.hpp>  // for blur, dilation, erosion
#include <opencv2/video.hpp>    // for backgroundsubtractor
#include <opencv2/videoio.hpp>  // for videocapture

#include <iostream>

void show(std::string title, const cv::Mat& image) {
  cv::imshow(title.c_str(), image);
  char c = static_cast<char>(cv::waitKey(1));
  if (c == 27) exit(0);
}

const auto learning_rate_divider = 10000;

void subtract(cv::Ptr<cv::BackgroundSubtractor> pMOG2, cv::Mat* image,
              cv::Mat* background, int learning_rate) {
  auto rate = learning_rate / static_cast<double>(learning_rate_divider);
  if (learning_rate <= 0) {
    rate = -1.0;
  }
  pMOG2->apply(*image, *background, rate);
}

void blur(cv::Mat* input_output, int blur_size) {
  if (blur_size <= 0) {
    return;
  }
  cv::blur(*input_output, *input_output, cv::Size(blur_size, blur_size));
}

void erode(cv::Mat* input_output, int erosion_size) {
  if (erosion_size <= 0) {
    return;
  }
  int erosion_type = cv::MORPH_RECT;
  cv::Mat element = cv::getStructuringElement(
      erosion_type, cv::Size(2 * erosion_size, 2 * erosion_size),
      cv::Point(erosion_size, erosion_size));
  cv::erode(*input_output, *input_output, element);
}

void dilate(cv::Mat* input_output, int dilation_size) {
  if (dilation_size <= 0) {
    return;
  }
  int dilation_type = cv::MORPH_RECT;
  cv::Mat element = cv::getStructuringElement(
      dilation_type, cv::Size(2 * dilation_size, 2 * dilation_size),
      cv::Point(dilation_size, dilation_size));
  cv::dilate(*input_output, *input_output, element);
}

cv::Point2f findContourMiddle(const std::vector<cv::Point>& contour) {
  /// Get the moments
  cv::Moments moments = cv::moments(contour, false);
  if (moments.m00 == 0) {
    return cv::Point2f(-1, -1);
  }

  ///  Get the mass centers:
  cv::Point2f mc =
      cv::Point2f(moments.m10 / moments.m00, moments.m01 / moments.m00);
  return mc;
}

void findContours(const cv::Mat& image, int camera_number) {
  cv::Mat canny_output;
  std::vector<std::vector<cv::Point> > contours;
  std::vector<cv::Vec4i> hierarchy;

  /// Find contours
  cv::findContours(image, contours, hierarchy, cv::RETR_TREE,
                   cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));

  if (contours.size() < 1) {
    return;
  }

  cv::Mat drawing = cv::Mat::zeros(image.size(), CV_8UC3);

  int index = 0;
  double biggest_area = 0.0;
  for (size_t i = 0; i < contours.size(); i++) {
    auto area = cv::contourArea(contours[i]);
    if (area > biggest_area) {
      index = i;
      biggest_area = area;
    }
  }

  auto middle = findContourMiddle(contours[index]);
  std::cout << camera_number << ":" << static_cast<int>(middle.x) << ","
            << static_cast<int>(middle.y) << std::endl;

  cv::Scalar color = cv::Scalar(255, 255, 255);
  cv::drawContours(drawing, contours, index, color, 2, 8, hierarchy, 0,
                   cv::Point());
  show("contours", drawing);
}

int thread(int camera_number) {
  cv::Mat background;                       // background image
  cv::Ptr<cv::BackgroundSubtractor> pMOG2;  // MOG2 Background subtractor
  int blur_size = 10;
  int erosion_size = 10;
  int dilation_size = 10;
  int learning_rate = 0;

  const int bg_history = 500;
  const int threshold = 16;          // default value
  const bool detectShadows = false;  // non-default

  pMOG2 =
      cv::createBackgroundSubtractorMOG2(bg_history, threshold, detectShadows);

  auto capture = cv::VideoCapture(camera_number);
  std::string control_window_name = "control" + std::to_string(camera_number);
  cv::namedWindow(control_window_name);
  cv::createTrackbar("blur", control_window_name, &blur_size, 20);
  cv::createTrackbar("erosion", control_window_name, &erosion_size, 20);
  cv::createTrackbar("dilation", control_window_name, &dilation_size, 20);
  cv::createTrackbar("learning rate", control_window_name, &learning_rate,
                     learning_rate_divider);

  std::cerr << camera_number << " started\n";
  while (1) {
    cv::Mat image;
    if (!capture.read(image) || image.empty()) {
      continue;
    }
    blur(&image, blur_size);
    erode(&image, erosion_size);
    dilate(&image, dilation_size);
    subtract(pMOG2, &image, &background, learning_rate);
    findContours(background, camera_number);
    show("transformed" + std::to_string(camera_number), background);
  }
}

int main(void) { thread(0); }
<commit_msg>Default learning rate of 5<commit_after>#include <iostream>
#include <opencv2/highgui.hpp>  // for imshow
#include <opencv2/imgproc.hpp>  // for blur, dilation, erosion
#include <opencv2/video.hpp>    // for backgroundsubtractor
#include <opencv2/videoio.hpp>  // for videocapture

void show(std::string title, const cv::Mat& image) {
  cv::imshow(title.c_str(), image);
  char c = static_cast<char>(cv::waitKey(1));
  if (c == 27) exit(0);
}

const auto learning_rate_divider = 10000;

void subtract(cv::Ptr<cv::BackgroundSubtractor> pMOG2, cv::Mat* image,
              cv::Mat* background, int learning_rate) {
  auto rate = learning_rate / static_cast<double>(learning_rate_divider);
  if (learning_rate <= 0) {
    rate = -1.0;
  }
  pMOG2->apply(*image, *background, rate);
}

void blur(cv::Mat* input_output, int blur_size) {
  if (blur_size <= 0) {
    return;
  }
  cv::blur(*input_output, *input_output, cv::Size(blur_size, blur_size));
}

void erode(cv::Mat* input_output, int erosion_size) {
  if (erosion_size <= 0) {
    return;
  }
  int erosion_type = cv::MORPH_RECT;
  cv::Mat element = cv::getStructuringElement(
      erosion_type, cv::Size(2 * erosion_size, 2 * erosion_size),
      cv::Point(erosion_size, erosion_size));
  cv::erode(*input_output, *input_output, element);
}

void dilate(cv::Mat* input_output, int dilation_size) {
  if (dilation_size <= 0) {
    return;
  }
  int dilation_type = cv::MORPH_RECT;
  cv::Mat element = cv::getStructuringElement(
      dilation_type, cv::Size(2 * dilation_size, 2 * dilation_size),
      cv::Point(dilation_size, dilation_size));
  cv::dilate(*input_output, *input_output, element);
}

cv::Point2f findContourMiddle(const std::vector<cv::Point>& contour) {
  /// Get the moments
  cv::Moments moments = cv::moments(contour, false);
  if (moments.m00 == 0) {
    return cv::Point2f(-1, -1);
  }

  ///  Get the mass centers:
  cv::Point2f mc =
      cv::Point2f(moments.m10 / moments.m00, moments.m01 / moments.m00);
  return mc;
}

void findContours(const cv::Mat& image, int camera_number) {
  cv::Mat canny_output;
  std::vector<std::vector<cv::Point> > contours;
  std::vector<cv::Vec4i> hierarchy;

  /// Find contours
  cv::findContours(image, contours, hierarchy, cv::RETR_TREE,
                   cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));

  if (contours.size() < 1) {
    return;
  }

  cv::Mat drawing = cv::Mat::zeros(image.size(), CV_8UC3);

  int index = 0;
  double biggest_area = 0.0;
  for (size_t i = 0; i < contours.size(); i++) {
    auto area = cv::contourArea(contours[i]);
    if (area > biggest_area) {
      index = i;
      biggest_area = area;
    }
  }

  auto middle = findContourMiddle(contours[index]);
  std::cout << camera_number << ":" << static_cast<int>(middle.x) << ","
            << static_cast<int>(middle.y) << std::endl;

  cv::Scalar color = cv::Scalar(255, 255, 255);
  cv::drawContours(drawing, contours, index, color, 2, 8, hierarchy, 0,
                   cv::Point());
  show("contours", drawing);
}

int thread(int camera_number) {
  cv::Mat background;                       // background image
  cv::Ptr<cv::BackgroundSubtractor> pMOG2;  // MOG2 Background subtractor
  int blur_size = 10;
  int erosion_size = 10;
  int dilation_size = 10;
  int learning_rate = 50;

  const int bg_history = 500;
  const int threshold = 16;          // default value
  const bool detectShadows = false;  // non-default

  pMOG2 =
      cv::createBackgroundSubtractorMOG2(bg_history, threshold, detectShadows);

  auto capture = cv::VideoCapture(camera_number);
  std::string control_window_name = "control" + std::to_string(camera_number);
  cv::namedWindow(control_window_name);
  cv::createTrackbar("blur", control_window_name, &blur_size, 20);
  cv::createTrackbar("erosion", control_window_name, &erosion_size, 20);
  cv::createTrackbar("dilation", control_window_name, &dilation_size, 20);
  cv::createTrackbar("learning rate", control_window_name, &learning_rate,
                     learning_rate_divider);

  std::cerr << camera_number << " started\n";
  while (1) {
    cv::Mat image;
    if (!capture.read(image) || image.empty()) {
      continue;
    }
    blur(&image, blur_size);
    erode(&image, erosion_size);
    dilate(&image, dilation_size);
    subtract(pMOG2, &image, &background, learning_rate);
    findContours(background, camera_number);
    show("transformed" + std::to_string(camera_number), background);
  }
}

int main(void) { thread(0); }
<|endoftext|>


<commit_before>#include <fstream>
#include <iomanip>
#include <string>

#ifndef LOG_HPP
#define LOG_HPP

#define LOG( log, message )                            \
    (log).logMessage(                                  \
        static_cast<std::ostringstream&>(              \
            std::ostringstream().flush() << (message)  \
        ).str()                                        \
    )

#define LOG_COND( log, cond, message )                 \
    if ( cond ) LOG( log, message )

namespace Log
{
    class Log
    {
        public:
            Log( const std::string& filename )
                : filename_( filename )
                , out_file_( filename, std::ios_base::out | std::ios_base::trunc )
            {
                time_t rawtime;
                tm * timeinfo;
                char buffer[80];

                time(&rawtime);
                timeinfo = localtime(&rawtime);

                strftime( buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo );

                out_file_ << buffer << std::endl;
            }

            /** Copy constructor */
            Log( const Log& other )
                : filename_( other.filename_ )
                , out_file_( filename_, std::ios_base::out | std::ios_base::app )
            {
            }

            /** Move constructor */
            Log( Log&& other )
                : filename_( other.filename_ )
                , out_file_( filename_, std::ios_base::out | std::ios_base::app )
            {
                other.out_file_.close();
            }

            /** Destructor */
            ~Log()
            {
                if ( out_file_.is_open() )
                {
                    out_file_.close();
                }
            }

            /** Copy assignment operator */
            Log& operator= ( const Log& other )
            {
                Log tmp( other ); // re-use copy-constructor
                *this = std::move( tmp ); // re-use move-assignment
                return *this;
            }

            /** Move assignment operator */
            Log& operator= ( Log&& other)
            {
                std::swap( filename_, other.filename_ );
                other.out_file_.close();

                if ( out_file_.is_open() )
                {
                    out_file_.close();
                }

                out_file_.open( filename_, std::ios_base::out | std::ios_base::app );

                return *this;
            }

            void logMessage( const std::string& message )
            {
                out_file_ << message << std::endl;
            }

        private:
            std::string filename_;
            std::ofstream out_file_;
    };
}

#endif // LOG_HPP
<commit_msg>Added a TODO in recognition of the fact that this file is both poorly commented, and has not been reviewed.<commit_after>#include <fstream>
#include <iomanip>
#include <string>

#ifndef LOG_HPP
#define LOG_HPP

#define LOG( log, message )                            \
    (log).logMessage(                                  \
        static_cast<std::ostringstream&>(              \
            std::ostringstream().flush() << (message)  \
        ).str()                                        \
    )

#define LOG_COND( log, cond, message )                 \
    if ( cond ) LOG( log, message )

// TODO: confirm that I havn't made any mistakes in this file
namespace Log
{
    class Log
    {
        public:
            Log( const std::string& filename )
                : filename_( filename )
                , out_file_( filename, std::ios_base::out | std::ios_base::trunc )
            {
                time_t rawtime;
                tm * timeinfo;
                char buffer[80];

                time(&rawtime);
                timeinfo = localtime(&rawtime);

                strftime( buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo );

                out_file_ << buffer << std::endl;
            }

            /** Copy constructor */
            Log( const Log& other )
                : filename_( other.filename_ )
                , out_file_( filename_, std::ios_base::out | std::ios_base::app )
            {
            }

            /** Move constructor */
            Log( Log&& other )
                : filename_( other.filename_ )
                , out_file_( filename_, std::ios_base::out | std::ios_base::app )
            {
                other.out_file_.close();
            }

            /** Destructor */
            ~Log()
            {
                if ( out_file_.is_open() )
                {
                    out_file_.close();
                }
            }

            /** Copy assignment operator */
            Log& operator= ( const Log& other )
            {
                Log tmp( other ); // re-use copy-constructor
                *this = std::move( tmp ); // re-use move-assignment
                return *this;
            }

            /** Move assignment operator */
            Log& operator= ( Log&& other)
            {
                std::swap( filename_, other.filename_ );
                other.out_file_.close();

                if ( out_file_.is_open() )
                {
                    out_file_.close();
                }

                out_file_.open( filename_, std::ios_base::out | std::ios_base::app );

                return *this;
            }

            void logMessage( const std::string& message )
            {
                out_file_ << message << std::endl;
            }

        private:
            std::string filename_;
            std::ofstream out_file_;
    };
}

#endif // LOG_HPP
<|endoftext|>


<commit_before>#ifndef CENTRALIZEDSIMULATIONMANAGER_HPP_
#define CENTRALIZEDSIMULATIONMANAGER_HPP_

#include "simulation_manager_impl.h"
#include "application.h"

#include "simulation_stats.h"
#include <map>
#include <deque>

using std::deque;
using std::map;
using std::pair;
using std::make_pair;
using std::swap;

template < class ES >
class CentralizedSimulationManager : public SimulationManager< ES > {
public:
    typedef pair< event::vtime_t, size_t > pair_time_offset;
    typedef pair< object *, pair_time_offset > pair_object_timestamp;
    typedef deque< pair_object_timestamp > object_handle_map_t;
    typedef deque< object * > object_group_t;
    typedef pair< event::vtime_t, object_group_t * > concurrent_group_t;
    typedef map< event::vtime_t, object_group_t * > ordered_object_exe_t;
    typedef typename ordered_object_exe_t::iterator _iterator;

    CentralizedSimulationManager( shared_ptr< application >, system_id::manager_id_t id = 0 );
    CentralizedSimulationManager( shared_ptr< application >, shared_ptr< SimulationStats >,  system_id::manager_id_t id = 0 );

    virtual const event::vtime_t & getSimulationTime() const;
    virtual bool  isSimulationComplete() const;

    virtual const system_id getNextObjectID();

    virtual void registerObject( object * obj );
    virtual void unregisterObject( object * obj );

    virtual size_t getObjectCount() const;
    virtual object * getObject( const system_id & id ) const;

    virtual void initialize();
    virtual void simulate( const event::vtime_t & until );
    virtual void finalize();

    virtual void routeEvent( const event * evt );
    virtual void notifyNextEvent( const system_id & obj, const event::vtime_t & t );

    virtual ~CentralizedSimulationManager();
protected:

    virtual concurrent_group_t getNextObjectGroup();

    virtual bool setSimulationTime( const event::vtime_t & t );
    virtual void setSimulateUntil( const event::vtime_t & t );

    void moveObject( object * obj, event::vtime_t t );

    shared_ptr< application >   m_app;

    event::vtime_t    m_sim_time;
    event::vtime_t    m_sim_until;
    bool m_sim_complete;

    object_handle_map_t m_objects;
    ordered_object_exe_t m_ordered_objs;

    unsigned int    m_nPendingEvents, m_nProcessedEvents;
    unsigned int    m_nRegisteredObjs;
    unsigned int    m_nUnregisterCalls;

    shared_ptr< SimulationStats > m_stats;
};

//
// Implementation
//

template < class ES >
CentralizedSimulationManager<ES>::CentralizedSimulationManager( shared_ptr< application > app, system_id::manager_id_t id ) :
    SimulationManager<ES>(id),
    m_app( app ),
    m_sim_time( SystemClock::ZERO ),
    m_sim_until( SystemClock::POSITIVE_INFINITY ),
    m_sim_complete(false),
    m_nPendingEvents(0),
    m_nProcessedEvents(0),
    m_nRegisteredObjs(0),
    m_nUnregisterCalls(0),
    m_stats( new SimulationStats() )
{}

template < class ES >
CentralizedSimulationManager<ES>::CentralizedSimulationManager( shared_ptr< application > app, shared_ptr< SimulationStats > stats, system_id::manager_id_t id ) :
    SimulationManager<ES>(id),
    m_app( app ),
    m_sim_time( SystemClock::ZERO ),
    m_sim_until( SystemClock::POSITIVE_INFINITY ),
    m_sim_complete(false),
    m_nPendingEvents(0),
    m_nProcessedEvents(0),
    m_nRegisteredObjs(0),
    m_nUnregisterCalls(0),
    m_stats( stats )
{}

template < class ES >
CentralizedSimulationManager<ES>::~CentralizedSimulationManager() {
    cout << m_nUnregisterCalls << " objects unregistered BEFORE destruction" << endl;
    unsigned int nUnfinalized = 0;
    while( !m_objects.empty() ) {
        object * tmp = m_objects.back().first;
        m_objects.pop_back();
        if( tmp ) {
            ++nUnfinalized;
            tmp->finalize();
            delete tmp;
        }
    }
    cout << nUnfinalized << " objects were finalized AFTER simulation finalization." << endl;
    m_ordered_objs.clear();
}

template < class ES >
const system_id CentralizedSimulationManager<ES>::getNextObjectID() {
    system_id nid( this->getManagerID(), m_objects.size() );
    m_objects.push_back( make_pair( (object *)NULL, make_pair(SystemClock::POSITIVE_INFINITY, 0 ) ) );
    return nid;
}

template< class ES >
void CentralizedSimulationManager<ES>::registerObject( object * obj ) {
    if( obj == NULL ) return;

    assert( obj->getSystemID() != this->m_id );

    if( m_objects[ obj->getObjectID() ].first == NULL ) {
        m_objects[ obj->getObjectID() ].first = obj;
        ++m_nRegisteredObjs;
    } else {
        moveObject( obj, SystemClock::POSITIVE_INFINITY );
    }
}

template< class ES >
void CentralizedSimulationManager<ES>::unregisterObject( object * obj ) {
    ++m_nUnregisterCalls;
    if( obj == NULL ) return;

    if( m_objects[ obj->getObjectID() ].first != NULL ) {
        m_nPendingEvents += obj->pendingEventCount(obj->getSystemID());
        m_nProcessedEvents += obj->processedEventCount(obj->getSystemID());

        if( m_objects[ obj->getObjectID() ].second.first != SystemClock::POSITIVE_INFINITY ) {
            moveObject( obj, SystemClock::POSITIVE_INFINITY );
        }

        m_objects[ obj->getObjectID() ].first = NULL;
        --m_nRegisteredObjs;
    }
}

template < class ES >
void CentralizedSimulationManager<ES>::moveObject( object * obj, event::vtime_t newT ) {
    pair_time_offset pto = m_objects[ obj->getObjectID() ].second;

    if( pto.first != SystemClock::POSITIVE_INFINITY ) {
        // objects with time set to POSITIVE_INFINITY are not "queued"
        _iterator it = m_ordered_objs.find( pto.first );

        if( it != m_ordered_objs.end() ) {
            object_group_t * g = it->second;

            assert( pto.second < g->size() &&  g->at( pto.second ) == obj );

            if( g->back() != obj ) {
                // object is not at the end of vector
                // swap with object at the end of the vector
                // and update that objects offset value to
                // be that of the current obj
                system_id other = g->back()->getSystemID();

                (*g)[ pto.second ] = g->back();
                g->back() = obj;

                assert( g->back() == obj );

                m_objects[ other.getObjectID() ].second.second = pto.second;
            }
            g->pop_back();
        }
    }

    m_objects[ obj->getObjectID() ].second.first = newT;
    if( newT != SystemClock::POSITIVE_INFINITY ) {
        _iterator it = m_ordered_objs.find( newT );
        if( it == m_ordered_objs.end() ) {
            // no other objects have events scheduled at newT
            pair< _iterator, bool > res = m_ordered_objs.insert( make_pair(newT, new object_group_t() ) );
            assert( res.second );
            it = res.first;
        }

        m_objects[ obj->getObjectID() ].second.second = it->second->size();
        it->second->push_back( obj );
    }
}

template< class ES >
size_t CentralizedSimulationManager<ES>::getObjectCount() const {
    return m_nRegisteredObjs;
}

template< class ES >
object * CentralizedSimulationManager<ES>::getObject( const system_id & id ) const {
    return m_objects[ id.getObjectID() ].first;
}

template< class ES >
void CentralizedSimulationManager<ES>::routeEvent( const event * evt ) {
    assert( m_objects.size() > evt->getReceiver().getObjectID() );
    m_objects[ evt->getReceiver().getObjectID() ].first->receiveEvent( evt );
}

template< class ES >
void CentralizedSimulationManager<ES>::notifyNextEvent( const system_id & obj, const event::vtime_t & t ) {
    moveObject( m_objects[ obj.getObjectID() ].first, t );
}

template< class ES >
typename CentralizedSimulationManager<ES>::concurrent_group_t CentralizedSimulationManager<ES>::getNextObjectGroup() {
    concurrent_group_t ot = *m_ordered_objs.begin();
    m_ordered_objs.erase( m_ordered_objs.begin() );

    return ot;
}

template< class ES >
void CentralizedSimulationManager<ES>::initialize() {
    m_stats->startPhase( INIT_PHASE_K );
    m_app->initialize();
    m_stats->stopPhase( INIT_PHASE_K );
}

template< class ES >
void CentralizedSimulationManager<ES>::simulate( const event::vtime_t & until ) {
    setSimulateUntil( until );

    m_stats->startPhase( SIMULATE_PHASE_K );
    while(! m_ordered_objs.empty() ) {
        concurrent_group_t ot = getNextObjectGroup();

        if( ot.first == SystemClock::POSITIVE_INFINITY || setSimulationTime( ot.first ) ) {
            break;
        }

//        for( object_group_t::iterator it = ot.second->begin(); it != ot.second->end(); it++ ) {
        while( !ot.second->empty() ) {
            object * obj = ot.second->back();
            ot.second->pop_back();

            m_objects[ obj->getObjectID() ].second.first = SystemClock::POSITIVE_INFINITY;
            obj->updateLocalTime(ot.first);
            obj->process();

            const event * e = obj->peekEvent( obj->getSystemID() );
            if( e != NULL ) {
                moveObject( obj, e->getReceived() );
            } else {
                moveObject( obj, SystemClock::POSITIVE_INFINITY );
            }
        }

        delete ot.second;
    }

    m_stats->stopPhase( SIMULATE_PHASE_K );

    cout << "End simulation time: " <<  getSimulationTime() << endl;
}

template< class ES >
void CentralizedSimulationManager<ES>::finalize() {
    m_stats->startPhase( FINALIZE_PHASE_K );

    m_app->finalize();

    m_stats->stopPhase( FINALIZE_PHASE_K );

    m_stats->setProcessedEvents( m_nProcessedEvents );
    m_stats->setPendingEvents( m_nPendingEvents );

}

template< class ES >
bool CentralizedSimulationManager<ES>::isSimulationComplete() const {
    return m_sim_complete;
}

template< class ES >
bool CentralizedSimulationManager<ES>::setSimulationTime( const event::vtime_t & t ) {
    assert( m_sim_time <= t );
    if( m_sim_time != t ) {
        m_sim_time = t;
        m_sim_complete = (m_sim_time >= m_sim_until);
    }

    return m_sim_complete;
}

template< class ES >
void CentralizedSimulationManager<ES>::setSimulateUntil( const event::vtime_t & t ) {
    m_sim_until = t;
}

template< class ES >
const event::vtime_t & CentralizedSimulationManager<ES>::getSimulationTime() const {
    return m_sim_time;
}
#endif  // CENTRALIZEDSIMULATIONMANAGER_HPP_
<commit_msg>Went back to vector container for object_group_t, instead of deque. The vector seems to offer slightly better performance<commit_after>#ifndef CENTRALIZEDSIMULATIONMANAGER_HPP_
#define CENTRALIZEDSIMULATIONMANAGER_HPP_

#include "simulation_manager_impl.h"
#include "application.h"

#include "simulation_stats.h"
#include <map>
#include <deque>

using std::deque;
using std::map;
using std::pair;
using std::make_pair;
using std::swap;

template < class ES >
class CentralizedSimulationManager : public SimulationManager< ES > {
public:
    typedef pair< event::vtime_t, size_t > pair_time_offset;
    typedef pair< object *, pair_time_offset > pair_object_timestamp;
    typedef deque< pair_object_timestamp > object_handle_map_t;
    typedef vector< object * > object_group_t;
    typedef pair< event::vtime_t, object_group_t * > concurrent_group_t;
    typedef map< event::vtime_t, object_group_t * > ordered_object_exe_t;
    typedef typename ordered_object_exe_t::iterator _iterator;

    CentralizedSimulationManager( shared_ptr< application >, system_id::manager_id_t id = 0 );
    CentralizedSimulationManager( shared_ptr< application >, shared_ptr< SimulationStats >,  system_id::manager_id_t id = 0 );

    virtual const event::vtime_t & getSimulationTime() const;
    virtual bool  isSimulationComplete() const;

    virtual const system_id getNextObjectID();

    virtual void registerObject( object * obj );
    virtual void unregisterObject( object * obj );

    virtual size_t getObjectCount() const;
    virtual object * getObject( const system_id & id ) const;

    virtual void initialize();
    virtual void simulate( const event::vtime_t & until );
    virtual void finalize();

    virtual void routeEvent( const event * evt );
    virtual void notifyNextEvent( const system_id & obj, const event::vtime_t & t );

    virtual ~CentralizedSimulationManager();
protected:

    virtual concurrent_group_t getNextObjectGroup();

    virtual bool setSimulationTime( const event::vtime_t & t );
    virtual void setSimulateUntil( const event::vtime_t & t );

    void moveObject( object * obj, event::vtime_t t );

    shared_ptr< application >   m_app;

    event::vtime_t    m_sim_time;
    event::vtime_t    m_sim_until;
    bool m_sim_complete;

    object_handle_map_t m_objects;
    ordered_object_exe_t m_ordered_objs;

    unsigned int    m_nPendingEvents, m_nProcessedEvents;
    unsigned int    m_nRegisteredObjs;
    unsigned int    m_nUnregisterCalls;

    shared_ptr< SimulationStats > m_stats;
};

//
// Implementation
//

template < class ES >
CentralizedSimulationManager<ES>::CentralizedSimulationManager( shared_ptr< application > app, system_id::manager_id_t id ) :
    SimulationManager<ES>(id),
    m_app( app ),
    m_sim_time( SystemClock::ZERO ),
    m_sim_until( SystemClock::POSITIVE_INFINITY ),
    m_sim_complete(false),
    m_nPendingEvents(0),
    m_nProcessedEvents(0),
    m_nRegisteredObjs(0),
    m_nUnregisterCalls(0),
    m_stats( new SimulationStats() )
{}

template < class ES >
CentralizedSimulationManager<ES>::CentralizedSimulationManager( shared_ptr< application > app, shared_ptr< SimulationStats > stats, system_id::manager_id_t id ) :
    SimulationManager<ES>(id),
    m_app( app ),
    m_sim_time( SystemClock::ZERO ),
    m_sim_until( SystemClock::POSITIVE_INFINITY ),
    m_sim_complete(false),
    m_nPendingEvents(0),
    m_nProcessedEvents(0),
    m_nRegisteredObjs(0),
    m_nUnregisterCalls(0),
    m_stats( stats )
{}

template < class ES >
CentralizedSimulationManager<ES>::~CentralizedSimulationManager() {
    cout << m_nUnregisterCalls << " objects unregistered BEFORE destruction" << endl;
    unsigned int nUnfinalized = 0;
    while( !m_objects.empty() ) {
        object * tmp = m_objects.back().first;
        m_objects.pop_back();
        if( tmp ) {
            ++nUnfinalized;
            tmp->finalize();
            delete tmp;
        }
    }
    cout << nUnfinalized << " objects were finalized AFTER simulation finalization." << endl;
    m_ordered_objs.clear();
}

template < class ES >
const system_id CentralizedSimulationManager<ES>::getNextObjectID() {
    system_id nid( this->getManagerID(), m_objects.size() );
    m_objects.push_back( make_pair( (object *)NULL, make_pair(SystemClock::POSITIVE_INFINITY, 0 ) ) );
    return nid;
}

template< class ES >
void CentralizedSimulationManager<ES>::registerObject( object * obj ) {
    if( obj == NULL ) return;

    assert( obj->getSystemID() != this->m_id );

    if( m_objects[ obj->getObjectID() ].first == NULL ) {
        m_objects[ obj->getObjectID() ].first = obj;
        ++m_nRegisteredObjs;
    } else {
        moveObject( obj, SystemClock::POSITIVE_INFINITY );
    }
}

template< class ES >
void CentralizedSimulationManager<ES>::unregisterObject( object * obj ) {
    ++m_nUnregisterCalls;
    if( obj == NULL ) return;

    if( m_objects[ obj->getObjectID() ].first != NULL ) {
        m_nPendingEvents += obj->pendingEventCount(obj->getSystemID());
        m_nProcessedEvents += obj->processedEventCount(obj->getSystemID());

        if( m_objects[ obj->getObjectID() ].second.first != SystemClock::POSITIVE_INFINITY ) {
            moveObject( obj, SystemClock::POSITIVE_INFINITY );
        }

        m_objects[ obj->getObjectID() ].first = NULL;
        --m_nRegisteredObjs;
    }
}

template < class ES >
void CentralizedSimulationManager<ES>::moveObject( object * obj, event::vtime_t newT ) {
    pair_time_offset pto = m_objects[ obj->getObjectID() ].second;

    if( pto.first != SystemClock::POSITIVE_INFINITY ) {
        // objects with time set to POSITIVE_INFINITY are not "queued"
        _iterator it = m_ordered_objs.find( pto.first );

        if( it != m_ordered_objs.end() ) {
            object_group_t * g = it->second;

            assert( pto.second < g->size() &&  g->at( pto.second ) == obj );

            if( g->back() != obj ) {
                // object is not at the end of vector
                // swap with object at the end of the vector
                // and update that objects offset value to
                // be that of the current obj
                system_id other = g->back()->getSystemID();

                (*g)[ pto.second ] = g->back();
                g->back() = obj;

                assert( g->back() == obj );

                m_objects[ other.getObjectID() ].second.second = pto.second;
            }
            g->pop_back();
        }
    }

    m_objects[ obj->getObjectID() ].second.first = newT;
    if( newT != SystemClock::POSITIVE_INFINITY ) {
        _iterator it = m_ordered_objs.find( newT );
        if( it == m_ordered_objs.end() ) {
            // no other objects have events scheduled at newT
            pair< _iterator, bool > res = m_ordered_objs.insert( make_pair(newT, new object_group_t() ) );
            assert( res.second );
            it = res.first;

//            it->second->reserve( m_nRegisteredObjs );
        }

        m_objects[ obj->getObjectID() ].second.second = it->second->size();
        it->second->push_back( obj );
    }
}

template< class ES >
size_t CentralizedSimulationManager<ES>::getObjectCount() const {
    return m_nRegisteredObjs;
}

template< class ES >
object * CentralizedSimulationManager<ES>::getObject( const system_id & id ) const {
    return m_objects[ id.getObjectID() ].first;
}

template< class ES >
void CentralizedSimulationManager<ES>::routeEvent( const event * evt ) {
    assert( m_objects.size() > evt->getReceiver().getObjectID() );
    m_objects[ evt->getReceiver().getObjectID() ].first->receiveEvent( evt );
}

template< class ES >
void CentralizedSimulationManager<ES>::notifyNextEvent( const system_id & obj, const event::vtime_t & t ) {
    moveObject( m_objects[ obj.getObjectID() ].first, t );
}

template< class ES >
typename CentralizedSimulationManager<ES>::concurrent_group_t CentralizedSimulationManager<ES>::getNextObjectGroup() {
    concurrent_group_t ot = *m_ordered_objs.begin();
    m_ordered_objs.erase( m_ordered_objs.begin() );

    return ot;
}

template< class ES >
void CentralizedSimulationManager<ES>::initialize() {
    m_stats->startPhase( INIT_PHASE_K );
    m_app->initialize();
    m_stats->stopPhase( INIT_PHASE_K );
}

template< class ES >
void CentralizedSimulationManager<ES>::simulate( const event::vtime_t & until ) {
    setSimulateUntil( until );

    m_stats->startPhase( SIMULATE_PHASE_K );
    while(! m_ordered_objs.empty() ) {
        concurrent_group_t ot = getNextObjectGroup();

        if( ot.first == SystemClock::POSITIVE_INFINITY || setSimulationTime( ot.first ) ) {
            break;
        }

//        for( object_group_t::iterator it = ot.second->begin(); it != ot.second->end(); it++ ) {
        while( !ot.second->empty() ) {
            object * obj = ot.second->back();
            ot.second->pop_back();

            m_objects[ obj->getObjectID() ].second.first = SystemClock::POSITIVE_INFINITY;
            obj->updateLocalTime(ot.first);
            obj->process();

            const event * e = obj->peekEvent( obj->getSystemID() );
            if( e != NULL ) {
                moveObject( obj, e->getReceived() );
            } else {
                moveObject( obj, SystemClock::POSITIVE_INFINITY );
            }
        }

        delete ot.second;
    }

    m_stats->stopPhase( SIMULATE_PHASE_K );

    cout << "End simulation time: " <<  getSimulationTime() << endl;
}

template< class ES >
void CentralizedSimulationManager<ES>::finalize() {
    m_stats->startPhase( FINALIZE_PHASE_K );

    m_app->finalize();

    m_stats->stopPhase( FINALIZE_PHASE_K );

    m_stats->setProcessedEvents( m_nProcessedEvents );
    m_stats->setPendingEvents( m_nPendingEvents );

}

template< class ES >
bool CentralizedSimulationManager<ES>::isSimulationComplete() const {
    return m_sim_complete;
}

template< class ES >
bool CentralizedSimulationManager<ES>::setSimulationTime( const event::vtime_t & t ) {
    assert( m_sim_time <= t );
    if( m_sim_time != t ) {
        m_sim_time = t;
        m_sim_complete = (m_sim_time >= m_sim_until);
    }

    return m_sim_complete;
}

template< class ES >
void CentralizedSimulationManager<ES>::setSimulateUntil( const event::vtime_t & t ) {
    m_sim_until = t;
}

template< class ES >
const event::vtime_t & CentralizedSimulationManager<ES>::getSimulationTime() const {
    return m_sim_time;
}
#endif  // CENTRALIZEDSIMULATIONMANAGER_HPP_
<|endoftext|>


<commit_before>/**
 * \file macros.hpp
 *
 * \brief TODO: Add description
 *
 * \author Matthew Rodusek (matthew.rodusek@gmail.com)
 */
#ifndef BIT_MEMORY_MACROS_HPP
#define BIT_MEMORY_MACROS_HPP

#ifdef BIT_MEMORY_LIKELY
#error BIT_MEMORY_LIKELY cannot be defined outside of macros.hpp
#endif

#ifdef BIT_MEMORY_UNLIKELY
#error BIT_MEMORY_UNLIKELY cannot be defined outside of macros.hpp
#endif

#ifdef BIT_MEMORY_ASSUME
#error BIT_MEMORY_ASSUME cannot be defined outside of macros.hpp
#endif

#ifdef __GNUC__
#define BIT_MEMORY_LIKELY(x) __builtin_expect(!!(x),1)
#else
#define BIT_MEMORY_LIKELY(x) x
#endif

#ifdef __GNUC__
#define BIT_MEMORY_UNLIKELY(x) __builtin_expect(!!(x),0)
#else
#define BIT_MEMORY_UNLIKELY(x) x
#endif

#if defined(__clang__)
#define BIT_MEMORY_ASSUME(x) __builtin_assume(x)
#elif defined(_MSC_VER)
#define BIT_MEMORY_ASSUME(x) __assume(x)
#else
#define BIT_MEMORY_ASSUME(x) x
#endif

#endif /* BIT_MEMORY_MACROS_HPP */
<commit_msg>Added 'BIT_MEMORY_UNUSED' macro<commit_after>/**
 * \file macros.hpp
 *
 * \brief TODO: Add description
 *
 * \author Matthew Rodusek (matthew.rodusek@gmail.com)
 */
#ifndef BIT_MEMORY_MACROS_HPP
#define BIT_MEMORY_MACROS_HPP

#ifdef BIT_MEMORY_LIKELY
#error BIT_MEMORY_LIKELY cannot be defined outside of macros.hpp
#endif

#ifdef BIT_MEMORY_UNLIKELY
#error BIT_MEMORY_UNLIKELY cannot be defined outside of macros.hpp
#endif

#ifdef BIT_MEMORY_ASSUME
#error BIT_MEMORY_ASSUME cannot be defined outside of macros.hpp
#endif

#ifdef BIT_MEMORY_UNUSED
#error BIT_MEMORY_UNUSED cannot be defined outside of macros.hpp
#endif

#ifdef __GNUC__
#define BIT_MEMORY_LIKELY(x) __builtin_expect(!!(x),1)
#else
#define BIT_MEMORY_LIKELY(x) x
#endif

#ifdef __GNUC__
#define BIT_MEMORY_UNLIKELY(x) __builtin_expect(!!(x),0)
#else
#define BIT_MEMORY_UNLIKELY(x) x
#endif

#if defined(__clang__)
#define BIT_MEMORY_ASSUME(x) __builtin_assume(x)
#elif defined(_MSC_VER)
#define BIT_MEMORY_ASSUME(x) __assume(x)
#else
#define BIT_MEMORY_ASSUME(x) x
#endif

#define BIT_MEMORY_UNUSED(x) (void) x

#endif /* BIT_MEMORY_MACROS_HPP */
<|endoftext|>