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

#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <unordered_map>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include "assert.hpp"
#include "Options.hpp"

using namespace eddic;

namespace po = boost::program_options;

struct ConfigValue {
    bool defined;
    boost::any value;
};

struct Configuration {
    std::unordered_map<std::string, ConfigValue> values;
};

std::shared_ptr<Configuration> configuration;
std::unordered_map<std::string, std::vector<std::string>> triggers;

bool desc_init = false;
po::options_description visible("Usage : eddic [options] source.eddi");
po::options_description all("Usage : eddic [options] source.eddi");

std::pair<std::string, std::string> numeric_parser(const std::string& s){
    if (s.find("-32") == 0) {
        return make_pair("32", std::string("true"));
    } else if (s.find("-64") == 0) {
        return make_pair("64", std::string("true"));
    } else {
        return make_pair(std::string(), std::string());
    }
}

void add_trigger(const std::string& option, std::vector<std::string> childs){
   triggers[option] = childs;
}

inline void trigger_childs(const std::vector<std::string>& childs){
    for(auto& child : childs){
        configuration->values[child].defined = true;
        configuration->values[child].value = std::string("true");
    }
}

bool eddic::parseOptions(int argc, const char* argv[]) {
    try {
        //Only if the description has not been already defined
        if(!desc_init){
            po::options_description general("General options");
            general.add_options()
                ("help,h", "Generate this help message")
                ("assembly,S", "Generate only the assembly")
                ("keep,k", "Keep the assembly file")
                ("version", "Print the version of eddic")
                ("output,o", po::value<std::string>()->default_value("a.out"), "Set the name of the executable")

                ("debug,g", "Add debugging symbols")

                ("32", "Force the compilation for 32 bits platform")
                ("64", "Force the compilation for 64 bits platform")

                ("warning-all", "Enable all the warning messages")
                ("warning-unused", "Warn about unused variables, parameters and functions")
                ("warning-cast", "Warn about useless casts");

            po::options_description display("Display options");
            display.add_options()
                ("ast", "Print the Abstract Syntax Tree representation of the source")
                ("ast-only", "Only print the Abstract Syntax Tree representation of the source (do not continue compilation after printing)")

                ("mtac", "Print the medium-level Three Address Code representation of the source")
                ("mtac-opt", "Print the medium-level Three Address Code representation of the source before any optimization has been performed")
                ("mtac-only", "Only print the medium-level Three Address Code representation of the source (do not continue compilation after printing)")

                ("ltac", "Print the low-level Three Address Code representation of the source")
                ("ltac-only", "Only print the low-level Three Address Code representation of the source (do not continue compilation after printing)");

            po::options_description optimization("Optimization options");
            optimization.add_options()
                ("Opt,O", po::value<int>()->implicit_value(0), "Define the optimization level")
                ("O0", "Disable all optimizations")
                ("O1", "Enable low-level optimizations")
                ("O2", "Enable all optimizations. This can be slow for big programs.")

                ("fglobal-optimization", "Enable optimizer engine")
                ("fpeephole-optimization", "Enable peephole optimizer")
                ("fno-inline-functions", "Disable inlining");

            po::options_description backend("Backend options");
            backend.add_options()
                ("quiet,q", "Do not print anything")
                ("verbose,v", "Make the compiler verbose")
                ("dev,d", "Activate development mode (very verbose)")
                ("perfs", "Display performance information")
                ("input", po::value<std::string>(), "Input file");

            all.add(general).add(display).add(optimization).add(backend);
            visible.add(general).add(display).add(optimization);

            add_trigger("warning-all", {"warning-unused", "warning-cast"});

            //TODO Should be a better way to do that
            add_trigger("__1", {"fpeephole-optimization"});
            add_trigger("__2", {"fglobal-optimization"});

            desc_init = true;
        }

        //Add the option of the input file
        po::positional_options_description p;
        p.add("input", -1);

        //Create a new set of options
        po::variables_map options;

        //Create a new configuration
        configuration = std::make_shared<Configuration>();

        //Parse the command line options
        po::store(po::command_line_parser(argc, argv).options(all).extra_parser(numeric_parser).positional(p).run(), options);
        po::notify(options);

        //Transfer the options in the eddic configuration
        for(auto& option : all.options()){
            ConfigValue value;

            if(options.count(option->long_name())){
                value.defined = true;
                value.value = options[option->long_name()].value();
            } else {
                value.defined = false;
                value.value = std::string("false");
            }

            configuration->values[option->long_name()] = value;
        }

        if(options.count("O0") + options.count("O1") + options.count("O2") > 1){
            std::cout << "Invalid command line options : only one optimization level should be set" << std::endl;

            return false;
        }

        if(options.count("64") && options.count("32")){
            std::cout << "Invalid command line options : a compilation cannot be both 32 and 64 bits" << std::endl;

            return false;
        }

        //TODO Perhaps a more clear way to do that
        if(options.count("O0")){
            configuration->values["Opt"].value = 0;
        } else if(options.count("O1")){
            configuration->values["Opt"].value = 1;
        } else if(options.count("O2")){
            configuration->values["Opt"].value = 2;
        }

        //Triggers dependent options
        for(auto& trigger : triggers){
            if(option_defined(trigger.first)){
                trigger_childs(trigger.second);
            }
        }

        if(option_int_value("Opt") >= 1){
            trigger_childs(triggers["__1"]);
        }

        if(option_int_value("Opt") >= 2){
            trigger_childs(triggers["__2"]);
        }
    } catch (const po::ambiguous_option& e) {
        std::cout << "Invalid command line options : " << e.what() << std::endl;

        return false;
    } catch (const po::unknown_option& e) {
        std::cout << "Invalid command line options : " << e.what() << std::endl;

        return false;
    } catch (const po::multiple_occurrences& e) {
        std::cout << "Only one file can be compiled" << std::endl;

        return false;
    }

    return true;
}

bool eddic::option_defined(const std::string& option_name){
    ASSERT(configuration, "The configuration have not been initialized");

    return configuration->values[option_name].defined;
}

std::string eddic::option_value(const std::string& option_name){
    ASSERT(configuration, "The configuration have not been initialized");

    return boost::any_cast<std::string>(configuration->values[option_name].value);
}

int eddic::option_int_value(const std::string& option_name){
    ASSERT(configuration, "The configuration have not been initialized");

    return boost::any_cast<int>(configuration->values[option_name].value);
}

void eddic::print_help(){
    std::cout << visible << std::endl;
}

void eddic::print_version(){
    std::cout << "eddic version 1.0.2" << std::endl;
}
<commit_msg>Fix optimization levels<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <unordered_map>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include "assert.hpp"
#include "Options.hpp"

using namespace eddic;

namespace po = boost::program_options;

struct ConfigValue {
    bool defined;
    boost::any value;
};

struct Configuration {
    std::unordered_map<std::string, ConfigValue> values;
};

std::shared_ptr<Configuration> configuration;
std::unordered_map<std::string, std::vector<std::string>> triggers;

bool desc_init = false;
po::options_description visible("Usage : eddic [options] source.eddi");
po::options_description all("Usage : eddic [options] source.eddi");

std::pair<std::string, std::string> numeric_parser(const std::string& s){
    if (s.find("-32") == 0) {
        return make_pair("32", std::string("true"));
    } else if (s.find("-64") == 0) {
        return make_pair("64", std::string("true"));
    } else {
        return make_pair(std::string(), std::string());
    }
}

void add_trigger(const std::string& option, std::vector<std::string> childs){
   triggers[option] = childs;
}

inline void trigger_childs(const std::vector<std::string>& childs){
    for(auto& child : childs){
        configuration->values[child].defined = true;
        configuration->values[child].value = std::string("true");
    }
}

bool eddic::parseOptions(int argc, const char* argv[]) {
    try {
        //Only if the description has not been already defined
        if(!desc_init){
            po::options_description general("General options");
            general.add_options()
                ("help,h", "Generate this help message")
                ("assembly,S", "Generate only the assembly")
                ("keep,k", "Keep the assembly file")
                ("version", "Print the version of eddic")
                ("output,o", po::value<std::string>()->default_value("a.out"), "Set the name of the executable")

                ("debug,g", "Add debugging symbols")

                ("32", "Force the compilation for 32 bits platform")
                ("64", "Force the compilation for 64 bits platform")

                ("warning-all", "Enable all the warning messages")
                ("warning-unused", "Warn about unused variables, parameters and functions")
                ("warning-cast", "Warn about useless casts");

            po::options_description display("Display options");
            display.add_options()
                ("ast", "Print the Abstract Syntax Tree representation of the source")
                ("ast-only", "Only print the Abstract Syntax Tree representation of the source (do not continue compilation after printing)")

                ("mtac", "Print the medium-level Three Address Code representation of the source")
                ("mtac-opt", "Print the medium-level Three Address Code representation of the source before any optimization has been performed")
                ("mtac-only", "Only print the medium-level Three Address Code representation of the source (do not continue compilation after printing)")

                ("ltac", "Print the low-level Three Address Code representation of the source")
                ("ltac-only", "Only print the low-level Three Address Code representation of the source (do not continue compilation after printing)");

            po::options_description optimization("Optimization options");
            optimization.add_options()
                ("Opt,O", po::value<int>()->implicit_value(0)->default_value(2), "Define the optimization level")
                ("O0", "Disable all optimizations")
                ("O1", "Enable low-level optimizations")
                ("O2", "Enable all optimizations. This can be slow for big programs.")

                ("fglobal-optimization", "Enable optimizer engine")
                ("fpeephole-optimization", "Enable peephole optimizer")
                ("fno-inline-functions", "Disable inlining");

            po::options_description backend("Backend options");
            backend.add_options()
                ("quiet,q", "Do not print anything")
                ("verbose,v", "Make the compiler verbose")
                ("dev,d", "Activate development mode (very verbose)")
                ("perfs", "Display performance information")
                ("input", po::value<std::string>(), "Input file");

            all.add(general).add(display).add(optimization).add(backend);
            visible.add(general).add(display).add(optimization);

            add_trigger("warning-all", {"warning-unused", "warning-cast"});

            //TODO Should be a better way to do that
            add_trigger("__1", {"fpeephole-optimization"});
            add_trigger("__2", {"fglobal-optimization"});

            desc_init = true;
        }

        //Add the option of the input file
        po::positional_options_description p;
        p.add("input", -1);

        //Create a new set of options
        po::variables_map options;

        //Create a new configuration
        configuration = std::make_shared<Configuration>();

        //Parse the command line options
        po::store(po::command_line_parser(argc, argv).options(all).extra_parser(numeric_parser).positional(p).run(), options);
        po::notify(options);

        //Transfer the options in the eddic configuration
        for(auto& option : all.options()){
            ConfigValue value;

            if(options.count(option->long_name())){
                value.defined = true;
                value.value = options[option->long_name()].value();
            } else {
                value.defined = false;
                value.value = std::string("false");
            }

            configuration->values[option->long_name()] = value;
        }

        if(options.count("O0") + options.count("O1") + options.count("O2") > 1){
            std::cout << "Invalid command line options : only one optimization level should be set" << std::endl;

            return false;
        }

        if(options.count("64") && options.count("32")){
            std::cout << "Invalid command line options : a compilation cannot be both 32 and 64 bits" << std::endl;

            return false;
        }

        //TODO Perhaps a more clear way to do that
        if(options.count("O0")){
            configuration->values["Opt"].value = 0;
        } else if(options.count("O1")){
            configuration->values["Opt"].value = 1;
        } else if(options.count("O2")){
            configuration->values["Opt"].value = 2;
        }

        //Triggers dependent options
        for(auto& trigger : triggers){
            if(option_defined(trigger.first)){
                trigger_childs(trigger.second);
            }
        }

        if(option_int_value("Opt") >= 1){
            trigger_childs(triggers["__1"]);
        }

        if(option_int_value("Opt") >= 2){
            trigger_childs(triggers["__2"]);
        }
    } catch (const po::ambiguous_option& e) {
        std::cout << "Invalid command line options : " << e.what() << std::endl;

        return false;
    } catch (const po::unknown_option& e) {
        std::cout << "Invalid command line options : " << e.what() << std::endl;

        return false;
    } catch (const po::multiple_occurrences& e) {
        std::cout << "Only one file can be compiled" << std::endl;

        return false;
    }

    return true;
}

bool eddic::option_defined(const std::string& option_name){
    ASSERT(configuration, "The configuration have not been initialized");

    return configuration->values[option_name].defined;
}

std::string eddic::option_value(const std::string& option_name){
    ASSERT(configuration, "The configuration have not been initialized");

    return boost::any_cast<std::string>(configuration->values[option_name].value);
}

int eddic::option_int_value(const std::string& option_name){
    ASSERT(configuration, "The configuration have not been initialized");

    return boost::any_cast<int>(configuration->values[option_name].value);
}

void eddic::print_help(){
    std::cout << visible << std::endl;
}

void eddic::print_version(){
    std::cout << "eddic version 1.0.2" << std::endl;
}
<|endoftext|>


<commit_before>///
/// @file  PhiTiny.hpp
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PHITINY_HPP
#define PHITINY_HPP

#include <stdint.h>
#include <vector>
#include <cassert>

namespace primecount {

/// This class calculates phi(x, a) in constant time for small values
/// of a < 7 using lookup tables. Let pp = prime_products_[a]:
/// phi(x, a) = (x / pp) * φ(pp) + phi(x % pp, a).
///
class PhiTiny {
public:
  PhiTiny()
  {
    phi_cache_[0].push_back(0);

    // Initialize the phi_cache_ lookup tables
    for (int a = 1; is_cached(a); a++)
    {
      phi_cache_[a].reserve(prime_products_[a]);
      for (int x = 0; x < prime_products_[a]; x++)
        phi_cache_[a].push_back(static_cast<int16_t>(phi(x, a - 1) - phi(x / primes_[a], a - 1)));
    }
  }
  static bool is_cached(int64_t a)
  {
    return a >= 0 && a < 7;
  }
  /// Partial sieve function (a.k.a. Legendre-sum).
  /// phi(x, a) counts the numbers <= x that are not divisible
  /// by any of the first a primes.
  /// @pre is_cached(a) == true.
  ///
  int64_t phi(int64_t x, int64_t a) const
  {
    assert(is_cached(a));
    assert(x >= 0);
    return (x / prime_products_[a]) * totients_[a] + phi_cache_[a][x % prime_products_[a]];
  }
private:
  std::vector<int16_t> phi_cache_[7];
  static const int32_t primes_[7];
  static const int32_t prime_products_[7];
  static const int32_t totients_[7];
};

} // namespace primecount

#endif
<commit_msg>Moved code from PhiTiny.hpp to PhiTiny.cpp<commit_after>///
/// @file  PhiTiny.hpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef PHITINY_HPP
#define PHITINY_HPP

#include <stdint.h>
#include <vector>
#include <cassert>

namespace primecount {

/// This class calculates phi(x, a) in constant time for small values
/// of a < 7 using lookup tables. Let pp = prime_products_[a]:
/// phi(x, a) = (x / pp) * φ(pp) + phi(x % pp, a).
///
class PhiTiny {
public:
  PhiTiny();
  static bool is_cached(int64_t a)
  {
    return a >= 0 && a < 7;
  }
  /// Partial sieve function (a.k.a. Legendre-sum).
  /// phi(x, a) counts the numbers <= x that are not divisible
  /// by any of the first a primes.
  /// @pre is_cached(a) == true.
  ///
  int64_t phi(int64_t x, int64_t a) const
  {
    assert(is_cached(a));
    assert(x >= 0);
    return (x / prime_products_[a]) * totients_[a] + phi_cache_[a][x % prime_products_[a]];
  }
private:
  std::vector<int16_t> phi_cache_[7];
  static const int32_t primes_[7];
  static const int32_t prime_products_[7];
  static const int32_t totients_[7];
};

} // namespace primecount

#endif
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <ncurses.h>

#include "concat_c.hh"
#include "configuration.hh"
#include "contents.hh"
#include "file_contents.hh"
#include "../lib.hh"
#include "key_aliases.hh"
#include "show_message.hh"
#include "vick-move/lib.hh"
#include "print_contents.hh"

namespace vick {
namespace insert_mode {

struct insert_c : public change {
    const std::string track;
    const move_t y, x;
    insert_c(const std::string& track, move_t y, move_t x)
        : track(track)
        , y(y)
        , x(x) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) +
                           contents.cont[y].substr(x + track.size());
        contents.y = y;
        contents.x = x;
        if (contents.x and contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + track +
                           contents.cont[y].substr(x);
        contents.y = y;
        contents.x = x + track.size();
        if (contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<insert_c>(track, contents.y,
                                          contents.x);
    }
};

struct newline_c : public change {
    const std::string first, second;
    const move_t y;
    newline_c(const contents& contents)
        : first(contents.cont[contents.y].substr(0, contents.x))
        , second(contents.cont[contents.y].substr(contents.x))
        , y(contents.y) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = first + second;
        contents.cont.erase(contents.cont.begin() + y + 1);
        contents.y = y;
        contents.x = first.size();
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = first;
        contents.cont.insert(contents.cont.begin() + y + 1, second);
        contents.y = y + 1;
        contents.x = 0;
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<newline_c>(contents);
    }
};

boost::optional<std::shared_ptr<change> >
enter_insert_mode(contents& contents, boost::optional<int> pref) {
    std::string track;
    auto x = contents.x;
    char ch;
    show_message("--INSERT--");
    if (contents.refresh) {
        print_contents(contents);
        show_message("--INSERT--");
    }
    while ((ch = getch()) != QUIT_KEY) {
        if (ch == '\n') {
            std::vector<std::shared_ptr<change> > changes;
            changes.reserve(3);
            if (track.size())
                changes.push_back(
                    std::make_shared<insert_c>(track, contents.y, x));
            changes.push_back(std::make_shared<newline_c>(contents));
            changes.back()->redo(contents);
            auto recursed = enter_insert_mode(contents, pref);
            if (recursed)
                changes.push_back(recursed.get());
            return boost::optional<std::shared_ptr<change> >(
                std::make_shared<concat_c>(changes));
        }
        if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
            track += ch;
        } else {
            contents.cont[contents.y].insert(contents.x, 1, ch);
            contents.x++;
            track += ch;
        }
        if (contents.refresh) {
            print_contents(contents);
            show_message("--INSERT--");
        }
    }
    showing_message = false;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<insert_c>(track, contents.y, x));
}

struct replace_c : public change {
    const std::string o, n;
    const move_t y, x;
    replace_c(const std::string& o, const std::string& n, move_t y,
              move_t x)
        : o(o)
        , n(n)
        , y(y)
        , x(x) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + o +
                           contents.cont[y].substr(x + o.size());
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + n +
                           contents.cont[y].substr(x + n.size());
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<replace_c>(contents.cont[contents.y]
                                               .substr(contents.x,
                                                       n.size()),
                                           n, contents.y, contents.x);
    }
};

boost::optional<std::shared_ptr<change> >
enter_replace_mode(contents& contents, boost::optional<int> pref) {
    std::string o, n;
    auto x = contents.x;
    char ch;
    show_message("--INSERT (REPLACE)--");
    if (get_contents().refresh) {
        print_contents(get_contents());
        show_message("--INSERT (REPLACE)--");
    }
    while ((ch = getch()) != QUIT_KEY) {
        if (ch == '\n') {
            o = contents.cont[contents.y][contents.x];
            std::vector<std::shared_ptr<change> > changes;
            changes.reserve(3);
            if (o.size())
                changes.push_back(
                    std::make_shared<replace_c>(o, n, contents.y, x));
            changes.push_back(std::make_shared<newline_c>(contents));
            changes.back()->redo(contents);
            auto recursed = enter_replace_mode(contents, pref);
            if (recursed)
                changes.push_back(recursed.get());
            return boost::optional<std::shared_ptr<change> >(
                std::make_shared<concat_c>(changes));
        }
        if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
            n += ch;
        } else {
            o += contents.cont[contents.y][contents.x];
            n += ch;
            contents.cont[contents.y][contents.x] = ch;
            contents.x++;
        }
        if (get_contents().refresh) {
            print_contents(get_contents());
            show_message("--INSERT (REPLACE)--");
        }
    }
    showing_message = false;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<replace_c>(o, n, contents.y, x));
}

struct append_c : public change {
    const std::string track;
    const move_t y, x;
    append_c(const std::string& track, move_t y, move_t x)
        : track(track)
        , y(y)
        , x(x) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) +
                           contents.cont[y].substr(x + track.size());
        contents.y = y;
        contents.x = x;
        if (contents.x and contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + track +
                           contents.cont[y].substr(x);
        contents.y = y;
        contents.x = x + track.size();
        if (contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<append_c>(track, contents.y,
                                          contents.x + 1);
    }
};

boost::optional<std::shared_ptr<change> >
enter_append_mode(contents& contents, boost::optional<int> pref) {
    if (contents.cont[contents.y].empty())
        return enter_insert_mode(contents, pref);
    contents.x++;
    std::string track;
    auto x = contents.x;
    char ch;
    show_message("--INSERT--");
    if (get_contents().refresh) {
        print_contents(get_contents());
        show_message("--INSERT--");
    }
    while ((ch = getch()) != QUIT_KEY) {
        if (ch == '\n') {
            std::vector<std::shared_ptr<change> > changes;
            changes.reserve(3);
            if (track.size())
                changes.push_back(
                    std::make_shared<insert_c>(track, contents.y, x));
            changes.push_back(std::make_shared<newline_c>(contents));
            changes.back()->redo(contents);
            auto recursed = enter_insert_mode(contents, pref);
            if (recursed)
                changes.push_back(recursed.get());
            return boost::optional<std::shared_ptr<change> >(
                std::make_shared<concat_c>(changes));
        }
        if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
            track += ch;
        } else {
            contents.cont[contents.y].insert(contents.x, 1, ch);
            contents.x++;
            track += ch;
        }
        if (get_contents().refresh) {
            print_contents(get_contents());
            show_message("--INSERT--");
        }
    }
    showing_message = false;
    // cancel out ++ from beginning
    if (contents.x != 0)
        contents.x--;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<append_c>(track, contents.y, x));
}
}
}
<commit_msg>Reorder includes<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <ncurses.h>

#include "../lib.hh"
#include "concat_c.hh"
#include "configuration.hh"
#include "contents.hh"
#include "file_contents.hh"
#include "key_aliases.hh"
#include "print_contents.hh"
#include "show_message.hh"
#include "vick-move/lib.hh"

namespace vick {
namespace insert_mode {

struct insert_c : public change {
    const std::string track;
    const move_t y, x;
    insert_c(const std::string& track, move_t y, move_t x)
        : track(track)
        , y(y)
        , x(x) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) +
                           contents.cont[y].substr(x + track.size());
        contents.y = y;
        contents.x = x;
        if (contents.x and contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + track +
                           contents.cont[y].substr(x);
        contents.y = y;
        contents.x = x + track.size();
        if (contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<insert_c>(track, contents.y,
                                          contents.x);
    }
};

struct newline_c : public change {
    const std::string first, second;
    const move_t y;
    newline_c(const contents& contents)
        : first(contents.cont[contents.y].substr(0, contents.x))
        , second(contents.cont[contents.y].substr(contents.x))
        , y(contents.y) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = first + second;
        contents.cont.erase(contents.cont.begin() + y + 1);
        contents.y = y;
        contents.x = first.size();
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = first;
        contents.cont.insert(contents.cont.begin() + y + 1, second);
        contents.y = y + 1;
        contents.x = 0;
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<newline_c>(contents);
    }
};

boost::optional<std::shared_ptr<change> >
enter_insert_mode(contents& contents, boost::optional<int> pref) {
    std::string track;
    auto x = contents.x;
    char ch;
    show_message("--INSERT--");
    if (contents.refresh) {
        print_contents(contents);
        show_message("--INSERT--");
    }
    while ((ch = getch()) != QUIT_KEY) {
        if (ch == '\n') {
            std::vector<std::shared_ptr<change> > changes;
            changes.reserve(3);
            if (track.size())
                changes.push_back(
                    std::make_shared<insert_c>(track, contents.y, x));
            changes.push_back(std::make_shared<newline_c>(contents));
            changes.back()->redo(contents);
            auto recursed = enter_insert_mode(contents, pref);
            if (recursed)
                changes.push_back(recursed.get());
            return boost::optional<std::shared_ptr<change> >(
                std::make_shared<concat_c>(changes));
        }
        if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
            track += ch;
        } else {
            contents.cont[contents.y].insert(contents.x, 1, ch);
            contents.x++;
            track += ch;
        }
        if (contents.refresh) {
            print_contents(contents);
            show_message("--INSERT--");
        }
    }
    showing_message = false;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<insert_c>(track, contents.y, x));
}

struct replace_c : public change {
    const std::string o, n;
    const move_t y, x;
    replace_c(const std::string& o, const std::string& n, move_t y,
              move_t x)
        : o(o)
        , n(n)
        , y(y)
        , x(x) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + o +
                           contents.cont[y].substr(x + o.size());
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + n +
                           contents.cont[y].substr(x + n.size());
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<replace_c>(contents.cont[contents.y]
                                               .substr(contents.x,
                                                       n.size()),
                                           n, contents.y, contents.x);
    }
};

boost::optional<std::shared_ptr<change> >
enter_replace_mode(contents& contents, boost::optional<int> pref) {
    std::string o, n;
    auto x = contents.x;
    char ch;
    show_message("--INSERT (REPLACE)--");
    if (get_contents().refresh) {
        print_contents(get_contents());
        show_message("--INSERT (REPLACE)--");
    }
    while ((ch = getch()) != QUIT_KEY) {
        if (ch == '\n') {
            o = contents.cont[contents.y][contents.x];
            std::vector<std::shared_ptr<change> > changes;
            changes.reserve(3);
            if (o.size())
                changes.push_back(
                    std::make_shared<replace_c>(o, n, contents.y, x));
            changes.push_back(std::make_shared<newline_c>(contents));
            changes.back()->redo(contents);
            auto recursed = enter_replace_mode(contents, pref);
            if (recursed)
                changes.push_back(recursed.get());
            return boost::optional<std::shared_ptr<change> >(
                std::make_shared<concat_c>(changes));
        }
        if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
            n += ch;
        } else {
            o += contents.cont[contents.y][contents.x];
            n += ch;
            contents.cont[contents.y][contents.x] = ch;
            contents.x++;
        }
        if (get_contents().refresh) {
            print_contents(get_contents());
            show_message("--INSERT (REPLACE)--");
        }
    }
    showing_message = false;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<replace_c>(o, n, contents.y, x));
}

struct append_c : public change {
    const std::string track;
    const move_t y, x;
    append_c(const std::string& track, move_t y, move_t x)
        : track(track)
        , y(y)
        , x(x) {}
    virtual bool is_overriding() const noexcept override {
        return true;
    }
    virtual void undo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) +
                           contents.cont[y].substr(x + track.size());
        contents.y = y;
        contents.x = x;
        if (contents.x and contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual void redo(contents& contents) override {
        contents.cont[y] = contents.cont[y].substr(0, x) + track +
                           contents.cont[y].substr(x);
        contents.y = y;
        contents.x = x + track.size();
        if (contents.x >= contents.cont[y].size())
            contents.x = contents.cont[y].size() - 1;
    }
    virtual std::shared_ptr<change>
    regenerate(const contents& contents) const override {
        return std::make_shared<append_c>(track, contents.y,
                                          contents.x + 1);
    }
};

boost::optional<std::shared_ptr<change> >
enter_append_mode(contents& contents, boost::optional<int> pref) {
    if (contents.cont[contents.y].empty())
        return enter_insert_mode(contents, pref);
    contents.x++;
    std::string track;
    auto x = contents.x;
    char ch;
    show_message("--INSERT--");
    if (get_contents().refresh) {
        print_contents(get_contents());
        show_message("--INSERT--");
    }
    while ((ch = getch()) != QUIT_KEY) {
        if (ch == '\n') {
            std::vector<std::shared_ptr<change> > changes;
            changes.reserve(3);
            if (track.size())
                changes.push_back(
                    std::make_shared<insert_c>(track, contents.y, x));
            changes.push_back(std::make_shared<newline_c>(contents));
            changes.back()->redo(contents);
            auto recursed = enter_insert_mode(contents, pref);
            if (recursed)
                changes.push_back(recursed.get());
            return boost::optional<std::shared_ptr<change> >(
                std::make_shared<concat_c>(changes));
        }
        if (contents.x >= contents.cont[contents.y].size()) {
            contents.cont[contents.y].push_back(ch);
            contents.x = contents.cont[contents.y].size();
            track += ch;
        } else {
            contents.cont[contents.y].insert(contents.x, 1, ch);
            contents.x++;
            track += ch;
        }
        if (get_contents().refresh) {
            print_contents(get_contents());
            show_message("--INSERT--");
        }
    }
    showing_message = false;
    // cancel out ++ from beginning
    if (contents.x != 0)
        contents.x--;
    return boost::optional<std::shared_ptr<change> >(
        std::make_shared<append_c>(track, contents.y, x));
}
}
}
<|endoftext|>


<commit_before>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Infomap software package is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/

#include "version.h"

#ifdef NS_INFOMAP
namespace infomap
{
#endif

const char* INFOMAP_VERSION = "0.18.4";

#ifdef NS_INFOMAP
}
#endif
<commit_msg>Bump version<commit_after>/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>

 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Infomap software package is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/

#include "version.h"

#ifdef NS_INFOMAP
namespace infomap
{
#endif

const char* INFOMAP_VERSION = "0.18.5";

#ifdef NS_INFOMAP
}
#endif
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include <windows.h>

#include <assert.h>
#include <string.h>
#include <stdio.h>

#include <string>

#include "os.hpp"
#include "os_string.hpp"

namespace os {

/*
 * Trick from http://locklessinc.com/articles/pthreads_on_windows/
 */
static CRITICAL_SECTION
criticalSection = {
    (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
};

void
acquireMutex(void)
{
    EnterCriticalSection(&criticalSection);
}

void
releaseMutex(void)
{
    LeaveCriticalSection(&criticalSection);
}

String
getProcessName(void)
{
    String path;
    size_t size = MAX_PATH;
    char *buf = path.buf(size);

    DWORD nWritten = GetModuleFileNameA(NULL, buf, size);
    (void)nWritten;

    path.truncate();

    return path;
}

String
getCurrentDir(void)
{
    String path;
    size_t size = MAX_PATH;
    char *buf = path.buf(size);

    DWORD ret = GetCurrentDirectoryA(size, buf);
    (void)ret;

    buf[size - 1] = 0;
    path.truncate();

    return path;
}

bool
String::exists(void) const
{
    DWORD attrs = GetFileAttributesA(str());
    return attrs != INVALID_FILE_ATTRIBUTES;
}

/**
 * Determine whether an argument should be quoted.
 */
static bool
needsQuote(const char *arg)
{
    char c;
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        }
        if (c == ' ' || c == '\t' || c == '\"') {
            return true;
        }
        if (c == '\\') {
            c = *arg++;
            if (c == '\0') {
                break;
            }
            if (c == '"') {
                return true;
            }
        }
    }
    return false;
}

static void
quoteArg(std::string &s, const char *arg)
{
    char c;
    unsigned backslashes = 0;

    s.push_back('"');
    while (true) {
        c = *arg++;
        switch (c)
        if (c == '\0') {
            break;
        } else if (c == '"') {
            while (backslashes) {
                s.push_back('\\');
                --backslashes;
            }
            s.push_back('\\');
        } else {
            if (c == '\\') {
                ++backslashes;
            } else {
                backslashes = 0;
            }
        }
        s.push_back(c);
    }
    s.push_back('"');
}

int execute(char * const * args)
{
    std::string commandLine;

    const char *arg0 = *args;
    const char *arg;
    char sep = 0;
    while ((arg = *args++) != NULL) {
        if (sep) {
            commandLine.push_back(sep);
        }

        if (needsQuote(arg)) {
            quoteArg(commandLine, arg);
        } else {
            commandLine.append(arg);
        }

        sep = ' ';
    }

    STARTUPINFO startupInfo;
    memset(&startupInfo, 0, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);

    PROCESS_INFORMATION processInformation;

    if (!CreateProcessA(NULL,
                        const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
                        0, // process attributes
                        0, // thread attributes
                        FALSE, // inherit handles
                        0, // creation flags,
                        NULL, // environment
                        NULL, // current directory
                        &startupInfo,
                        &processInformation
                        )) {
        log("error: failed to execute %s\n", arg0);
        return -1;
    }

    WaitForSingleObject(processInformation.hProcess, INFINITE);

    DWORD exitCode = ~0;
    GetExitCodeProcess(processInformation.hProcess, &exitCode);

    CloseHandle(processInformation.hProcess);
    CloseHandle(processInformation.hThread);

    return (int)exitCode;
}

void
log(const char *format, ...)
{
    char buf[4096];

    va_list ap;
    va_start(ap, format);
    fflush(stdout);
    vsnprintf(buf, sizeof buf, format, ap);
    va_end(ap);

    OutputDebugStringA(buf);

    /*
     * Also write the message to stderr, when a debugger is not present (to
     * avoid duplicate messages in command line debuggers).
     */
#if _WIN32_WINNT > 0x0400
    if (!IsDebuggerPresent()) {
        fflush(stdout);
        fputs(buf, stderr);
        fflush(stderr);
    }
#endif
}

long long
getTime(void)
{
    static LARGE_INTEGER frequency;
    LARGE_INTEGER counter;
    if (!frequency.QuadPart)
        QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&counter);
    return counter.QuadPart*1000000LL/frequency.QuadPart;
}

void
abort(void)
{
#ifndef NDEBUG
    DebugBreak();
#else
    ExitProcess(0);
#endif
}

static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
static void (*gCallback)(void) = NULL;

static LONG WINAPI
unhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
    if (gCallback) {
        gCallback();
    }

	if (prevExceptionFilter) {
		return prevExceptionFilter(pExceptionInfo);
    } else {
		return EXCEPTION_CONTINUE_SEARCH;
    }
}

void
setExceptionCallback(void (*callback)(void))
{
    assert(!gCallback);

    if (!gCallback) {
        gCallback = callback;

        assert(!prevExceptionFilter);

        /*
         * TODO: Unfortunately it seems that the CRT will reset the exception
         * handler in certain circumnstances.  See
         * http://www.codeproject.com/KB/winsdk/crash_hook.aspx
         */
        prevExceptionFilter = SetUnhandledExceptionFilter(unhandledExceptionFilter);
    }
}

void
resetExceptionCallback(void)
{
    gCallback = NULL;
}

} /* namespace os */
<commit_msg>Use AddVectoredExceptionHandler<commit_after>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

#include <windows.h>

#include <assert.h>
#include <string.h>
#include <stdio.h>

#include <string>

#include "os.hpp"
#include "os_string.hpp"

namespace os {

/*
 * Trick from http://locklessinc.com/articles/pthreads_on_windows/
 */
static CRITICAL_SECTION
criticalSection = {
    (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
};

void
acquireMutex(void)
{
    EnterCriticalSection(&criticalSection);
}

void
releaseMutex(void)
{
    LeaveCriticalSection(&criticalSection);
}

String
getProcessName(void)
{
    String path;
    size_t size = MAX_PATH;
    char *buf = path.buf(size);

    DWORD nWritten = GetModuleFileNameA(NULL, buf, size);
    (void)nWritten;

    path.truncate();

    return path;
}

String
getCurrentDir(void)
{
    String path;
    size_t size = MAX_PATH;
    char *buf = path.buf(size);

    DWORD ret = GetCurrentDirectoryA(size, buf);
    (void)ret;

    buf[size - 1] = 0;
    path.truncate();

    return path;
}

bool
String::exists(void) const
{
    DWORD attrs = GetFileAttributesA(str());
    return attrs != INVALID_FILE_ATTRIBUTES;
}

/**
 * Determine whether an argument should be quoted.
 */
static bool
needsQuote(const char *arg)
{
    char c;
    while (true) {
        c = *arg++;
        if (c == '\0') {
            break;
        }
        if (c == ' ' || c == '\t' || c == '\"') {
            return true;
        }
        if (c == '\\') {
            c = *arg++;
            if (c == '\0') {
                break;
            }
            if (c == '"') {
                return true;
            }
        }
    }
    return false;
}

static void
quoteArg(std::string &s, const char *arg)
{
    char c;
    unsigned backslashes = 0;

    s.push_back('"');
    while (true) {
        c = *arg++;
        switch (c)
        if (c == '\0') {
            break;
        } else if (c == '"') {
            while (backslashes) {
                s.push_back('\\');
                --backslashes;
            }
            s.push_back('\\');
        } else {
            if (c == '\\') {
                ++backslashes;
            } else {
                backslashes = 0;
            }
        }
        s.push_back(c);
    }
    s.push_back('"');
}

int execute(char * const * args)
{
    std::string commandLine;

    const char *arg0 = *args;
    const char *arg;
    char sep = 0;
    while ((arg = *args++) != NULL) {
        if (sep) {
            commandLine.push_back(sep);
        }

        if (needsQuote(arg)) {
            quoteArg(commandLine, arg);
        } else {
            commandLine.append(arg);
        }

        sep = ' ';
    }

    STARTUPINFO startupInfo;
    memset(&startupInfo, 0, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);

    PROCESS_INFORMATION processInformation;

    if (!CreateProcessA(NULL,
                        const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
                        0, // process attributes
                        0, // thread attributes
                        FALSE, // inherit handles
                        0, // creation flags,
                        NULL, // environment
                        NULL, // current directory
                        &startupInfo,
                        &processInformation
                        )) {
        log("error: failed to execute %s\n", arg0);
        return -1;
    }

    WaitForSingleObject(processInformation.hProcess, INFINITE);

    DWORD exitCode = ~0;
    GetExitCodeProcess(processInformation.hProcess, &exitCode);

    CloseHandle(processInformation.hProcess);
    CloseHandle(processInformation.hThread);

    return (int)exitCode;
}

void
log(const char *format, ...)
{
    char buf[4096];

    va_list ap;
    va_start(ap, format);
    fflush(stdout);
    vsnprintf(buf, sizeof buf, format, ap);
    va_end(ap);

    OutputDebugStringA(buf);

    /*
     * Also write the message to stderr, when a debugger is not present (to
     * avoid duplicate messages in command line debuggers).
     */
#if _WIN32_WINNT > 0x0400
    if (!IsDebuggerPresent()) {
        fflush(stdout);
        fputs(buf, stderr);
        fflush(stderr);
    }
#endif
}

long long
getTime(void)
{
    static LARGE_INTEGER frequency;
    LARGE_INTEGER counter;
    if (!frequency.QuadPart)
        QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&counter);
    return counter.QuadPart*1000000LL/frequency.QuadPart;
}

void
abort(void)
{
#ifndef NDEBUG
    DebugBreak();
#else
    ExitProcess(0);
#endif
}

static PVOID prevExceptionFilter = NULL;
static void (*gCallback)(void) = NULL;

static LONG CALLBACK
unhandledExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
    PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;

    /*
     * Ignore OutputDebugStringA exception.
     */
    if (pExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) {
        return EXCEPTION_CONTINUE_SEARCH;
    }

    /*
     * Ignore C++ exceptions
     *
     * http://support.microsoft.com/kb/185294
     * http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
     */
    if (pExceptionRecord->ExceptionCode == 0xe06d7363) {
        return EXCEPTION_CONTINUE_SEARCH;
    }

    // Clear direction flag
#ifdef _MSC_VER
    __asm {
        cld
    };
#else
    asm("cld");
#endif

    log("apitrace: warning: caught exception 0x%08lx\n", pExceptionRecord->ExceptionCode);

    static int recursion_count = 0;
    if (recursion_count) {
        fprintf(stderr, "apitrace: warning: recursion handling exception\n");
    } else {
        if (gCallback) {
            ++recursion_count;
            gCallback();
            --recursion_count;
        }
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

void
setExceptionCallback(void (*callback)(void))
{
    assert(!gCallback);

    if (!gCallback) {
        gCallback = callback;

        assert(!prevExceptionFilter);

        prevExceptionFilter = AddVectoredExceptionHandler(0, unhandledExceptionHandler);
    }
}

void
resetExceptionCallback(void)
{
    if (gCallback) {
        RemoveVectoredExceptionHandler(prevExceptionFilter);
        gCallback = NULL;
    }
}

} /* namespace os */
<|endoftext|>


<commit_before>/*
Copyright (c) 2010-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Universite de Sherbrooke 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 <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/image_encodings.h>
#include <cv_bridge/cv_bridge.h>
#include <std_msgs/Empty.h>
#include <image_transport/image_transport.h>
#include <std_srvs/Empty.h>

#include <rtabmap/core/CameraRGB.h>
#include <rtabmap/core/CameraThread.h>
#include <rtabmap/core/CameraEvent.h>

#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UEventsHandler.h>
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UFile.h>

#include <dynamic_reconfigure/server.h>
#include <rtabmap_ros/CameraConfig.h>

class CameraWrapper : public UEventsHandler
{
public:
	// Usb device like a Webcam
	CameraWrapper(int usbDevice = 0,
			      float imageRate = 0,
				  unsigned int imageWidth = 0,
				  unsigned int imageHeight = 0) :
		cameraThread_(0),
		camera_(0),
		frameId_("camera")
	{
		ros::NodeHandle nh;
		ros::NodeHandle pnh("~");
		pnh.param("frame_id", frameId_, frameId_);
		image_transport::ImageTransport it(nh);
		rosPublisher_ = it.advertise("image", 1);
		startSrv_ = nh.advertiseService("start_camera", &CameraWrapper::startSrv, this);
		stopSrv_ = nh.advertiseService("stop_camera", &CameraWrapper::stopSrv, this);
		UEventsManager::addHandler(this);
	}

	virtual ~CameraWrapper()
	{
		if(cameraThread_)
		{
			cameraThread_->join(true);
			delete cameraThread_;
		}
	}

	bool init()
	{
		if(cameraThread_)
		{
			return cameraThread_->camera()->init();
		}
		return false;
	}

	void start()
	{
		if(cameraThread_)
		{
			return cameraThread_->start();
		}
	}

	bool startSrv(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
	{
		ROS_INFO("Camera started...");
		if(cameraThread_)
		{
			cameraThread_->start();
		}
		return true;
	}

	bool stopSrv(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
	{
		ROS_INFO("Camera stopped...");
		if(cameraThread_)
		{
			cameraThread_->kill();
		}
		return true;
	}

	void setParameters(int deviceId, double frameRate, const std::string & path, bool pause)
	{
		ROS_INFO("Parameters changed: deviceId=%d, path=%s frameRate=%f pause=%s",
				deviceId, path.c_str(), frameRate, pause?"true":"false");
		if(cameraThread_)
		{
			rtabmap::CameraVideo * videoCam = dynamic_cast<rtabmap::CameraVideo *>(camera_);
			rtabmap::CameraImages * imagesCam = dynamic_cast<rtabmap::CameraImages *>(camera_);

			if(imagesCam)
			{
				// images
				if(!path.empty() && UDirectory::getDir(path+"/").compare(UDirectory::getDir(imagesCam->getPath())) == 0)
				{
					imagesCam->setImageRate(frameRate);
					if(pause && !cameraThread_->isPaused())
					{
						cameraThread_->join(true);
					}
					else if(!pause && cameraThread_->isPaused())
					{
						cameraThread_->start();
					}
				}
				else
				{
					delete cameraThread_;
					cameraThread_ = 0;
				}
			}
			else if(videoCam)
			{
				if(!path.empty() && path.compare(videoCam->getFilePath()) == 0)
				{
					// video
					videoCam->setImageRate(frameRate);
					if(pause && !cameraThread_->isPaused())
					{
						cameraThread_->join(true);
					}
					else if(!pause && cameraThread_->isPaused())
					{
						cameraThread_->start();
					}
				}
				else if(path.empty() &&
						videoCam->getFilePath().empty() &&
						videoCam->getUsbDevice() == deviceId)
				{
					// usb device
					videoCam->setImageRate(frameRate);
					if(pause && !cameraThread_->isPaused())
					{
						cameraThread_->join(true);
					}
					else if(!pause && cameraThread_->isPaused())
					{
						cameraThread_->start();
					}
				}
				else
				{
					delete cameraThread_;
					cameraThread_ = 0;
				}
			}
			else
			{
				ROS_ERROR("Wrong camera type ?!?");
				delete cameraThread_;
				cameraThread_ = 0;
			}
		}

		if(!cameraThread_)
		{
			if(!path.empty() && UDirectory::exists(path))
			{
				//images
				camera_ = new rtabmap::CameraImages(path, frameRate);
			}
			else if(!path.empty() && UFile::exists(path))
			{
				//video
				camera_ = new rtabmap::CameraVideo(path, false, frameRate);
			}
			else
			{
				if(!path.empty() && !UDirectory::exists(path) && !UFile::exists(path))
				{
					ROS_ERROR("Path \"%s\" does not exist (or you don't have the permissions to read)... falling back to usb device...", path.c_str());
				}
				//usb device
				camera_ = new rtabmap::CameraVideo(deviceId, frameRate);
			}
			cameraThread_ = new rtabmap::CameraThread(camera_);
			init();
			if(!pause)
			{
				start();
			}
		}
	}

protected:
	virtual void handleEvent(UEvent * event)
	{
		if(event->getClassName().compare("CameraEvent") == 0)
		{
			rtabmap::CameraEvent * e = (rtabmap::CameraEvent*)event;
			const cv::Mat & image = e->data().imageRaw();
			if(!image.empty() && image.depth() == CV_8U)
			{
				cv_bridge::CvImage img;
				if(image.channels() == 1)
				{
					img.encoding = sensor_msgs::image_encodings::MONO8;
				}
				else
				{
					img.encoding = sensor_msgs::image_encodings::BGR8;
				}
				img.image = image;
				sensor_msgs::ImagePtr rosMsg = img.toImageMsg();
				rosMsg->header.frame_id = frameId_;
				rosMsg->header.stamp = ros::Time::now();
				rosPublisher_.publish(rosMsg);
			}
		}
	}

private:
	image_transport::Publisher rosPublisher_;
	rtabmap::CameraThread * cameraThread_;
	rtabmap::Camera * camera_;
	ros::ServiceServer startSrv_;
	ros::ServiceServer stopSrv_;
	std::string frameId_;
};

CameraWrapper * camera = 0;
void callback(rtabmap_ros::CameraConfig &config, uint32_t level)
{
	if(camera)
	{
		camera->setParameters(config.device_id, config.frame_rate, config.video_or_images_path, config.pause);
	}
}

int main(int argc, char** argv)
{
	ULogger::setType(ULogger::kTypeConsole);
	//ULogger::setLevel(ULogger::kDebug);
	ULogger::setEventLevel(ULogger::kWarning);

	ros::init(argc, argv, "camera");

	ros::NodeHandle nh("~");

	camera = new CameraWrapper(); // webcam device 0

	dynamic_reconfigure::Server<rtabmap_ros::CameraConfig> server;
	dynamic_reconfigure::Server<rtabmap_ros::CameraConfig>::CallbackType f;
	f = boost::bind(&callback, _1, _2);
	server.setCallback(f);

	ros::spin();

	//cleanup
	if(camera)
	{
		delete camera;
	}

	return 0;
}
<commit_msg>Updated CameraVideo interface<commit_after>/*
Copyright (c) 2010-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the Universite de Sherbrooke 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 <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/image_encodings.h>
#include <cv_bridge/cv_bridge.h>
#include <std_msgs/Empty.h>
#include <image_transport/image_transport.h>
#include <std_srvs/Empty.h>

#include <rtabmap/core/CameraRGB.h>
#include <rtabmap/core/CameraThread.h>
#include <rtabmap/core/CameraEvent.h>

#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UEventsHandler.h>
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/UDirectory.h>
#include <rtabmap/utilite/UFile.h>

#include <dynamic_reconfigure/server.h>
#include <rtabmap_ros/CameraConfig.h>

class CameraWrapper : public UEventsHandler
{
public:
	// Usb device like a Webcam
	CameraWrapper(int usbDevice = 0,
			      float imageRate = 0,
				  unsigned int imageWidth = 0,
				  unsigned int imageHeight = 0) :
		cameraThread_(0),
		camera_(0),
		frameId_("camera")
	{
		ros::NodeHandle nh;
		ros::NodeHandle pnh("~");
		pnh.param("frame_id", frameId_, frameId_);
		image_transport::ImageTransport it(nh);
		rosPublisher_ = it.advertise("image", 1);
		startSrv_ = nh.advertiseService("start_camera", &CameraWrapper::startSrv, this);
		stopSrv_ = nh.advertiseService("stop_camera", &CameraWrapper::stopSrv, this);
		UEventsManager::addHandler(this);
	}

	virtual ~CameraWrapper()
	{
		if(cameraThread_)
		{
			cameraThread_->join(true);
			delete cameraThread_;
		}
	}

	bool init()
	{
		if(cameraThread_)
		{
			return cameraThread_->camera()->init();
		}
		return false;
	}

	void start()
	{
		if(cameraThread_)
		{
			return cameraThread_->start();
		}
	}

	bool startSrv(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
	{
		ROS_INFO("Camera started...");
		if(cameraThread_)
		{
			cameraThread_->start();
		}
		return true;
	}

	bool stopSrv(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
	{
		ROS_INFO("Camera stopped...");
		if(cameraThread_)
		{
			cameraThread_->kill();
		}
		return true;
	}

	void setParameters(int deviceId, double frameRate, const std::string & path, bool pause)
	{
		ROS_INFO("Parameters changed: deviceId=%d, path=%s frameRate=%f pause=%s",
				deviceId, path.c_str(), frameRate, pause?"true":"false");
		if(cameraThread_)
		{
			rtabmap::CameraVideo * videoCam = dynamic_cast<rtabmap::CameraVideo *>(camera_);
			rtabmap::CameraImages * imagesCam = dynamic_cast<rtabmap::CameraImages *>(camera_);

			if(imagesCam)
			{
				// images
				if(!path.empty() && UDirectory::getDir(path+"/").compare(UDirectory::getDir(imagesCam->getPath())) == 0)
				{
					imagesCam->setImageRate(frameRate);
					if(pause && !cameraThread_->isPaused())
					{
						cameraThread_->join(true);
					}
					else if(!pause && cameraThread_->isPaused())
					{
						cameraThread_->start();
					}
				}
				else
				{
					delete cameraThread_;
					cameraThread_ = 0;
				}
			}
			else if(videoCam)
			{
				if(!path.empty() && path.compare(videoCam->getFilePath()) == 0)
				{
					// video
					videoCam->setImageRate(frameRate);
					if(pause && !cameraThread_->isPaused())
					{
						cameraThread_->join(true);
					}
					else if(!pause && cameraThread_->isPaused())
					{
						cameraThread_->start();
					}
				}
				else if(path.empty() &&
						videoCam->getFilePath().empty() &&
						videoCam->getUsbDevice() == deviceId)
				{
					// usb device
					videoCam->setImageRate(frameRate);
					if(pause && !cameraThread_->isPaused())
					{
						cameraThread_->join(true);
					}
					else if(!pause && cameraThread_->isPaused())
					{
						cameraThread_->start();
					}
				}
				else
				{
					delete cameraThread_;
					cameraThread_ = 0;
				}
			}
			else
			{
				ROS_ERROR("Wrong camera type ?!?");
				delete cameraThread_;
				cameraThread_ = 0;
			}
		}

		if(!cameraThread_)
		{
			if(!path.empty() && UDirectory::exists(path))
			{
				//images
				camera_ = new rtabmap::CameraImages(path, frameRate);
			}
			else if(!path.empty() && UFile::exists(path))
			{
				//video
				camera_ = new rtabmap::CameraVideo(path, false, frameRate);
			}
			else
			{
				if(!path.empty() && !UDirectory::exists(path) && !UFile::exists(path))
				{
					ROS_ERROR("Path \"%s\" does not exist (or you don't have the permissions to read)... falling back to usb device...", path.c_str());
				}
				//usb device
				camera_ = new rtabmap::CameraVideo(deviceId, false, frameRate);
			}
			cameraThread_ = new rtabmap::CameraThread(camera_);
			init();
			if(!pause)
			{
				start();
			}
		}
	}

protected:
	virtual void handleEvent(UEvent * event)
	{
		if(event->getClassName().compare("CameraEvent") == 0)
		{
			rtabmap::CameraEvent * e = (rtabmap::CameraEvent*)event;
			const cv::Mat & image = e->data().imageRaw();
			if(!image.empty() && image.depth() == CV_8U)
			{
				cv_bridge::CvImage img;
				if(image.channels() == 1)
				{
					img.encoding = sensor_msgs::image_encodings::MONO8;
				}
				else
				{
					img.encoding = sensor_msgs::image_encodings::BGR8;
				}
				img.image = image;
				sensor_msgs::ImagePtr rosMsg = img.toImageMsg();
				rosMsg->header.frame_id = frameId_;
				rosMsg->header.stamp = ros::Time::now();
				rosPublisher_.publish(rosMsg);
			}
		}
	}

private:
	image_transport::Publisher rosPublisher_;
	rtabmap::CameraThread * cameraThread_;
	rtabmap::Camera * camera_;
	ros::ServiceServer startSrv_;
	ros::ServiceServer stopSrv_;
	std::string frameId_;
};

CameraWrapper * camera = 0;
void callback(rtabmap_ros::CameraConfig &config, uint32_t level)
{
	if(camera)
	{
		camera->setParameters(config.device_id, config.frame_rate, config.video_or_images_path, config.pause);
	}
}

int main(int argc, char** argv)
{
	ULogger::setType(ULogger::kTypeConsole);
	//ULogger::setLevel(ULogger::kDebug);
	ULogger::setEventLevel(ULogger::kWarning);

	ros::init(argc, argv, "camera");

	ros::NodeHandle nh("~");

	camera = new CameraWrapper(); // webcam device 0

	dynamic_reconfigure::Server<rtabmap_ros::CameraConfig> server;
	dynamic_reconfigure::Server<rtabmap_ros::CameraConfig>::CallbackType f;
	f = boost::bind(&callback, _1, _2);
	server.setCallback(f);

	ros::spin();

	//cleanup
	if(camera)
	{
		delete camera;
	}

	return 0;
}
<|endoftext|>


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

#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)

#include "platform/mbed_poll.h"
#include "platform/mbed_thread.h"

namespace mbed {

UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
    SerialBase(tx, rx, baud),
    _blocking(true),
    _tx_irq_enabled(false),
    _rx_irq_enabled(false),
    _tx_enabled(true),
    _rx_enabled(true),
    _dcd_irq(NULL)
{
    /* Attatch IRQ routines to the serial device. */
    enable_rx_irq();
}

UARTSerial::~UARTSerial()
{
    delete _dcd_irq;
}

void UARTSerial::dcd_irq()
{
    wake();
}

void UARTSerial::set_baud(int baud)
{
    SerialBase::baud(baud);
}

void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
{
    delete _dcd_irq;
    _dcd_irq = NULL;

    if (dcd_pin != NC) {
        _dcd_irq = new InterruptIn(dcd_pin);
        if (active_high) {
            _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq));
        } else {
            _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq));
        }
    }
}

void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
{
    api_lock();
    SerialBase::format(bits, parity, stop_bits);
    api_unlock();
}

#if DEVICE_SERIAL_FC
void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
{
    api_lock();
    SerialBase::set_flow_control(type, flow1, flow2);
    api_unlock();
}
#endif

int UARTSerial::close()
{
    /* Does not let us pass a file descriptor. So how to close ?
     * Also, does it make sense to close a device type file descriptor*/
    return 0;
}

int UARTSerial::isatty()
{
    return 1;

}

off_t UARTSerial::seek(off_t offset, int whence)
{
    /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
     * buffer system (from an interrupt context) */
    return -ESPIPE;
}

int UARTSerial::sync()
{
    api_lock();

    while (!_txbuf.empty()) {
        api_unlock();
        // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
        thread_sleep_for(1);
        api_lock();
    }

    api_unlock();

    return 0;
}

void UARTSerial::sigio(Callback<void()> func)
{
    core_util_critical_section_enter();
    _sigio_cb = func;
    if (_sigio_cb) {
        short current_events = poll(0x7FFF);
        if (current_events) {
            _sigio_cb();
        }
    }
    core_util_critical_section_exit();
}

/* Special synchronous write designed to work from critical section, such
 * as in mbed_error_vprintf.
 */
ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
{
    while (!_txbuf.empty()) {
        tx_irq();
    }

    for (size_t data_written = 0; data_written < length; data_written++) {
        SerialBase::_base_putc(*buf_ptr++);
    }

    return length;
}

ssize_t UARTSerial::write(const void *buffer, size_t length)
{
    size_t data_written = 0;
    const char *buf_ptr = static_cast<const char *>(buffer);

    if (length == 0) {
        return 0;
    }

    if (core_util_in_critical_section()) {
        return write_unbuffered(buf_ptr, length);
    }

    api_lock();

    // Unlike read, we should write the whole thing if blocking. POSIX only
    // allows partial as a side-effect of signal handling; it normally tries to
    // write everything if blocking. Without signals we can always write all.
    while (data_written < length) {

        if (_txbuf.full()) {
            if (!_blocking) {
                break;
            }
            do {
                api_unlock();
                thread_sleep_for(1); // XXX todo - proper wait?
                api_lock();
            } while (_txbuf.full());
        }

        while (data_written < length && !_txbuf.full()) {
            _txbuf.push(*buf_ptr++);
            data_written++;
        }

        core_util_critical_section_enter();
        if (_tx_enabled && !_tx_irq_enabled) {
            UARTSerial::tx_irq();                // only write to hardware in one place
            if (!_txbuf.empty()) {
                enable_tx_irq();
            }
        }
        core_util_critical_section_exit();
    }

    api_unlock();

    return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
}

ssize_t UARTSerial::read(void *buffer, size_t length)
{
    size_t data_read = 0;

    char *ptr = static_cast<char *>(buffer);

    if (length == 0) {
        return 0;
    }

    api_lock();

    while (_rxbuf.empty()) {
        if (!_blocking) {
            api_unlock();
            return -EAGAIN;
        }
        api_unlock();
        thread_sleep_for(1);  // XXX todo - proper wait?
        api_lock();
    }

    while (data_read < length && !_rxbuf.empty()) {
        _rxbuf.pop(*ptr++);
        data_read++;
    }

    core_util_critical_section_enter();
    if (_rx_enabled && !_rx_irq_enabled) {
        UARTSerial::rx_irq();               // only read from hardware in one place
        if (!_rxbuf.full()) {
            enable_rx_irq();
        }
    }
    core_util_critical_section_exit();

    api_unlock();

    return data_read;
}

bool UARTSerial::hup() const
{
    return _dcd_irq && _dcd_irq->read() != 0;
}

void UARTSerial::wake()
{
    if (_sigio_cb) {
        _sigio_cb();
    }
}

short UARTSerial::poll(short events) const
{

    short revents = 0;
    /* Check the Circular Buffer if space available for writing out */

    if (!_rxbuf.empty()) {
        revents |= POLLIN;
    }

    /* POLLHUP and POLLOUT are mutually exclusive */
    if (hup()) {
        revents |= POLLHUP;
    } else if (!_txbuf.full()) {
        revents |= POLLOUT;
    }

    /*TODO Handle other event types */

    return revents;
}

void UARTSerial::lock()
{
    // This is the override for SerialBase.
    // No lock required as we only use SerialBase from interrupt or from
    // inside our own critical section.
}

void UARTSerial::unlock()
{
    // This is the override for SerialBase.
}

void UARTSerial::api_lock(void)
{
    _mutex.lock();
}

void UARTSerial::api_unlock(void)
{
    _mutex.unlock();
}

void UARTSerial::rx_irq(void)
{
    bool was_empty = _rxbuf.empty();

    /* Fill in the receive buffer if the peripheral is readable
     * and receive buffer is not full. */
    while (!_rxbuf.full() && SerialBase::readable()) {
        char data = SerialBase::_base_getc();
        _rxbuf.push(data);
    }

    if (_rx_irq_enabled && _rxbuf.full()) {
        disable_rx_irq();
    }

    /* Report the File handler that data is ready to be read from the buffer. */
    if (was_empty && !_rxbuf.empty()) {
        wake();
    }
}

// Also called from write to start transfer
void UARTSerial::tx_irq(void)
{
    bool was_full = _txbuf.full();
    char data;

    /* Write to the peripheral if there is something to write
     * and if the peripheral is available to write. */
    while (SerialBase::writeable() && _txbuf.pop(data)) {
        SerialBase::_base_putc(data);
    }

    if (_tx_irq_enabled && _txbuf.empty()) {
        disable_tx_irq();
    }

    /* Report the File handler that data can be written to peripheral. */
    if (was_full && !_txbuf.full() && !hup()) {
        wake();
    }
}

/* These are all called from critical section */
void UARTSerial::enable_rx_irq()
{
    SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
    _rx_irq_enabled = true;
}

void UARTSerial::disable_rx_irq()
{
    SerialBase::attach(NULL, RxIrq);
    _rx_irq_enabled = false;
}

void UARTSerial::enable_tx_irq()
{
    SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
    _tx_irq_enabled = true;
}

void UARTSerial::disable_tx_irq()
{
    SerialBase::attach(NULL, TxIrq);
    _tx_irq_enabled = false;
}

int UARTSerial::enable_input(bool enabled)
{
    api_lock();
    SerialBase::enable_input(enabled);
    api_unlock();

    return 0;
}

int UARTSerial::enable_output(bool enabled)
{
    api_lock();
    SerialBase::enable_input(enabled);
    api_unlock();

    return 0;
}

} //namespace mbed

#endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
<commit_msg>Call correct method<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "drivers/UARTSerial.h"

#if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)

#include "platform/mbed_poll.h"
#include "platform/mbed_thread.h"

namespace mbed {

UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
    SerialBase(tx, rx, baud),
    _blocking(true),
    _tx_irq_enabled(false),
    _rx_irq_enabled(false),
    _tx_enabled(true),
    _rx_enabled(true),
    _dcd_irq(NULL)
{
    /* Attatch IRQ routines to the serial device. */
    enable_rx_irq();
}

UARTSerial::~UARTSerial()
{
    delete _dcd_irq;
}

void UARTSerial::dcd_irq()
{
    wake();
}

void UARTSerial::set_baud(int baud)
{
    SerialBase::baud(baud);
}

void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
{
    delete _dcd_irq;
    _dcd_irq = NULL;

    if (dcd_pin != NC) {
        _dcd_irq = new InterruptIn(dcd_pin);
        if (active_high) {
            _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq));
        } else {
            _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq));
        }
    }
}

void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
{
    api_lock();
    SerialBase::format(bits, parity, stop_bits);
    api_unlock();
}

#if DEVICE_SERIAL_FC
void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
{
    api_lock();
    SerialBase::set_flow_control(type, flow1, flow2);
    api_unlock();
}
#endif

int UARTSerial::close()
{
    /* Does not let us pass a file descriptor. So how to close ?
     * Also, does it make sense to close a device type file descriptor*/
    return 0;
}

int UARTSerial::isatty()
{
    return 1;

}

off_t UARTSerial::seek(off_t offset, int whence)
{
    /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
     * buffer system (from an interrupt context) */
    return -ESPIPE;
}

int UARTSerial::sync()
{
    api_lock();

    while (!_txbuf.empty()) {
        api_unlock();
        // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
        thread_sleep_for(1);
        api_lock();
    }

    api_unlock();

    return 0;
}

void UARTSerial::sigio(Callback<void()> func)
{
    core_util_critical_section_enter();
    _sigio_cb = func;
    if (_sigio_cb) {
        short current_events = poll(0x7FFF);
        if (current_events) {
            _sigio_cb();
        }
    }
    core_util_critical_section_exit();
}

/* Special synchronous write designed to work from critical section, such
 * as in mbed_error_vprintf.
 */
ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
{
    while (!_txbuf.empty()) {
        tx_irq();
    }

    for (size_t data_written = 0; data_written < length; data_written++) {
        SerialBase::_base_putc(*buf_ptr++);
    }

    return length;
}

ssize_t UARTSerial::write(const void *buffer, size_t length)
{
    size_t data_written = 0;
    const char *buf_ptr = static_cast<const char *>(buffer);

    if (length == 0) {
        return 0;
    }

    if (core_util_in_critical_section()) {
        return write_unbuffered(buf_ptr, length);
    }

    api_lock();

    // Unlike read, we should write the whole thing if blocking. POSIX only
    // allows partial as a side-effect of signal handling; it normally tries to
    // write everything if blocking. Without signals we can always write all.
    while (data_written < length) {

        if (_txbuf.full()) {
            if (!_blocking) {
                break;
            }
            do {
                api_unlock();
                thread_sleep_for(1); // XXX todo - proper wait?
                api_lock();
            } while (_txbuf.full());
        }

        while (data_written < length && !_txbuf.full()) {
            _txbuf.push(*buf_ptr++);
            data_written++;
        }

        core_util_critical_section_enter();
        if (_tx_enabled && !_tx_irq_enabled) {
            UARTSerial::tx_irq();                // only write to hardware in one place
            if (!_txbuf.empty()) {
                enable_tx_irq();
            }
        }
        core_util_critical_section_exit();
    }

    api_unlock();

    return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
}

ssize_t UARTSerial::read(void *buffer, size_t length)
{
    size_t data_read = 0;

    char *ptr = static_cast<char *>(buffer);

    if (length == 0) {
        return 0;
    }

    api_lock();

    while (_rxbuf.empty()) {
        if (!_blocking) {
            api_unlock();
            return -EAGAIN;
        }
        api_unlock();
        thread_sleep_for(1);  // XXX todo - proper wait?
        api_lock();
    }

    while (data_read < length && !_rxbuf.empty()) {
        _rxbuf.pop(*ptr++);
        data_read++;
    }

    core_util_critical_section_enter();
    if (_rx_enabled && !_rx_irq_enabled) {
        UARTSerial::rx_irq();               // only read from hardware in one place
        if (!_rxbuf.full()) {
            enable_rx_irq();
        }
    }
    core_util_critical_section_exit();

    api_unlock();

    return data_read;
}

bool UARTSerial::hup() const
{
    return _dcd_irq && _dcd_irq->read() != 0;
}

void UARTSerial::wake()
{
    if (_sigio_cb) {
        _sigio_cb();
    }
}

short UARTSerial::poll(short events) const
{

    short revents = 0;
    /* Check the Circular Buffer if space available for writing out */

    if (!_rxbuf.empty()) {
        revents |= POLLIN;
    }

    /* POLLHUP and POLLOUT are mutually exclusive */
    if (hup()) {
        revents |= POLLHUP;
    } else if (!_txbuf.full()) {
        revents |= POLLOUT;
    }

    /*TODO Handle other event types */

    return revents;
}

void UARTSerial::lock()
{
    // This is the override for SerialBase.
    // No lock required as we only use SerialBase from interrupt or from
    // inside our own critical section.
}

void UARTSerial::unlock()
{
    // This is the override for SerialBase.
}

void UARTSerial::api_lock(void)
{
    _mutex.lock();
}

void UARTSerial::api_unlock(void)
{
    _mutex.unlock();
}

void UARTSerial::rx_irq(void)
{
    bool was_empty = _rxbuf.empty();

    /* Fill in the receive buffer if the peripheral is readable
     * and receive buffer is not full. */
    while (!_rxbuf.full() && SerialBase::readable()) {
        char data = SerialBase::_base_getc();
        _rxbuf.push(data);
    }

    if (_rx_irq_enabled && _rxbuf.full()) {
        disable_rx_irq();
    }

    /* Report the File handler that data is ready to be read from the buffer. */
    if (was_empty && !_rxbuf.empty()) {
        wake();
    }
}

// Also called from write to start transfer
void UARTSerial::tx_irq(void)
{
    bool was_full = _txbuf.full();
    char data;

    /* Write to the peripheral if there is something to write
     * and if the peripheral is available to write. */
    while (SerialBase::writeable() && _txbuf.pop(data)) {
        SerialBase::_base_putc(data);
    }

    if (_tx_irq_enabled && _txbuf.empty()) {
        disable_tx_irq();
    }

    /* Report the File handler that data can be written to peripheral. */
    if (was_full && !_txbuf.full() && !hup()) {
        wake();
    }
}

/* These are all called from critical section */
void UARTSerial::enable_rx_irq()
{
    SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
    _rx_irq_enabled = true;
}

void UARTSerial::disable_rx_irq()
{
    SerialBase::attach(NULL, RxIrq);
    _rx_irq_enabled = false;
}

void UARTSerial::enable_tx_irq()
{
    SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
    _tx_irq_enabled = true;
}

void UARTSerial::disable_tx_irq()
{
    SerialBase::attach(NULL, TxIrq);
    _tx_irq_enabled = false;
}

int UARTSerial::enable_input(bool enabled)
{
    api_lock();
    SerialBase::enable_input(enabled);
    api_unlock();

    return 0;
}

int UARTSerial::enable_output(bool enabled)
{
    api_lock();
    SerialBase::enable_output(enabled);
    api_unlock();

    return 0;
}

} //namespace mbed

#endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
<|endoftext|>


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

#include "Teacher.h"
#include "TeacherPlugin.h"

namespace microbe {
    void Teacher::setLearningRate(const double value)
    {
        learningRate = value;
    }

    double Teacher::getLearningRate(void)
    {
        return learningRate;
    }

    void Teacher::setMomentum(const double value)
    {
        momentum = value;
    }

    void Teacher::addLearningSet(LearningSet& set)
    {
        learningSets.push_back(&set);
    }

    std::vector<LearningSet*> Teacher::getLearningSets(void)
    {
        return learningSets;
    }

    double Teacher::getLastEpochError(void)
    {
        return lastEpochError;
    }

    double Teacher::calculateSquaredErrorEpoch(void)
    {
        double error = 0;

        for (LearningSet* set : learningSets) {
            error += squaredError(*set);
        }

        lastEpochError = std::sqrt(error / learningSets.size());
        return lastEpochError;
    }

    bool Teacher::train(void)
    {
        calculateSquaredErrorEpoch();

        while (lastEpochError > goal) {
            firePreEpoch();
            trainEpoch();
            calculateSquaredErrorEpoch();
            firePostEpoch();
        }

        return true;
    }

    double Teacher::squaredError(LearningSet& set)
    {
        double error = 0.0;

        network->setValues(set.getInput());
        network->run();

        auto outputs = network->getOutput();
        auto expected = set.getOutput();

        for (int i = 0; i < outputs.size(); i++) {
            error += std::pow(outputs.at(i) - expected.at(i), 2);
        }

        return error;
    }

    void Teacher::registerPlugin(TeacherPlugin& plugin)
    {
        plugin.setTeacher(this);
        plugin.init();
        plugins.push_back(&plugin);
    }

    void Teacher::firePreEpoch(void)
    {
        for (TeacherPlugin *plugin : plugins) {
            plugin->preEpoch();
        }
    }

    void Teacher::firePostEpoch(void)
    {
        for (TeacherPlugin *plugin : plugins) {
            plugin->postEpoch();
        }
    }
}
<commit_msg>Missing body of setGoal() in Teacher class<commit_after>/**
 * Copyright 2014 Krzysztof Magosa
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Teacher.h"
#include "TeacherPlugin.h"

namespace microbe {
    void Teacher::setGoal(const double value)
    {
        goal = value;
    }

    void Teacher::setLearningRate(const double value)
    {
        learningRate = value;
    }

    double Teacher::getLearningRate(void)
    {
        return learningRate;
    }

    void Teacher::setMomentum(const double value)
    {
        momentum = value;
    }

    void Teacher::addLearningSet(LearningSet& set)
    {
        learningSets.push_back(&set);
    }

    std::vector<LearningSet*> Teacher::getLearningSets(void)
    {
        return learningSets;
    }

    double Teacher::getLastEpochError(void)
    {
        return lastEpochError;
    }

    double Teacher::calculateSquaredErrorEpoch(void)
    {
        double error = 0;

        for (LearningSet* set : learningSets) {
            error += squaredError(*set);
        }

        lastEpochError = std::sqrt(error / learningSets.size());
        return lastEpochError;
    }

    bool Teacher::train(void)
    {
        calculateSquaredErrorEpoch();

        while (lastEpochError > goal) {
            firePreEpoch();
            trainEpoch();
            calculateSquaredErrorEpoch();
            firePostEpoch();
        }

        return true;
    }

    double Teacher::squaredError(LearningSet& set)
    {
        double error = 0.0;

        network->setValues(set.getInput());
        network->run();

        auto outputs = network->getOutput();
        auto expected = set.getOutput();

        for (int i = 0; i < outputs.size(); i++) {
            error += std::pow(outputs.at(i) - expected.at(i), 2);
        }

        return error;
    }

    void Teacher::registerPlugin(TeacherPlugin& plugin)
    {
        plugin.setTeacher(this);
        plugin.init();
        plugins.push_back(&plugin);
    }

    void Teacher::firePreEpoch(void)
    {
        for (TeacherPlugin *plugin : plugins) {
            plugin->preEpoch();
        }
    }

    void Teacher::firePostEpoch(void)
    {
        for (TeacherPlugin *plugin : plugins) {
            plugin->postEpoch();
        }
    }
}
<|endoftext|>