<commit_before>/** \file    util.cc
 *  \brief   Implementation of various utility functions.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015,2017,2018 Library of the University of Tübingen

    This program 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.

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "util.h"
#include <iterator>
#include <stdexcept>
#include <cctype>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include "Compiler.h"
#include "MiscUtil.h"
#include "TimeUtil.h"

// Macro to determine the number of entries in a one-dimensional array:
#define DIM(array) (sizeof(array) / sizeof(array[0]))

char *progname; // Must be set in main() with "progname = argv[0];";

Logger::Logger()
    : fd_(STDERR_FILENO), log_process_pids_(false), log_no_decorations_(false), log_strip_call_site_(false),
      min_log_level_(LL_INFO)
{
    const char * const min_log_level(::getenv("MIN_LOG_LEVEL"));
    if (min_log_level != nullptr)
        min_log_level_ = Logger::StringToLogLevel(min_log_level);
    const char * const logger_format(::getenv("LOGGER_FORMAT"));
    if (logger_format != nullptr) {
        if (std::strstr(logger_format, "process_pids") != nullptr)
            log_process_pids_ = true;
        if (std::strstr(logger_format, "no_decorations") != nullptr)
            log_no_decorations_ = true;
        if (std::strstr(logger_format, "strip_call_site") != nullptr)
            log_strip_call_site_ = true;
    }
}

void Logger::error(const std::string &msg) {
    std::lock_guard<std::mutex> mutex_locker(mutex_);

    writeString("SEVERE", msg);
    if (::getenv("BACKTRACE") != nullptr) {
        const bool saved_log_no_decorations(log_no_decorations_);
        log_no_decorations_ = true;
        writeString("", "Backtrace:");
        for (const auto &stack_entry : MiscUtil::GetCallStack())
            writeString("", "  " + stack_entry);
        log_no_decorations_ = saved_log_no_decorations;
    }

    std::exit(EXIT_FAILURE);
}

void Logger::warning(const std::string &msg) {
    if (min_log_level_ < LL_WARNING)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("WARN", msg);
}

void Logger::info(const std::string &msg) {
    if (min_log_level_ < LL_INFO)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("INFO", msg);
}

void Logger::debug(const std::string &msg) {
    if ((min_log_level_ < LL_DEBUG) and (MiscUtil::SafeGetEnv("UTIL_LOG_DEBUG") != "true"))
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("DEBUG", msg);
}

inline Logger *LoggerInstantiator() {
    return new Logger();
}

Logger *logger(LoggerInstantiator());

Logger::LogLevel Logger::StringToLogLevel(const std::string &level_candidate) {
    if (level_candidate == "ERROR")
        return Logger::LL_ERROR;
    if (level_candidate == "WARNING")
        return Logger::LL_WARNING;
    if (level_candidate == "INFO")
        return Logger::LL_INFO;
    if (level_candidate == "DEBUG")
        return Logger::LL_DEBUG;
    LOG_ERROR("not a valid minimum log level: \"" + level_candidate + "\"! (Use ERROR, WARNING, INFO or DEBUG)");
}

std::string Logger::LogLevelToString(const LogLevel log_level) {
    if (log_level == Logger::LL_ERROR)
        return "ERROR";
    if (log_level == Logger::LL_WARNING)
        return "WARNING";
    if (log_level == Logger::LL_INFO)
        return "INFO";
    if (log_level == Logger::LL_DEBUG)
        return "DEBUG";
    LOG_ERROR("unsupported log level, we should *never* get here!");
}

void Logger::writeString(const std::string &level, std::string msg) {
    if (unlikely(::progname == nullptr))
        msg = "You must set \"progname\" in main() with \"::progname = argv[0];\" in oder to use the Logger API!";
    else if (not log_no_decorations_) {
        msg = TimeUtil::GetCurrentDateAndTime(TimeUtil::ISO_8601_FORMAT) + " " + level + " " + std::string(::progname) + ": "
              + msg;
        if (log_process_pids_)
            msg += " (PID: " + std::to_string(::getpid()) + ")";
    }

    if (log_strip_call_site_) {
        const auto END_OF_CALL_SITE_PREFIX(msg.find("): "));
        if (END_OF_CALL_SITE_PREFIX != std::string::npos)
            msg = msg.substr(END_OF_CALL_SITE_PREFIX + 3);
    }

    msg += '\n';

    if (unlikely(::write(fd_, reinterpret_cast<const void *>(msg.data()), msg.size()) == -1)) {
        const std::string error_message("in Logger::writeString(util.cc): write to file descriptor " + std::to_string(fd_)
                                        + " failed! (errno = " + std::to_string(errno) + ")");
        #pragma GCC diagnostic ignored "-Wunused-result"
        ::write(STDERR_FILENO, error_message.data(), error_message.size());
        #pragma GCC diagnostic warning "-Wunused-result"
        _exit(EXIT_FAILURE);
    }

    if (unlikely(::progname == nullptr))
        _exit(EXIT_FAILURE);
}

DSVReader::DSVReader(const std::string &filename, const char field_separator, const char field_delimiter)
    : field_separator_(field_separator), field_delimiter_(field_delimiter), line_no_(0), filename_(filename)
{
    input_ = std::fopen(filename.c_str(), "rm");
    if (input_ == nullptr)
        throw std::runtime_error("in DSVReader::DSVReader: can't open \"" + filename + "\" for reading!");
}

DSVReader::~DSVReader() {
    if (input_ != nullptr)
        std::fclose(input_);
}

namespace {

void SkipFieldPadding(FILE * const input) {
    int ch = std::fgetc(input);
    while (isblank(ch))
        ch = std::fgetc(input);
    std::ungetc(ch, input);
}

std::string ReadQuotedValue(FILE * const input, const char field_delimiter, const char field_separator) {
    std::string value;
    bool delimiter_seen(false);
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF)
            throw std::runtime_error("unexpected EOF while reading a quoted DSV value!");
        if (ch == field_delimiter) {
            if (delimiter_seen) {
                // ignore if it's not the outermost delimiter
                const int next(std::fgetc(input));
                std::ungetc(next, input);

                if (next == field_separator or next == '\n' or next == EOF)
                    return value;
                else
                    value += field_delimiter;
            } else
                delimiter_seen = true;
        } else
            value += static_cast<char>(ch);
    }
}

/** \brief Remove trailing spaces and tabs from "s". */
std::string TrimBlanks(std::string * s) {
    std::string::const_reverse_iterator it(s->crbegin());
    for (/* Empty! */; it != s->crend() and std::isblank(*it); ++it)
        /* Intentionally Empty! */;
    if (it != s->crbegin())
        *s = s->substr(0, std::distance(it, s->crend()));

    return *s;
}

std::string ReadNonQuotedValue(FILE * const input, const char field_separator) {
    std::string value;
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF or ch == '\n' or ch == field_separator) {
            std::ungetc(ch, input);
            return TrimBlanks(&value);
        }
        value += static_cast<char>(ch);
    }
}

void BacktraceSignalHandler(int signal_no) {
    void *stack_return_addresses[20];
    const size_t number_of_addresses(::backtrace(stack_return_addresses, DIM(stack_return_addresses)));
    char err_msg[1024] = "Caught signal ";
    char *cp = err_msg + std::strlen(err_msg);
    if (signal_no > 10)
        *cp++ = '0' + (signal_no / 10);
    *cp++ = '0' + (signal_no % 10);
    *cp++ = '.';
    *cp++ = '\n';
    *cp = '\0';
    ssize_t unused(::write(STDERR_FILENO, err_msg, std::strlen(err_msg)));
    (void)unused;
    ::backtrace_symbols_fd(stack_return_addresses, number_of_addresses, STDERR_FILENO);
    ::_exit(EXIT_FAILURE);
}

int InstallSegvSignalHandler(void handler(int)) {
    ::signal(SIGSEGV, handler);
    return 0;
}

volatile int dummy = InstallSegvSignalHandler(BacktraceSignalHandler);

} // unnamed namespace

bool DSVReader::readLine(std::vector<std::string> * const values) {
    values->clear();
    ++line_no_;

    int ch;
    for (;;) {
        if (not values->empty()) {
            SkipFieldPadding(input_);
            ch = std::fgetc(input_);
            if (ch == EOF)
                return not values->empty();
            if (ch == '\n')
                return true;
            if (ch != field_separator_)
                throw std::runtime_error("in DSVReader::readLine: on line " + std::to_string(line_no_)
                                         + ": field separator expected, found '"
                                         + std::string(1, static_cast<char>(ch)) + "' instead!");
        }

        SkipFieldPadding(input_);
        ch = std::fgetc(input_);
        if (ch == '\n')
            return true;
        if (ch == EOF)
            return not values->empty();
        if (ch == field_separator_) {
            std::ungetc(ch, input_);
            values->emplace_back("");
        } else if (ch == field_delimiter_) {
            std::ungetc(ch, input_);
            values->emplace_back(ReadQuotedValue(input_, field_delimiter_, field_separator_));
        } else {
            std::ungetc(ch, input_);
            values->emplace_back(ReadNonQuotedValue(input_, field_separator_));
        }
    }
}
<commit_msg>Fix handling of trailing spaces after quoted string<commit_after>/** \file    util.cc
 *  \brief   Implementation of various utility functions.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015,2017,2018 Library of the University of Tübingen

    This program 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.

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "util.h"
#include <iterator>
#include <stdexcept>
#include <cctype>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include "Compiler.h"
#include "MiscUtil.h"
#include "TimeUtil.h"

// Macro to determine the number of entries in a one-dimensional array:
#define DIM(array) (sizeof(array) / sizeof(array[0]))

char *progname; // Must be set in main() with "progname = argv[0];";

Logger::Logger()
    : fd_(STDERR_FILENO), log_process_pids_(false), log_no_decorations_(false), log_strip_call_site_(false),
      min_log_level_(LL_INFO)
{
    const char * const min_log_level(::getenv("MIN_LOG_LEVEL"));
    if (min_log_level != nullptr)
        min_log_level_ = Logger::StringToLogLevel(min_log_level);
    const char * const logger_format(::getenv("LOGGER_FORMAT"));
    if (logger_format != nullptr) {
        if (std::strstr(logger_format, "process_pids") != nullptr)
            log_process_pids_ = true;
        if (std::strstr(logger_format, "no_decorations") != nullptr)
            log_no_decorations_ = true;
        if (std::strstr(logger_format, "strip_call_site") != nullptr)
            log_strip_call_site_ = true;
    }
}

void Logger::error(const std::string &msg) {
    std::lock_guard<std::mutex> mutex_locker(mutex_);

    writeString("SEVERE", msg);
    if (::getenv("BACKTRACE") != nullptr) {
        const bool saved_log_no_decorations(log_no_decorations_);
        log_no_decorations_ = true;
        writeString("", "Backtrace:");
        for (const auto &stack_entry : MiscUtil::GetCallStack())
            writeString("", "  " + stack_entry);
        log_no_decorations_ = saved_log_no_decorations;
    }

    std::exit(EXIT_FAILURE);
}

void Logger::warning(const std::string &msg) {
    if (min_log_level_ < LL_WARNING)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("WARN", msg);
}

void Logger::info(const std::string &msg) {
    if (min_log_level_ < LL_INFO)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("INFO", msg);
}

void Logger::debug(const std::string &msg) {
    if ((min_log_level_ < LL_DEBUG) and (MiscUtil::SafeGetEnv("UTIL_LOG_DEBUG") != "true"))
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("DEBUG", msg);
}

inline Logger *LoggerInstantiator() {
    return new Logger();
}

Logger *logger(LoggerInstantiator());

Logger::LogLevel Logger::StringToLogLevel(const std::string &level_candidate) {
    if (level_candidate == "ERROR")
        return Logger::LL_ERROR;
    if (level_candidate == "WARNING")
        return Logger::LL_WARNING;
    if (level_candidate == "INFO")
        return Logger::LL_INFO;
    if (level_candidate == "DEBUG")
        return Logger::LL_DEBUG;
    LOG_ERROR("not a valid minimum log level: \"" + level_candidate + "\"! (Use ERROR, WARNING, INFO or DEBUG)");
}

std::string Logger::LogLevelToString(const LogLevel log_level) {
    if (log_level == Logger::LL_ERROR)
        return "ERROR";
    if (log_level == Logger::LL_WARNING)
        return "WARNING";
    if (log_level == Logger::LL_INFO)
        return "INFO";
    if (log_level == Logger::LL_DEBUG)
        return "DEBUG";
    LOG_ERROR("unsupported log level, we should *never* get here!");
}

void Logger::writeString(const std::string &level, std::string msg) {
    if (unlikely(::progname == nullptr))
        msg = "You must set \"progname\" in main() with \"::progname = argv[0];\" in oder to use the Logger API!";
    else if (not log_no_decorations_) {
        msg = TimeUtil::GetCurrentDateAndTime(TimeUtil::ISO_8601_FORMAT) + " " + level + " " + std::string(::progname) + ": "
              + msg;
        if (log_process_pids_)
            msg += " (PID: " + std::to_string(::getpid()) + ")";
    }

    if (log_strip_call_site_) {
        const auto END_OF_CALL_SITE_PREFIX(msg.find("): "));
        if (END_OF_CALL_SITE_PREFIX != std::string::npos)
            msg = msg.substr(END_OF_CALL_SITE_PREFIX + 3);
    }

    msg += '\n';

    if (unlikely(::write(fd_, reinterpret_cast<const void *>(msg.data()), msg.size()) == -1)) {
        const std::string error_message("in Logger::writeString(util.cc): write to file descriptor " + std::to_string(fd_)
                                        + " failed! (errno = " + std::to_string(errno) + ")");
        #pragma GCC diagnostic ignored "-Wunused-result"
        ::write(STDERR_FILENO, error_message.data(), error_message.size());
        #pragma GCC diagnostic warning "-Wunused-result"
        _exit(EXIT_FAILURE);
    }

    if (unlikely(::progname == nullptr))
        _exit(EXIT_FAILURE);
}

DSVReader::DSVReader(const std::string &filename, const char field_separator, const char field_delimiter)
    : field_separator_(field_separator), field_delimiter_(field_delimiter), line_no_(0), filename_(filename)
{
    input_ = std::fopen(filename.c_str(), "rm");
    if (input_ == nullptr)
        throw std::runtime_error("in DSVReader::DSVReader: can't open \"" + filename + "\" for reading!");
}

DSVReader::~DSVReader() {
    if (input_ != nullptr)
        std::fclose(input_);
}

namespace {

void SkipFieldPadding(FILE * const input) {
    int ch = std::fgetc(input);
    while (isblank(ch))
        ch = std::fgetc(input);
    std::ungetc(ch, input);
}

/** \brief Remove trailing spaces and tabs from "s". */
std::string TrimBlanks(std::string * s) {
    std::string::const_reverse_iterator it(s->crbegin());
    for (/* Empty! */; it != s->crend() and std::isblank(*it); ++it)
        /* Intentionally Empty! */;
    if (it != s->crbegin())
        *s = s->substr(0, std::distance(it, s->crend()));

    return *s;
}

std::string ReadQuotedValue(FILE * const input, const char field_delimiter, const char field_separator) {
    std::string value;
    bool delimiter_seen(false);
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF)
            throw std::runtime_error("unexpected EOF while reading a quoted DSV value!");
        if (ch == field_delimiter) {
            if (delimiter_seen) {
                // ignore if it's not the outermost delimiter
                const int next(std::fgetc(input));
                std::ungetc(next, input);

                if (next == field_separator or next == '\n' or next == EOF)
                    return value;
            } else
                delimiter_seen = true;
        } else {
            if (ch == '\n' or ch == EOF) {
                std::ungetc(ch, input);
                return TrimBlanks(&value);
            }
            value += static_cast<char>(ch);
        }
    }
}

std::string ReadNonQuotedValue(FILE * const input, const char field_separator) {
    std::string value;
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF or ch == '\n' or ch == field_separator) {
            std::ungetc(ch, input);
            return TrimBlanks(&value);
        }
        value += static_cast<char>(ch);
    }
}

void BacktraceSignalHandler(int signal_no) {
    void *stack_return_addresses[20];
    const size_t number_of_addresses(::backtrace(stack_return_addresses, DIM(stack_return_addresses)));
    char err_msg[1024] = "Caught signal ";
    char *cp = err_msg + std::strlen(err_msg);
    if (signal_no > 10)
        *cp++ = '0' + (signal_no / 10);
    *cp++ = '0' + (signal_no % 10);
    *cp++ = '.';
    *cp++ = '\n';
    *cp = '\0';
    ssize_t unused(::write(STDERR_FILENO, err_msg, std::strlen(err_msg)));
    (void)unused;
    ::backtrace_symbols_fd(stack_return_addresses, number_of_addresses, STDERR_FILENO);
    ::_exit(EXIT_FAILURE);
}

int InstallSegvSignalHandler(void handler(int)) {
    ::signal(SIGSEGV, handler);
    return 0;
}

volatile int dummy = InstallSegvSignalHandler(BacktraceSignalHandler);

} // unnamed namespace

bool DSVReader::readLine(std::vector<std::string> * const values) {
    values->clear();
    ++line_no_;

    int ch;
    for (;;) {
        if (not values->empty()) {
            SkipFieldPadding(input_);
            ch = std::fgetc(input_);
            if (ch == EOF)
                return not values->empty();
            if (ch == '\n')
                return true;
            if (ch != field_separator_)
                throw std::runtime_error("in DSVReader::readLine: on line " + std::to_string(line_no_)
                                         + ": field separator expected, found '"
                                         + std::string(1, static_cast<char>(ch)) + "' instead!");
        }

        SkipFieldPadding(input_);
        ch = std::fgetc(input_);
        if (ch == '\n')
            return true;
        if (ch == EOF)
            return not values->empty();
        if (ch == field_separator_) {
            std::ungetc(ch, input_);
            values->emplace_back("");
        } else if (ch == field_delimiter_) {
            std::ungetc(ch, input_);
            values->emplace_back(ReadQuotedValue(input_, field_delimiter_, field_separator_));
        } else {
            std::ungetc(ch, input_);
            values->emplace_back(ReadNonQuotedValue(input_, field_separator_));
        }
    }
}
<|endoftext|>


<commit_before>#include "dsa_common.h"

#include "broker_config.h"

#include <boost/filesystem.hpp>
#include <iostream>
#include "module/logger.h"

namespace fs = boost::filesystem;

namespace dsa {
BrokerConfig::BrokerConfig(int argc, const char* argv[]) {
  init();
  load();
}

const string_& BrokerConfig::get_file_path() {
  static string_ default_path = "broker.json";

  if (_file_path.empty()) {
    return default_path;
  }
  return _file_path;
}

// init all the config properties
void BrokerConfig::init() {
  add_item("thread", Var(2), VarValidatorInt(1, 100));
  add_item("host", Var("0.0.0.0"), [](const Var& var) {
    return var.is_string() && !var.get_string().empty();
  });
  add_item("port", Var(4120), VarValidatorInt(0, 65535));
  add_item("secure-port", Var(-1), VarValidatorInt(-1, 65535));
  add_item("http-port", Var(8080), VarValidatorInt(1, 65535));
  add_item("https-port", Var(8443), VarValidatorInt(1, 65535));
  add_item("log-level", Var("warn"), [](const Var& var) {
    string_ str = var.to_string();
    return str == "trace" || str == "debug" || str == "info" || str == "warn" ||
           str == "error" || str == "fatal";
  });
}
// load config json from file
void BrokerConfig::load() {
  auto& path = get_file_path();
  if (fs::exists(path)) {
    if (fs::is_regular_file(path)) {
      std::ifstream config_file(get_file_path(), std::ios::in);
      if (config_file.is_open()) {
        std::stringstream buffer;
        buffer << config_file.rdbuf();
        Var data = Var::from_json(buffer.str());
        if (data.is_map()) {
          try {
            // allows config to be stored in different location
            if (_file_path.empty() && data.get_map().count("config-path") > 0 &&
                !data["config-path"].to_string().empty()) {
              // load broker config from different path
              _file_path = data["config-path"].get_string();
              load();
              return;
            }
          } catch (std::exception& e) {
            // config-path doesn't exist, use default
          }
          for (auto& it : data.get_map()) {
            auto search = _items.find(it.first);
            if (search != _items.end()) {
              search->second.set_value(std::move(it.second));
            }
          }
          return;
        }
      }
    }

    LOG_FATAL(LOG << "failed to open broker config file: " << path);
  } else {
    // config doesn't exist, write a default config file
    save();
  }
}
void BrokerConfig::save() {
  auto& path = get_file_path();
  std::ofstream config_file(path, std::ios::out | std::ios::trunc);
  if (config_file.is_open()) {
    config_file << "{\n"
                << R"("dsa-version": ")" << int(DSA_MAJOR_VERSION) << "."
                << int(DSA_MINOR_VERSION) << "\",\n";
#ifdef DSA_DEBUG
    config_file << R"("broker-build": "debug")";
#else
    config_file << R"("broker-build": "release")";
#endif
    for (auto& name : _names) {
      config_file << ",\n\"" << name << "\": ";
      config_file << _items[name].get_value().to_json(2);
    }
    config_file << "\n}";
  } else {
    LOG_ERROR(Logger::_(), LOG << "failed to write the broker config file");
  }
}
void BrokerConfig::add_item(const string_& name, Var&& value,
                            VarValidator&& validator) {
  _names.emplace_back(name);
  _items.emplace(name,
                 BrokerConfigItem(std::move(value), std::move(validator)));
}
}
<commit_msg>update to macro _DSA_DEBUG<commit_after>#include "dsa_common.h"

#include "broker_config.h"

#include <boost/filesystem.hpp>
#include <iostream>
#include "module/logger.h"

namespace fs = boost::filesystem;

namespace dsa {
BrokerConfig::BrokerConfig(int argc, const char* argv[]) {
  init();
  load();
}

const string_& BrokerConfig::get_file_path() {
  static string_ default_path = "broker.json";

  if (_file_path.empty()) {
    return default_path;
  }
  return _file_path;
}

// init all the config properties
void BrokerConfig::init() {
  add_item("thread", Var(2), VarValidatorInt(1, 100));
  add_item("host", Var("0.0.0.0"), [](const Var& var) {
    return var.is_string() && !var.get_string().empty();
  });
  add_item("port", Var(4120), VarValidatorInt(0, 65535));
  add_item("secure-port", Var(-1), VarValidatorInt(-1, 65535));
  add_item("http-port", Var(8080), VarValidatorInt(1, 65535));
  add_item("https-port", Var(8443), VarValidatorInt(1, 65535));
  add_item("log-level", Var("warn"), [](const Var& var) {
    string_ str = var.to_string();
    return str == "trace" || str == "debug" || str == "info" || str == "warn" ||
           str == "error" || str == "fatal";
  });
}
// load config json from file
void BrokerConfig::load() {
  auto& path = get_file_path();
  if (fs::exists(path)) {
    if (fs::is_regular_file(path)) {
      std::ifstream config_file(get_file_path(), std::ios::in);
      if (config_file.is_open()) {
        std::stringstream buffer;
        buffer << config_file.rdbuf();
        Var data = Var::from_json(buffer.str());
        if (data.is_map()) {
          try {
            // allows config to be stored in different location
            if (_file_path.empty() && data.get_map().count("config-path") > 0 &&
                !data["config-path"].to_string().empty()) {
              // load broker config from different path
              _file_path = data["config-path"].get_string();
              load();
              return;
            }
          } catch (std::exception& e) {
            // config-path doesn't exist, use default
          }
          for (auto& it : data.get_map()) {
            auto search = _items.find(it.first);
            if (search != _items.end()) {
              search->second.set_value(std::move(it.second));
            }
          }
          return;
        }
      }
    }

    LOG_FATAL(LOG << "failed to open broker config file: " << path);
  } else {
    // config doesn't exist, write a default config file
    save();
  }
}
void BrokerConfig::save() {
  auto& path = get_file_path();
  std::ofstream config_file(path, std::ios::out | std::ios::trunc);
  if (config_file.is_open()) {
    config_file << "{\n"
                << R"("dsa-version": ")" << int(DSA_MAJOR_VERSION) << "."
                << int(DSA_MINOR_VERSION) << "\",\n";
#ifdef _DSA_DEBUG
    config_file << R"("broker-build": "debug")";
#else
    config_file << R"("broker-build": "release")";
#endif
    for (auto& name : _names) {
      config_file << ",\n\"" << name << "\": ";
      config_file << _items[name].get_value().to_json(2);
    }
    config_file << "\n}";
  } else {
    LOG_ERROR(Logger::_(), LOG << "failed to write the broker config file");
  }
}
void BrokerConfig::add_item(const string_& name, Var&& value,
                            VarValidator&& validator) {
  _names.emplace_back(name);
  _items.emplace(name,
                 BrokerConfigItem(std::move(value), std::move(validator)));
}
}
<|endoftext|>


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

// Authors: Ge,Jun (gejun@baidu.com)

#include <google/protobuf/descriptor.h>         // MethodDescriptor
#include <google/protobuf/message.h>            // Message
#include <gflags/gflags.h>
#include "butil/logging.h"                       // LOG()
#include "butil/time.h"
#include "butil/iobuf.h"                         // butil::IOBuf
#include "brpc/controller.h"               // Controller
#include "brpc/details/controller_private_accessor.h"
#include "brpc/socket.h"                   // Socket
#include "brpc/server.h"                   // Server
#include "brpc/details/server_private_accessor.h"
#include "brpc/span.h"
#include "brpc/redis.h"
#include "brpc/policy/redis_protocol.h"

namespace brpc {

DECLARE_bool(enable_rpcz);

namespace policy {

DEFINE_bool(redis_verbose, false,
            "[DEBUG] Print EVERY redis request/response to stderr");

struct InputResponse : public InputMessageBase {
    bthread_id_t id_wait;
    RedisResponse response;

    // @InputMessageBase
    void DestroyImpl() {
        delete this;
    }
};

// "Message" = "Response" as we only implement the client for redis.
ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket,
                              bool /*read_eof*/, const void* /*arg*/) {
    if (source->empty()) {
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    // NOTE(gejun): PopPipelinedInfo() is actually more contended than what
    // I thought before. The Socket._pipeline_q is a SPSC queue pushed before
    // sending and popped when response comes back, being protected by a
    // mutex. Previously the mutex is shared with Socket._id_wait_list. When
    // 200 bthreads access one redis-server, ~1.5s in total is spent on
    // contention in 10-second duration. If the mutex is separated, the time
    // drops to ~0.25s. I further replaced PeekPipelinedInfo() with
    // GivebackPipelinedInfo() to lock only once(when receiving response)
    // in most cases, and the time decreases to ~0.14s.
    PipelinedInfo pi;
    if (!socket->PopPipelinedInfo(&pi)) {
        LOG(WARNING) << "No corresponding PipelinedInfo in socket";
        return MakeParseError(PARSE_ERROR_TRY_OTHERS);
    }

    do {
        InputResponse* msg = static_cast<InputResponse*>(socket->parsing_context());
        if (msg == NULL) {
            msg = new InputResponse;
            socket->reset_parsing_context(msg);
        }

        const int consume_count = (pi.with_auth ? 1 : pi.count);

        if (!msg->response.ConsumePartialIOBuf(*source, consume_count)) {
            socket->GivebackPipelinedInfo(pi);
            return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
        }

        if (pi.with_auth) {
            if (msg->response.reply_size() != 1) {
                socket->GivebackPipelinedInfo(pi);
                return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
            }

            DestroyingPtr<InputResponse> auth_msg(
                 static_cast<InputResponse*>(socket->release_parsing_context()));
            if (!(auth_msg->response.reply(0).type() == brpc::REDIS_REPLY_STATUS &&
                  auth_msg->response.reply(0).data().compare("OK") == 0)) {
                LOG(ERROR) << "Redis Auth failed: " << auth_msg->response.reply(0);
            }
            pi.with_auth = false;
            continue;
        }

        CHECK_EQ((uint32_t)msg->response.reply_size(), pi.count);
        msg->id_wait = pi.id_wait;
        socket->release_parsing_context();
        return MakeMessage(msg);
    } while(true);

    return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
}

void ProcessRedisResponse(InputMessageBase* msg_base) {
    const int64_t start_parse_us = butil::cpuwide_time_us();
    DestroyingPtr<InputResponse> msg(static_cast<InputResponse*>(msg_base));

    const bthread_id_t cid = msg->id_wait;
    Controller* cntl = NULL;
    const int rc = bthread_id_lock(cid, (void**)&cntl);
    if (rc != 0) {
        LOG_IF(ERROR, rc != EINVAL && rc != EPERM)
            << "Fail to lock correlation_id=" << cid << ": " << berror(rc);
        return;
    }

    ControllerPrivateAccessor accessor(cntl);
    Span* span = accessor.span();
    if (span) {
        span->set_base_real_us(msg->base_real_us());
        span->set_received_us(msg->received_us());
        span->set_response_size(msg->response.ByteSize());
        span->set_start_parse_us(start_parse_us);
    }
    const int saved_error = cntl->ErrorCode();
    if (cntl->response() != NULL) {
        if (cntl->response()->GetDescriptor() != RedisResponse::descriptor()) {
            cntl->SetFailed(ERESPONSE, "Must be RedisResponse");
        } else {
            // We work around ParseFrom of pb which is just a placeholder.
            if (msg->response.reply_size() != (int)accessor.pipelined_count()) {
                cntl->SetFailed(ERESPONSE, "pipelined_count=%d of response does "
                                      "not equal request's=%d",
                                      msg->response.reply_size(), accessor.pipelined_count());
            }
            ((RedisResponse*)cntl->response())->Swap(&msg->response);
            if (FLAGS_redis_verbose) {
                std::cerr << "[REDIS RESPONSE] "
                          << *((RedisResponse*)cntl->response())
                          << std::endl;
            }
        }
    } // silently ignore the response.

    // Unlocks correlation_id inside. Revert controller's
    // error code if it version check of `cid' fails
    msg.reset();  // optional, just release resourse ASAP
    accessor.OnResponse(cid, saved_error);
}

void SerializeRedisRequest(butil::IOBuf* buf,
                           Controller* cntl,
                           const google::protobuf::Message* request) {
    if (request == NULL) {
        return cntl->SetFailed(EREQUEST, "request is NULL");
    }
    if (request->GetDescriptor() != RedisRequest::descriptor()) {
        return cntl->SetFailed(EREQUEST, "The request is not a RedisRequest");
    }
    const RedisRequest* rr = (const RedisRequest*)request;
    // We work around SerializeTo of pb which is just a placeholder.
    if (!rr->SerializeTo(buf)) {
        return cntl->SetFailed(EREQUEST, "Fail to serialize RedisRequest");
    }
    ControllerPrivateAccessor(cntl).set_pipelined_count(rr->command_size());
    if (FLAGS_redis_verbose) {
        std::cerr << "[REDIS REQUEST] " << *rr << std::endl;
    }
}

void PackRedisRequest(butil::IOBuf* buf,
                      SocketMessage**,
                      uint64_t /*correlation_id*/,
                      const google::protobuf::MethodDescriptor*,
                      Controller* cntl,
                      const butil::IOBuf& request,
                      const Authenticator* auth) {
    if (auth) {
        std::string auth_str;
        if (auth->GenerateCredential(&auth_str) != 0) {
            return cntl->SetFailed(EREQUEST, "Fail to generate credential");
        }
        buf->append(auth_str);
        ControllerPrivateAccessor(cntl).set_with_auth(true);
    } else {
        ControllerPrivateAccessor(cntl).set_with_auth(false);
    }

    buf->append(request);
}

const std::string& GetRedisMethodName(
    const google::protobuf::MethodDescriptor*,
    const Controller*) {
    const static std::string REDIS_SERVER_STR = "redis-server";
    return REDIS_SERVER_STR;
}

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

// Authors: Ge,Jun (gejun@baidu.com)

#include <google/protobuf/descriptor.h>         // MethodDescriptor
#include <google/protobuf/message.h>            // Message
#include <gflags/gflags.h>
#include "butil/logging.h"                       // LOG()
#include "butil/time.h"
#include "butil/iobuf.h"                         // butil::IOBuf
#include "brpc/controller.h"               // Controller
#include "brpc/details/controller_private_accessor.h"
#include "brpc/socket.h"                   // Socket
#include "brpc/server.h"                   // Server
#include "brpc/details/server_private_accessor.h"
#include "brpc/span.h"
#include "brpc/redis.h"
#include "brpc/policy/redis_protocol.h"

namespace brpc {

DECLARE_bool(enable_rpcz);

namespace policy {

DEFINE_bool(redis_verbose, false,
            "[DEBUG] Print EVERY redis request/response to stderr");

struct InputResponse : public InputMessageBase {
    bthread_id_t id_wait;
    RedisResponse response;

    // @InputMessageBase
    void DestroyImpl() {
        delete this;
    }
};

// "Message" = "Response" as we only implement the client for redis.
ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket,
                              bool /*read_eof*/, const void* /*arg*/) {
    if (source->empty()) {
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    // NOTE(gejun): PopPipelinedInfo() is actually more contended than what
    // I thought before. The Socket._pipeline_q is a SPSC queue pushed before
    // sending and popped when response comes back, being protected by a
    // mutex. Previously the mutex is shared with Socket._id_wait_list. When
    // 200 bthreads access one redis-server, ~1.5s in total is spent on
    // contention in 10-second duration. If the mutex is separated, the time
    // drops to ~0.25s. I further replaced PeekPipelinedInfo() with
    // GivebackPipelinedInfo() to lock only once(when receiving response)
    // in most cases, and the time decreases to ~0.14s.
    PipelinedInfo pi;
    if (!socket->PopPipelinedInfo(&pi)) {
        LOG(WARNING) << "No corresponding PipelinedInfo in socket";
        return MakeParseError(PARSE_ERROR_TRY_OTHERS);
    }

    do {
        InputResponse* msg = static_cast<InputResponse*>(socket->parsing_context());
        if (msg == NULL) {
            msg = new InputResponse;
            socket->reset_parsing_context(msg);
        }

        const int consume_count = (pi.with_auth ? 1 : pi.count);

        if (!msg->response.ConsumePartialIOBuf(*source, consume_count)) {
            socket->GivebackPipelinedInfo(pi);
            return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
        }

        if (pi.with_auth) {
            if (msg->response.reply_size() != 1 ||
                (!(msg->response.reply(0).type() == brpc::REDIS_REPLY_STATUS &&
                  msg->response.reply(0).data().compare("OK") == 0))) {
                LOG(ERROR) << "Redis Auth failed: " << msg->response;
                return MakeParseError(PARSE_ERROR_NO_RESOURCE,
                                      "Fail to authenticate with Redis");
            }

            DestroyingPtr<InputResponse> auth_msg(
                 static_cast<InputResponse*>(socket->release_parsing_context()));
            pi.with_auth = false;
            continue;
        }

        CHECK_EQ((uint32_t)msg->response.reply_size(), pi.count);
        msg->id_wait = pi.id_wait;
        socket->release_parsing_context();
        return MakeMessage(msg);
    } while(true);

    return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
}

void ProcessRedisResponse(InputMessageBase* msg_base) {
    const int64_t start_parse_us = butil::cpuwide_time_us();
    DestroyingPtr<InputResponse> msg(static_cast<InputResponse*>(msg_base));

    const bthread_id_t cid = msg->id_wait;
    Controller* cntl = NULL;
    const int rc = bthread_id_lock(cid, (void**)&cntl);
    if (rc != 0) {
        LOG_IF(ERROR, rc != EINVAL && rc != EPERM)
            << "Fail to lock correlation_id=" << cid << ": " << berror(rc);
        return;
    }

    ControllerPrivateAccessor accessor(cntl);
    Span* span = accessor.span();
    if (span) {
        span->set_base_real_us(msg->base_real_us());
        span->set_received_us(msg->received_us());
        span->set_response_size(msg->response.ByteSize());
        span->set_start_parse_us(start_parse_us);
    }
    const int saved_error = cntl->ErrorCode();
    if (cntl->response() != NULL) {
        if (cntl->response()->GetDescriptor() != RedisResponse::descriptor()) {
            cntl->SetFailed(ERESPONSE, "Must be RedisResponse");
        } else {
            // We work around ParseFrom of pb which is just a placeholder.
            if (msg->response.reply_size() != (int)accessor.pipelined_count()) {
                cntl->SetFailed(ERESPONSE, "pipelined_count=%d of response does "
                                      "not equal request's=%d",
                                      msg->response.reply_size(), accessor.pipelined_count());
            }
            ((RedisResponse*)cntl->response())->Swap(&msg->response);
            if (FLAGS_redis_verbose) {
                std::cerr << "[REDIS RESPONSE] "
                          << *((RedisResponse*)cntl->response())
                          << std::endl;
            }
        }
    } // silently ignore the response.

    // Unlocks correlation_id inside. Revert controller's
    // error code if it version check of `cid' fails
    msg.reset();  // optional, just release resourse ASAP
    accessor.OnResponse(cid, saved_error);
}

void SerializeRedisRequest(butil::IOBuf* buf,
                           Controller* cntl,
                           const google::protobuf::Message* request) {
    if (request == NULL) {
        return cntl->SetFailed(EREQUEST, "request is NULL");
    }
    if (request->GetDescriptor() != RedisRequest::descriptor()) {
        return cntl->SetFailed(EREQUEST, "The request is not a RedisRequest");
    }
    const RedisRequest* rr = (const RedisRequest*)request;
    // We work around SerializeTo of pb which is just a placeholder.
    if (!rr->SerializeTo(buf)) {
        return cntl->SetFailed(EREQUEST, "Fail to serialize RedisRequest");
    }
    ControllerPrivateAccessor(cntl).set_pipelined_count(rr->command_size());
    if (FLAGS_redis_verbose) {
        std::cerr << "[REDIS REQUEST] " << *rr << std::endl;
    }
}

void PackRedisRequest(butil::IOBuf* buf,
                      SocketMessage**,
                      uint64_t /*correlation_id*/,
                      const google::protobuf::MethodDescriptor*,
                      Controller* cntl,
                      const butil::IOBuf& request,
                      const Authenticator* auth) {
    if (auth) {
        std::string auth_str;
        if (auth->GenerateCredential(&auth_str) != 0) {
            return cntl->SetFailed(EREQUEST, "Fail to generate credential");
        }
        buf->append(auth_str);
        ControllerPrivateAccessor(cntl).set_with_auth(true);
    } else {
        ControllerPrivateAccessor(cntl).set_with_auth(false);
    }

    buf->append(request);
}

const std::string& GetRedisMethodName(
    const google::protobuf::MethodDescriptor*,
    const Controller*) {
    const static std::string REDIS_SERVER_STR = "redis-server";
    return REDIS_SERVER_STR;
}

}  // namespace policy
} // namespace brpc
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE new_reasoner_test

#include <vector>
#include <iostream>

#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/bind.hpp>

#include <lemon/color.h>
#include <lemon/graph_to_eps.h>

#include <lemon/core.h>
#include <lemon/concepts/digraph.h>
#include <lemon/list_graph.h>
#include <lemon/maps.h>

#include "graph.h"
#include "hypotheses.h"
#include "energy.h"
#include "reasoning/mrf_reasoner.h"
#include "traxels.h"

using namespace Tracking;
using namespace std;
using namespace boost;

BOOST_AUTO_TEST_CASE( HypothesesGraph_build_hyp ) {
    HypothesesGraph graph;
    graph.add_node(13);
}

BOOST_AUTO_TEST_CASE( HypothesesGraph_build_hyp2 ) {

  std::cout << "Constructing HypothesesGraph" << std::endl;
  std::cout <<  std::endl;

  typedef HypothesesGraph::ArcIt ArcIt2;
  typedef HypothesesGraph::Arc Arc;
  typedef HypothesesGraph::NodeIt NodeIt;
  typedef HypothesesGraph::Node Node;
  using lemon::INVALID;

  HypothesesGraph g;
  HypothesesGraph* graph=&g;
  graph->add(node_traxel());

  std::cout << "Adding nodes" << std::endl;
  std::cout <<  std::endl;

  Node n1=g.add_node(0);
  Node n2=g.add_node(0);
  Node n3=g.add_node(0);
  g.add_node(0);
  Node m1=g.add_node(1);
  Node m2=g.add_node(1);
  Node m3=g.add_node(1);
  Node m4=g.add_node(1);
  Node o1=g.add_node(2);
  Node o2=g.add_node(2);
  Node o3=g.add_node(2);
  Node o4=g.add_node(2);

  std::cout << "Nodes:";
  for (NodeIt i(g); i!=INVALID; ++i)
    std::cout << " " << g.id(i);
  std::cout << std::endl;

  std::cout << "Addings arcs" << std::endl;
  std::cout <<  std::endl;

  g.addArc(n1,m2);
  g.addArc(n2,m1);
  g.addArc(n3,m3);
  g.addArc(n3,m4);
  g.addArc(m1,o1);
  g.addArc(m2,o2);
  g.addArc(m4,o3);
  g.addArc(m4,o4);

  std::cout << "Arcs:";
  for (ArcIt2 i(g); i!=INVALID; ++i)
  std::cout << " (" << g.id(g.source(i)) << "," << g.id(g.target(i)) << ")";
  std::cout << std::endl;
  std::cout <<  std::endl;

  std::cout << "Constructing Reasoner" << std::endl;
  std::cout <<  std::endl;

   Traxels empty;
   ConstantEnergy e(25);

   SingleTimestepTraxelMrf mrf(bind<double>(e, _1, empty, empty),		//detection
			        bind<double>(e, _1, empty, empty),		//non_detection
			        bind<double>(e, _1, empty, empty),		//appearance
			        bind<double>(e, _1, empty, empty),		//disappearance
				bind<double>(e, _1, _2, empty, empty),		//move
				bind<double>(e, _1, _2, _3, empty, empty)	//division
			       );

  std::cout << "Formulating Factors" << std::endl;
  std::cout <<  std::endl;

    cout << "-> workflow: formulating model" << endl;
    mrf.formulate( *graph );
    cout << "-> workflow: infer" << endl;
    mrf.infer();
    cout << "-> workflow: conclude" << endl;
    mrf.conclude(*graph);
    prune_inactive(*graph);
}

BOOST_AUTO_TEST_CASE( HypothesesGraph_build_hyp_mrf ) {

    Traxel n1, n2, n3, n4, m1, m2, m3, m4, o1, o2, o3, o4, o5;
    feature_array comn1(feature_array::difference_type(3)); //float vector
    feature_array comn2(feature_array::difference_type(3));
    feature_array comn3(feature_array::difference_type(3));
    feature_array comn4(feature_array::difference_type(3));
    feature_array comm1(feature_array::difference_type(3));
    feature_array comm2(feature_array::difference_type(3));
    feature_array comm3(feature_array::difference_type(3));
    feature_array comm4(feature_array::difference_type(3));
    feature_array como1(feature_array::difference_type(3));
    feature_array como2(feature_array::difference_type(3));
    feature_array como3(feature_array::difference_type(3));
    feature_array como4(feature_array::difference_type(3));
    feature_array como5(feature_array::difference_type(3));

    comn1[0] = 0;
    comn1[1] = 0;
    comn1[2] = 0;
    n1.features["com"] = comn1;
    n1.Id = 11;
    n1.Timestep = 0;

    comn2[0] = 1;
    comn2[1] = 1;
    comn2[2] = 1;
    n2.features["com"] = comn2;
    n2.Id = 12;
    n2.Timestep = 0;

    comn3[0] = 0;
    comn3[1] = 0;
    comn3[2] = 2;
    n3.features["com"] = comn3;
    n3.Id = 13;
    n3.Timestep = 0;

    comn4[0] = 2;
    comn4[1] = 0;
    comn4[2] = 0;
    n4.features["com"] = comn4;
    n4.Id = 14;
    n4.Timestep = 0;

    comm1[0] = 2;
    comm1[1] = 2;
    comm1[2] = 2;
    m1.features["com"] = comm1;
    m1.Id = 21;
    m1.Timestep = 1;

    comm2[0] = 1;
    comm2[1] = 0;
    comm2[2] = 1;
    m2.features["com"] = comm2;
    m2.Id = 22;
    m2.Timestep = 1;

    comm3[0] = 0;
    comm3[1] = 1;
    comm3[2] = 1;
    m3.features["com"] = comm3;
    m3.Id = 23;
    m3.Timestep = 1;

    comm4[0] = 3;
    comm4[1] = 3;
    comm4[2] = 3;
    m4.features["com"] = comm4;
    m4.Id = 24;
    m4.Timestep = 1;

    como1[0] = 4;
    como1[1] = 4;
    como1[2] = 4;
    o1.features["com"] = como1;
    o1.Id = 31;
    o1.Timestep = 2;

    como2[0] = 7;
    como2[1] = 19;
    como2[2] = 8;
    o2.features["com"] = como2;
    o2.Id = 32;
    o2.Timestep = 2;

    como3[0] = 0;
    como3[1] = 7;
    como3[2] = 1;
    o3.features["com"] = como3;
    o3.Id = 33;
    o3.Timestep = 2;

    como4[0] = 5;
    como4[1] = 0;
    como4[2] = 9;
    o4.features["com"] = como4;
    o4.Id = 34;
    o4.Timestep = 2;

    como5[0] = 0;
    como5[1] = 4;
    como5[2] = 0;
    o5.features["com"] = como5;
    o5.Id = 34;
    o5.Timestep = 2;

    TraxelStore ts;
    add(ts,n1);
    add(ts,n2);
    add(ts,n3);
    add(ts,n4);
    add(ts,m1);
    add(ts,m2);
    add(ts,m3);
    add(ts,m4);
    add(ts,o1);
    add(ts,o2);
    add(ts,o3);
    add(ts,o4);
    add(ts,o5);

    SingleTimestepTraxel_HypothesesBuilder builder(&ts);
    HypothesesGraph* graph = builder.build();

    Traxels empty;
    ConstantEnergy e1(10);
    ConstantEnergy e2(90);
    ConstantEnergy e3(70);
    ConstantEnergy e4(50);
    ConstantEnergy e5(20);
    ConstantEnergy e6(5);

    SingleTimestepTraxelMrf mrf(bind<double>(e1, _1, empty, empty),		//detection
			        bind<double>(e2, _1, empty, empty),		//non_detection
			        bind<double>(e3, _1, empty, empty),		//appearance
			        bind<double>(e4, _1, empty, empty),		//disappearance
				bind<double>(e5, _1, _2, empty, empty),		//move
				bind<double>(e6, _1, _2, _3, empty, empty)	//division
			       );
    cout << "-> workflow: formulating model" << endl;
    mrf.formulate( *graph );
    cout << "-> workflow: infer" << endl;
    mrf.infer();
    cout << "-> workflow: conclude" << endl;
    mrf.conclude(*graph);
    prune_inactive(*graph);
}
<commit_msg>mrf reasoner test: testing topology of graphical model; two tests fail as expected due to a newly discovered bug<commit_after>#define BOOST_TEST_MODULE new_reasoner_test

#include <vector>
#include <iostream>

#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/bind.hpp>

#include <lemon/color.h>
#include <lemon/graph_to_eps.h>

#include <lemon/core.h>
#include <lemon/concepts/digraph.h>
#include <lemon/list_graph.h>
#include <lemon/maps.h>

#include "graph.h"
#include "hypotheses.h"
#include "energy.h"
#include "reasoning/mrf_reasoner.h"
#include "traxels.h"

using namespace Tracking;
using namespace std;
using namespace boost;

BOOST_AUTO_TEST_CASE( HypothesesGraph_build_hyp ) {
    HypothesesGraph graph;
    graph.add_node(13);
}

BOOST_AUTO_TEST_CASE( HypothesesGraph_build_hyp2 ) {

  std::cout << "Constructing HypothesesGraph" << std::endl;
  std::cout <<  std::endl;

  typedef HypothesesGraph::ArcIt ArcIt2;
  typedef HypothesesGraph::Arc Arc;
  typedef HypothesesGraph::NodeIt NodeIt;
  typedef HypothesesGraph::Node Node;
  using lemon::INVALID;

  HypothesesGraph g;
  HypothesesGraph* graph=&g;
  graph->add(node_traxel());

  std::cout << "Adding nodes" << std::endl;
  std::cout <<  std::endl;

  Node n1=g.add_node(0);
  Node n2=g.add_node(0);
  Node n3=g.add_node(0);
  g.add_node(0);
  Node m1=g.add_node(1);
  Node m2=g.add_node(1);
  Node m3=g.add_node(1);
  Node m4=g.add_node(1);
  Node o1=g.add_node(2);
  Node o2=g.add_node(2);
  Node o3=g.add_node(2);
  Node o4=g.add_node(2);

  std::cout << "Nodes:";
  for (NodeIt i(g); i!=INVALID; ++i)
    std::cout << " " << g.id(i);
  std::cout << std::endl;

  std::cout << "Addings arcs" << std::endl;
  std::cout <<  std::endl;

  g.addArc(n2,m2);
  g.addArc(n1,m2);
  g.addArc(n2,m1);
  g.addArc(n3,m3);
  g.addArc(n3,m4);
  g.addArc(m1,o1);
  g.addArc(m2,o2);
  g.addArc(m4,o3);
  g.addArc(m4,o4);

  std::cout << "Arcs:";
  for (ArcIt2 i(g); i!=INVALID; ++i)
  std::cout << " (" << g.id(g.source(i)) << "," << g.id(g.target(i)) << ")";
  std::cout << std::endl;
  std::cout <<  std::endl;

  std::cout << "Constructing Reasoner" << std::endl;
  std::cout <<  std::endl;

   Traxels empty;
   ConstantEnergy e(25);

   SingleTimestepTraxelMrf mrf(bind<double>(e, _1, empty, empty),		//detection
			        bind<double>(e, _1, empty, empty),		//non_detection
			        bind<double>(e, _1, empty, empty),		//appearance
			        bind<double>(e, _1, empty, empty),		//disappearance
				bind<double>(e, _1, _2, empty, empty),		//move
				bind<double>(e, _1, _2, _3, empty, empty)	//division
			       );

  std::cout << "Formulating Factors" << std::endl;
  std::cout <<  std::endl;

  cout << "-> workflow: formulating model" << endl;
  mrf.formulate( *graph );

  ////
  //// check topology of graphical model
  ////
  const OpengmMrf::ogmGraphicalModel* model = mrf.get_graphical_model()->Model();
  BOOST_CHECK( model != NULL );
  BOOST_CHECK_EQUAL( model->numberOfVariables(), 21);
  BOOST_CHECK_EQUAL( model->numberOfFactors(), 36);

  // check some factors
  size_t det_var; // detection variable

  det_var = mrf.get_node_map().find(m2)->second;
  BOOST_CHECK_EQUAL(model->numberOfFactors(det_var), 3);

  const OpengmMrf::ogmGraphicalModel::FactorType f = (*model)[model->factorOfVariable(det_var, 2)];
  BOOST_CHECK_EQUAL(f.numberOfVariables(), 3);
  BOOST_CHECK_EQUAL(f.size(), 8);
  BOOST_CHECK_EQUAL(f.shape(0), 2);
  BOOST_CHECK_EQUAL(f.shape(1), 2);
  BOOST_CHECK_EQUAL(f.shape(2), 2);
  BOOST_CHECK_EQUAL(f.function<0>()(0,0,0), 0);
  BOOST_CHECK_EQUAL(f.function<0>()(0,0,1), 0);
  BOOST_CHECK_EQUAL(f.function<0>()(0,1,0), 0);
  BOOST_CHECK_EQUAL(f.function<0>()(0,1,1), 0);
  BOOST_CHECK_EQUAL(f.function<0>()(1,0,0), 0);
  BOOST_CHECK_EQUAL(f.function<0>()(1,0,1), 25);
  BOOST_CHECK_EQUAL(f.function<0>()(1,1,0), 25);
  BOOST_CHECK_EQUAL(f.function<0>()(1,1,1), 0);

  det_var = mrf.get_node_map().find(m4)->second;
  BOOST_CHECK_EQUAL(model->numberOfFactors(det_var), 3);

  const OpengmMrf::ogmGraphicalModel::FactorType f2 = (*model)[model->factorOfVariable(det_var, 1)];
  BOOST_CHECK_EQUAL(f2.numberOfVariables(), 3);
  BOOST_CHECK_EQUAL(f2.size(), 8);
  BOOST_CHECK_EQUAL(f2.shape(0), 2);
  BOOST_CHECK_EQUAL(f2.shape(1), 2);
  BOOST_CHECK_EQUAL(f2.shape(2), 2);
  BOOST_CHECK_EQUAL(f2.function<0>()(0,0,0), 0);
  BOOST_CHECK_EQUAL(f2.function<0>()(0,0,1), 0);
  BOOST_CHECK_EQUAL(f2.function<0>()(0,1,0), 0);
  BOOST_CHECK_EQUAL(f2.function<0>()(0,1,1), 0);
  BOOST_CHECK_EQUAL(f2.function<0>()(1,0,0), 25);
  BOOST_CHECK_EQUAL(f2.function<0>()(1,0,1), 25);
  BOOST_CHECK_EQUAL(f2.function<0>()(1,1,0), 25);
  BOOST_CHECK_EQUAL(f2.function<0>()(1,1,1), 25);

  cout << "-> workflow: infer" << endl;
  mrf.infer();
  cout << "-> workflow: conclude" << endl;
  mrf.conclude(*graph);
  prune_inactive(*graph);
}

BOOST_AUTO_TEST_CASE( HypothesesGraph_build_hyp_mrf ) {

    Traxel n1, n2, n3, n4, m1, m2, m3, m4, o1, o2, o3, o4, o5;
    feature_array comn1(feature_array::difference_type(3)); //float vector
    feature_array comn2(feature_array::difference_type(3));
    feature_array comn3(feature_array::difference_type(3));
    feature_array comn4(feature_array::difference_type(3));
    feature_array comm1(feature_array::difference_type(3));
    feature_array comm2(feature_array::difference_type(3));
    feature_array comm3(feature_array::difference_type(3));
    feature_array comm4(feature_array::difference_type(3));
    feature_array como1(feature_array::difference_type(3));
    feature_array como2(feature_array::difference_type(3));
    feature_array como3(feature_array::difference_type(3));
    feature_array como4(feature_array::difference_type(3));
    feature_array como5(feature_array::difference_type(3));

    comn1[0] = 0;
    comn1[1] = 0;
    comn1[2] = 0;
    n1.features["com"] = comn1;
    n1.Id = 11;
    n1.Timestep = 0;

    comn2[0] = 1;
    comn2[1] = 1;
    comn2[2] = 1;
    n2.features["com"] = comn2;
    n2.Id = 12;
    n2.Timestep = 0;

    comn3[0] = 0;
    comn3[1] = 0;
    comn3[2] = 2;
    n3.features["com"] = comn3;
    n3.Id = 13;
    n3.Timestep = 0;

    comn4[0] = 2;
    comn4[1] = 0;
    comn4[2] = 0;
    n4.features["com"] = comn4;
    n4.Id = 14;
    n4.Timestep = 0;

    comm1[0] = 2;
    comm1[1] = 2;
    comm1[2] = 2;
    m1.features["com"] = comm1;
    m1.Id = 21;
    m1.Timestep = 1;

    comm2[0] = 1;
    comm2[1] = 0;
    comm2[2] = 1;
    m2.features["com"] = comm2;
    m2.Id = 22;
    m2.Timestep = 1;

    comm3[0] = 0;
    comm3[1] = 1;
    comm3[2] = 1;
    m3.features["com"] = comm3;
    m3.Id = 23;
    m3.Timestep = 1;

    comm4[0] = 3;
    comm4[1] = 3;
    comm4[2] = 3;
    m4.features["com"] = comm4;
    m4.Id = 24;
    m4.Timestep = 1;

    como1[0] = 4;
    como1[1] = 4;
    como1[2] = 4;
    o1.features["com"] = como1;
    o1.Id = 31;
    o1.Timestep = 2;

    como2[0] = 7;
    como2[1] = 19;
    como2[2] = 8;
    o2.features["com"] = como2;
    o2.Id = 32;
    o2.Timestep = 2;

    como3[0] = 0;
    como3[1] = 7;
    como3[2] = 1;
    o3.features["com"] = como3;
    o3.Id = 33;
    o3.Timestep = 2;

    como4[0] = 5;
    como4[1] = 0;
    como4[2] = 9;
    o4.features["com"] = como4;
    o4.Id = 34;
    o4.Timestep = 2;

    como5[0] = 0;
    como5[1] = 4;
    como5[2] = 0;
    o5.features["com"] = como5;
    o5.Id = 34;
    o5.Timestep = 2;

    TraxelStore ts;
    add(ts,n1);
    add(ts,n2);
    add(ts,n3);
    add(ts,n4);
    add(ts,m1);
    add(ts,m2);
    add(ts,m3);
    add(ts,m4);
    add(ts,o1);
    add(ts,o2);
    add(ts,o3);
    add(ts,o4);
    add(ts,o5);

    SingleTimestepTraxel_HypothesesBuilder builder(&ts);
    HypothesesGraph* graph = builder.build();

    Traxels empty;
    ConstantEnergy e1(10);
    ConstantEnergy e2(90);
    ConstantEnergy e3(70);
    ConstantEnergy e4(50);
    ConstantEnergy e5(20);
    ConstantEnergy e6(5);

    SingleTimestepTraxelMrf mrf(bind<double>(e1, _1, empty, empty),		//detection
			        bind<double>(e2, _1, empty, empty),		//non_detection
			        bind<double>(e3, _1, empty, empty),		//appearance
			        bind<double>(e4, _1, empty, empty),		//disappearance
				bind<double>(e5, _1, _2, empty, empty),		//move
				bind<double>(e6, _1, _2, _3, empty, empty)	//division
			       );
    cout << "-> workflow: formulating model" << endl;
    mrf.formulate( *graph );
    cout << "-> workflow: infer" << endl;
    mrf.infer();
    cout << "-> workflow: conclude" << endl;
    mrf.conclude(*graph);
    prune_inactive(*graph);
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the Qt Script Generator project on Trolltech Labs.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "shellimplgenerator.h"
#include "reporthandler.h"
#include "fileout.h"

extern void declareFunctionMetaTypes(QTextStream &stream,
                                     const AbstractMetaFunctionList &functions,
                                     QSet<QString> &registeredTypeNames);

QString ShellImplGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
{
    return QString("qtscriptshell_%1.cpp").arg(meta_class->name());
}

static bool include_less_than(const Include &a, const Include &b)
{
    return a.name < b.name;
}

static void writeHelperCode(QTextStream &s, const AbstractMetaClass *)
{
    s << "#define QTSCRIPT_IS_GENERATED_FUNCTION(fun) ((fun.data().toUInt32() & 0xFFFF0000) == 0xBABE0000)" << endl;
    s << endl;
}

void writeQtScriptQtBindingsLicense(QTextStream &stream);

void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
{
    if (FileOut::license)
        writeQtScriptQtBindingsLicense(s);

    QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri";

    priGenerator->addSource(pro_file_name, fileNameForClass(meta_class));

    s << "#include \"qtscriptshell_" << meta_class->name() << ".h\"" << endl << endl;

    if (!meta_class->generateShellClass())
        return;

    s << "#include <QtScript/QScriptEngine>" << endl;

    IncludeList list = meta_class->typeEntry()->extraIncludes();
    qSort(list.begin(), list.end(), include_less_than);
    foreach (const Include &inc, list) {
        if (inc.type == Include::TargetLangImport)
            continue;

        s << "#include ";
        if (inc.type == Include::LocalPath)
            s << "\"";
        else
            s << "<";

        s << inc.name;

        if (inc.type == Include::LocalPath)
            s << "\"";
        else
            s << ">";

        s << endl;
    }
    s << endl;

    writeHelperCode(s, meta_class);

    // find constructors
    AbstractMetaFunctionList ctors;
    ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
                                       | AbstractMetaClass::WasVisible
                                       | AbstractMetaClass::NotRemovedFromTargetLang);
    // find member functions
    AbstractMetaFunctionList functions = meta_class->queryFunctions(
        AbstractMetaClass:: VirtualFunctions | AbstractMetaClass::WasVisible
        | AbstractMetaClass::NotRemovedFromTargetLang
        );

    // write metatype declarations
    {
        QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
        declareFunctionMetaTypes(s, functions, registeredTypeNames);
        s << endl;
    }

    // write constructors
    foreach (const AbstractMetaFunction *ctor, ctors) {
        s << "QtScriptShell_" << meta_class->name() << "::";
        writeFunctionSignature(s, ctor, 0, QString(), Option(OriginalName | ShowStatic));
        s << endl;
        s << "    : " << meta_class->qualifiedCppName() << "(";
        AbstractMetaArgumentList args = ctor->arguments();
        for (int i = 0; i < args.size(); ++i) {
            if (i > 0)
                s << ", ";
            s << args.at(i)->argumentName();
        }
        s << ")" << " {}" << endl << endl;
    }

    // write destructor
    s << "QtScriptShell_" << meta_class->name() << "::"
      << "~QtScriptShell_" << meta_class->name() << "()"
      << " {}" << endl << endl;

    // write member functions
    for (int i = 0; i < functions.size(); ++i) {
        AbstractMetaFunction *fun = functions.at(i);
        writeFunctionSignature(s, fun, meta_class, QString(),
                               Option(OriginalName | ShowStatic | UnderscoreSpaces),
                               "QtScriptShell_");
        s << endl << "{" << endl;
        QString scriptFunctionName = fun->name();
        if (QPropertySpec *read = meta_class->propertySpecForRead(fun->name())) {
            if (read->name() == fun->name()) {
                // use different name to avoid infinite recursion
                // ### not sure if this is the best solution though...
                scriptFunctionName.prepend("_qs_");
            }
        }
        s << "    QScriptValue _q_function = __qtscript_self.property(\""
          << scriptFunctionName << "\");" << endl;
        s << "    if (!_q_function.isFunction() || QTSCRIPT_IS_GENERATED_FUNCTION(_q_function)" << endl
          << "        || (__qtscript_self.propertyFlags(\"" << scriptFunctionName << "\") & QScriptValue::QObjectMember)) {" << endl;

        AbstractMetaArgumentList args = fun->arguments();
        s << "        ";
        if (fun->isAbstract()) {
            s << "qFatal(\"" << meta_class->name() << "::" << fun->name()
              << "() is abstract!\");" << endl;
        } else {
            // call the C++ implementation
            if (fun->type())
                s << "return ";
            s << meta_class->qualifiedCppName() << "::" << fun->originalName() << "(";
            for (int i = 0; i < args.size(); ++i) {
                if (i > 0)
                    s << ", ";
                s << args.at(i)->argumentName();
            }
            s << ");" << endl;
        }

        s << "    } else {" << endl;

        // call the script function
        if (args.size() > 0)
            s << "        QScriptEngine *_q_engine = __qtscript_self.engine();" << endl;
        s << "        ";
        if (fun->type()) {
            s << "return qscriptvalue_cast<";
            writeTypeInfo(s, fun->type());
            s << ">(";
        }
        s << "_q_function.call(__qtscript_self";
        if (args.size() > 0) {
            s << "," << endl;
            s << "            QScriptValueList()";
            int i = 0;
            for (int j = 0; j < args.size(); ++j) {
                if (fun->argumentRemoved(j+1))
                    continue;
                s << endl << "            << ";
                s << "qScriptValueFromValue(_q_engine, ";
                AbstractMetaType *atype = args.at(j)->type();
                QString asig = atype->cppSignature();
                bool constCastArg = asig.endsWith('*') && asig.startsWith("const ");
                if (constCastArg)
                    s << "const_cast<" << asig.mid(6) << ">(";
                s << args.at(i)->argumentName() << ")";
                if (constCastArg)
                    s << ")";
                ++i;
            }
        }
        s << ")";
        if (fun->type())
            s << ")";
        s << ";" << endl;

        s << "    }" << endl;

        s << "}" << endl << endl;
    }
}

void ShellImplGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
{
    CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
    foreach (const CodeSnip &cs, code_snips) {
        if (cs.language == TypeSystem::ShellCode) {
            s << cs.code() << endl;
        }
    }
}
<commit_msg>fix issue introduced by 04e49d162b15d7a32d4e5837e5f5ef284ea226ba<commit_after>/****************************************************************************
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the Qt Script Generator project on Trolltech Labs.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file.  Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "shellimplgenerator.h"
#include "reporthandler.h"
#include "fileout.h"

extern void declareFunctionMetaTypes(QTextStream &stream,
                                     const AbstractMetaFunctionList &functions,
                                     QSet<QString> &registeredTypeNames);

QString ShellImplGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
{
    return QString("qtscriptshell_%1.cpp").arg(meta_class->name());
}

static bool include_less_than(const Include &a, const Include &b)
{
    return a.name < b.name;
}

static void writeHelperCode(QTextStream &s, const AbstractMetaClass *)
{
    s << "#define QTSCRIPT_IS_GENERATED_FUNCTION(fun) ((fun.data().toUInt32() & 0xFFFF0000) == 0xBABE0000)" << endl;
    s << endl;
}

void writeQtScriptQtBindingsLicense(QTextStream &stream);

void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
{
    if (FileOut::license)
        writeQtScriptQtBindingsLicense(s);

    QString packName = meta_class->package().replace(".", "_");

    priGenerator->addSource(packName, fileNameForClass(meta_class));

    s << "#include \"qtscriptshell_" << meta_class->name() << ".h\"" << endl << endl;

    if (!meta_class->generateShellClass())
        return;

    s << "#include <QtScript/QScriptEngine>" << endl;

    IncludeList list = meta_class->typeEntry()->extraIncludes();
    qSort(list.begin(), list.end(), include_less_than);
    foreach (const Include &inc, list) {
        if (inc.type == Include::TargetLangImport)
            continue;

        s << "#include ";
        if (inc.type == Include::LocalPath)
            s << "\"";
        else
            s << "<";

        s << inc.name;

        if (inc.type == Include::LocalPath)
            s << "\"";
        else
            s << ">";

        s << endl;
    }
    s << endl;

    writeHelperCode(s, meta_class);

    // find constructors
    AbstractMetaFunctionList ctors;
    ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
                                       | AbstractMetaClass::WasVisible
                                       | AbstractMetaClass::NotRemovedFromTargetLang);
    // find member functions
    AbstractMetaFunctionList functions = meta_class->queryFunctions(
        AbstractMetaClass:: VirtualFunctions | AbstractMetaClass::WasVisible
        | AbstractMetaClass::NotRemovedFromTargetLang
        );

    // write metatype declarations
    {
        QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
        declareFunctionMetaTypes(s, functions, registeredTypeNames);
        s << endl;
    }

    // write constructors
    foreach (const AbstractMetaFunction *ctor, ctors) {
        s << "QtScriptShell_" << meta_class->name() << "::";
        writeFunctionSignature(s, ctor, 0, QString(), Option(OriginalName | ShowStatic));
        s << endl;
        s << "    : " << meta_class->qualifiedCppName() << "(";
        AbstractMetaArgumentList args = ctor->arguments();
        for (int i = 0; i < args.size(); ++i) {
            if (i > 0)
                s << ", ";
            s << args.at(i)->argumentName();
        }
        s << ")" << " {}" << endl << endl;
    }

    // write destructor
    s << "QtScriptShell_" << meta_class->name() << "::"
      << "~QtScriptShell_" << meta_class->name() << "()"
      << " {}" << endl << endl;

    // write member functions
    for (int i = 0; i < functions.size(); ++i) {
        AbstractMetaFunction *fun = functions.at(i);
        writeFunctionSignature(s, fun, meta_class, QString(),
                               Option(OriginalName | ShowStatic | UnderscoreSpaces),
                               "QtScriptShell_");
        s << endl << "{" << endl;
        QString scriptFunctionName = fun->name();
        if (QPropertySpec *read = meta_class->propertySpecForRead(fun->name())) {
            if (read->name() == fun->name()) {
                // use different name to avoid infinite recursion
                // ### not sure if this is the best solution though...
                scriptFunctionName.prepend("_qs_");
            }
        }
        s << "    QScriptValue _q_function = __qtscript_self.property(\""
          << scriptFunctionName << "\");" << endl;
        s << "    if (!_q_function.isFunction() || QTSCRIPT_IS_GENERATED_FUNCTION(_q_function)" << endl
          << "        || (__qtscript_self.propertyFlags(\"" << scriptFunctionName << "\") & QScriptValue::QObjectMember)) {" << endl;

        AbstractMetaArgumentList args = fun->arguments();
        s << "        ";
        if (fun->isAbstract()) {
            s << "qFatal(\"" << meta_class->name() << "::" << fun->name()
              << "() is abstract!\");" << endl;
        } else {
            // call the C++ implementation
            if (fun->type())
                s << "return ";
            s << meta_class->qualifiedCppName() << "::" << fun->originalName() << "(";
            for (int i = 0; i < args.size(); ++i) {
                if (i > 0)
                    s << ", ";
                s << args.at(i)->argumentName();
            }
            s << ");" << endl;
        }

        s << "    } else {" << endl;

        // call the script function
        if (args.size() > 0)
            s << "        QScriptEngine *_q_engine = __qtscript_self.engine();" << endl;
        s << "        ";
        if (fun->type()) {
            s << "return qscriptvalue_cast<";
            writeTypeInfo(s, fun->type());
            s << ">(";
        }
        s << "_q_function.call(__qtscript_self";
        if (args.size() > 0) {
            s << "," << endl;
            s << "            QScriptValueList()";
            int i = 0;
            for (int j = 0; j < args.size(); ++j) {
                if (fun->argumentRemoved(j+1))
                    continue;
                s << endl << "            << ";
                s << "qScriptValueFromValue(_q_engine, ";
                AbstractMetaType *atype = args.at(j)->type();
                QString asig = atype->cppSignature();
                bool constCastArg = asig.endsWith('*') && asig.startsWith("const ");
                if (constCastArg)
                    s << "const_cast<" << asig.mid(6) << ">(";
                s << args.at(i)->argumentName() << ")";
                if (constCastArg)
                    s << ")";
                ++i;
            }
        }
        s << ")";
        if (fun->type())
            s << ")";
        s << ";" << endl;

        s << "    }" << endl;

        s << "}" << endl << endl;
    }
}

void ShellImplGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
{
    CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
    foreach (const CodeSnip &cs, code_snips) {
        if (cs.language == TypeSystem::ShellCode) {
            s << cs.code() << endl;
        }
    }
}
<|endoftext|>


<commit_before>/*! \file variant.hpp
    \brief Support for std::variant
    \ingroup STLSupport */
/*
  Copyright (c) 2014, 2017, Randolph Voorhies, Shane Grant, Juan Pedro
  Bolivar Puente. 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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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.
*/
#ifndef CEREAL_TYPES_STD_VARIANT_HPP_
#define CEREAL_TYPES_STD_VARIANT_HPP_

#include "cereal/cereal.hpp"
#include <variant>
#include <cstdint>

namespace cereal
{
  namespace variant_detail
  {
    //! @internal
    template <class Archive>
    struct variant_save_visitor
    {
      variant_save_visitor(Archive & ar_) : ar(ar_) {}

      template<class T>
        void operator()(T const & value) const
        {
          ar( CEREAL_NVP_("data", value) );
        }

      Archive & ar;
    };

    //! @internal
    template<int N, class Variant, class ... Args, class Archive>
    typename std::enable_if<N == std::variant_size_v<Variant>, void>::type
    load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
    {
      throw ::cereal::Exception("Error traversing variant during load");
    }
    //! @internal
    template<int N, class Variant, class H, class ... T, class Archive>
    typename std::enable_if<N < std::variant_size_v<Variant>, void>::type
    load_variant(Archive & ar, int target, Variant & variant)
    {
      if(N == target)
      {
        H value;
        ar( CEREAL_NVP_("data", value) );
        variant = std::move(value);
      }
      else
        load_variant<N+1, Variant, T...>(ar, target, variant);
    }

  } // namespace variant_detail

  //! Saving for std::variant
  template <class Archive, typename VariantType1, typename... VariantTypes> inline
  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::variant<VariantType1, VariantTypes...> const & variant )
  {
    std::uint32_t index = variant.index();
    ar( CEREAL_NVP_("index", index) );
    variant_detail::variant_save_visitor<Archive> visitor(ar);
    std::visit(visitor, variant);
  }

  //! Loading for std::variant
  template <class Archive, typename... VariantTypes> inline
  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::variant<VariantTypes...> & variant )
  {
    using variant_t = typename std::variant<VariantTypes...>;

    std::uint32_t index;
    ar( CEREAL_NVP_("index", index) );
    if(index >= std::variant_size_v<variant_t>)
      throw Exception("Invalid 'index' selector when deserializing std::variant");

    variant_detail::load_variant<0, variant_t, VariantTypes...>(ar, index, variant);
  }
} // namespace cereal

#endif // CEREAL_TYPES_STD_VARIANT_HPP_
<commit_msg>Change type to int32_t to be consistent with boost_variant<commit_after>/*! \file variant.hpp
    \brief Support for std::variant
    \ingroup STLSupport */
/*
  Copyright (c) 2014, 2017, Randolph Voorhies, Shane Grant, Juan Pedro
  Bolivar Puente. 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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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.
*/
#ifndef CEREAL_TYPES_STD_VARIANT_HPP_
#define CEREAL_TYPES_STD_VARIANT_HPP_

#include "cereal/cereal.hpp"
#include <variant>
#include <cstdint>

namespace cereal
{
  namespace variant_detail
  {
    //! @internal
    template <class Archive>
    struct variant_save_visitor
    {
      variant_save_visitor(Archive & ar_) : ar(ar_) {}

      template<class T>
        void operator()(T const & value) const
        {
          ar( CEREAL_NVP_("data", value) );
        }

      Archive & ar;
    };

    //! @internal
    template<int N, class Variant, class ... Args, class Archive>
    typename std::enable_if<N == std::variant_size_v<Variant>, void>::type
    load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
    {
      throw ::cereal::Exception("Error traversing variant during load");
    }
    //! @internal
    template<int N, class Variant, class H, class ... T, class Archive>
    typename std::enable_if<N < std::variant_size_v<Variant>, void>::type
    load_variant(Archive & ar, int target, Variant & variant)
    {
      if(N == target)
      {
        H value;
        ar( CEREAL_NVP_("data", value) );
        variant = std::move(value);
      }
      else
        load_variant<N+1, Variant, T...>(ar, target, variant);
    }

  } // namespace variant_detail

  //! Saving for std::variant
  template <class Archive, typename VariantType1, typename... VariantTypes> inline
  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::variant<VariantType1, VariantTypes...> const & variant )
  {
    std::int32_t index = variant.index();
    ar( CEREAL_NVP_("index", index) );
    variant_detail::variant_save_visitor<Archive> visitor(ar);
    std::visit(visitor, variant);
  }

  //! Loading for std::variant
  template <class Archive, typename... VariantTypes> inline
  void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::variant<VariantTypes...> & variant )
  {
    using variant_t = typename std::variant<VariantTypes...>;

    std::int32_t index;
    ar( CEREAL_NVP_("index", index) );
    if(index >= std::variant_size_v<variant_t>)
      throw Exception("Invalid 'index' selector when deserializing std::variant");

    variant_detail::load_variant<0, variant_t, VariantTypes...>(ar, index, variant);
  }
} // namespace cereal

#endif // CEREAL_TYPES_STD_VARIANT_HPP_
<|endoftext|>


<commit_before>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        iutest_port.hpp
 * @brief       portable
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2011-2018, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================
#ifndef INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
#define INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_

//======================================================================
// include
#if defined(__MWERKS__)
#  define _MSL_USING_NAMESPACE
#endif

#include "iutest_internal_defs.hpp"

#if defined(IUTEST_OS_LINUX) || defined(IUTEST_OS_CYGWIN) || defined(IUTEST_OS_MAC)
#  include <unistd.h>
#  include <locale.h>
#endif

#if IUTEST_HAS_FILE_STAT
#  include <sys/stat.h>
#endif

//======================================================================
// define
#if !defined(IUTEST_MAX_PATH)
#  if   defined(MAX_PATH) && MAX_PATH
#    define IUTEST_MAX_PATH MAX_PATH
#  elif defined(PATH_MAX) && PATH_MAX
#    define IUTEST_MAX_PATH PATH_MAX
#  elif defined(FILENAME_MAX) && FILENAME_MAX
#    define IUTEST_MAX_PATH FILENAME_MAX
#  else
#    define IUTEST_MAX_PATH 1024
#  endif
#endif

/**
 * @brief   ログメッセージストリーム
*/
#define IUTEST_LOG_(level)          \
    ::iutest::detail::IUTestLog(    \
        ::iutest::detail::IUTestLog::LOG_##level, __FILE__, __LINE__).GetStream()

/**
 * @brief   内部エラーチェック
*/
#define IUTEST_CHECK_(condition)                \
    IUTEST_AMBIGUOUS_ELSE_BLOCKER_              \
    if( !::iutest::detail::IsTrue(condition) )  \
        IUTEST_LOG_(FATAL) << "Condition " #condition " failed. "

namespace iutest {

#ifdef IUTEST_OS_NACL
namespace nacl
{

/**
 * @brief   printf
*/
void vprint_message(const char *fmt, va_list va);
void print_message(const char *fmt, ...);

}
#endif

namespace internal {
namespace posix
{

const char* GetEnv(const char* name);
int PutEnv(const char* expr);
int SetEnv(const char* name, const char* value, int overwrite);

const char* GetCWD(char* buf, size_t length);
::std::string GetCWD();

void SleepMillisec(unsigned int millisec);

#if defined(IUTEST_OS_WINDOWS_MOBILE)
void Abort();
#else
IUTEST_ATTRIBUTE_NORETURN_ void Abort();
inline void Abort() { abort(); }
#endif

#if IUTEST_HAS_FILENO

#if defined(_MSC_VER)
inline int Fileno(FILE* fp) { return _fileno(fp); }
#else
inline int Fileno(FILE* fp) { return fileno(fp); }
#endif

#else

inline int Fileno(FILE*) { return -1; }

#endif

#if IUTEST_HAS_FILE_STAT

#if defined(IUTEST_OS_WINDOWS) && !defined(IUTEST_OS_WINDOWS_WINE)

typedef struct _stat StatStruct;

inline int FileStat(int fd, StatStruct* buf) { return _fstat(fd, buf); }
inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return (st.st_mode & _S_IFDIR) != 0; }

#else

typedef struct stat StatStruct;

inline int FileStat(int fd, StatStruct* buf) { return fstat(fd, buf); }
inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }

#endif

inline int Stat(FILE* fp, StatStruct* buf)
{
    int fd = Fileno(fp);
    return fd >= 0 ? FileStat(fd, buf) : fd;
}

#endif

}   // end of namespace posix

inline void SleepMilliseconds(int n) { posix::SleepMillisec(static_cast<unsigned int>(n)); }

}   // end of namespace internal

namespace detail
{

namespace posix = internal::posix;

/**
 * @brief   パス区切り文字の取得
*/
char GetPathSeparator() IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsAltPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   一番後ろのパスセパレータのアドレスを取得
*/
const char* FindLastPathSeparator(const char* path, size_t length) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   環境変数の設定
*/
bool SetEnvironmentVariable(const char* name, const char* value);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] buf     = 出力バッファ
 * @return  成否
*/
bool GetEnvironmentVariable(const char* name, char* buf, size_t size);

#if !defined(IUTEST_NO_FUNCTION_TEMPLATE_ORDERING)

template<size_t SIZE>
inline bool GetEnvironmentVariable(const char* name, char (&buf)[SIZE])
{
return GetEnvironmentVariable(name, buf, SIZE);
}

#endif

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力文字列
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentVariable(const char* name, ::std::string& var);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力数値
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentInt(const char* name, int& var);

#if defined(IUTEST_OS_WINDOWS)
namespace win
{

    /**
     * @brief   文字列変換
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ WideStringToMultiByteString(const wchar_t* wide_c_str);

    /**
     * @brief   HRESULT のエラー文字列を取得
     * @param [in]  hr  = エラー値
     * @return  文字列
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ GetHResultString(HRESULT hr);

}   // end of namespace win
#endif

/**
 * @brief   ログ
 */
class IUTestLog
{
public:
    enum Level
    {
          LOG_INFO
        , LOG_WARNING
        , LOG_ERROR
        , LOG_FATAL
        , LOG_LEVEL_NUM
    };
public:
    IUTestLog(Level level, const char* file, int line);

    ~IUTestLog();

public:
    iu_stringstream& GetStream() { return m_stream; }

public:
    static int GetCount(Level level) { return GetCountTable().count[level]; }
    static bool HasWarning() { return GetCount(LOG_WARNING) > 0; }
    static bool HasError() { return GetCount(LOG_ERROR) > 0 || GetCount(LOG_FATAL) > 0; }

private:
    struct Count
    {
        int count[LOG_LEVEL_NUM];
    };

    static Count& GetCountTable() { static Count count = { {0} }; return count; }
    static void CountUp(int level);

private:
    const Level kLevel;
    iu_stringstream m_stream;

    IUTEST_PP_DISALLOW_COPY_AND_ASSIGN(IUTestLog);
};

#if IUTEST_HAS_STREAM_BUFFER

/**
 * @brief   stream buffer
*/
template<int SIZE=BUFSIZ>
class IUStreamBuffer
{
public:
    explicit IUStreamBuffer(FILE* fp)
        : m_fp(fp)
    {
        m_buf[0] = '\0';
        fflush(fp);
        setvbuf(fp, m_buf, _IOFBF, SIZE);
    }

    ~IUStreamBuffer()
    {
IUTEST_PRAGMA_CRT_SECURE_WARN_DISABLE_BEGIN()
        fflush(m_fp);
        setbuf(m_fp, NULL);
IUTEST_PRAGMA_CRT_SECURE_WARN_DISABLE_END()
    }

public:
    ::std::string GetStreamString() { return m_buf; }

private:
    FILE* m_fp;
    char m_buf[SIZE];
};

/**
* @brief    stream capture
*/

#endif

}   // end of namespace detail
}   // end of namespace iutest

#if !IUTEST_HAS_LIB
#  include "../impl/iutest_port.ipp"
#endif

#endif // INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
<commit_msg>setbuf to setvbuf<commit_after>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        iutest_port.hpp
 * @brief       portable
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2011-2018, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================
#ifndef INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
#define INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_

//======================================================================
// include
#if defined(__MWERKS__)
#  define _MSL_USING_NAMESPACE
#endif

#include "iutest_internal_defs.hpp"

#if defined(IUTEST_OS_LINUX) || defined(IUTEST_OS_CYGWIN) || defined(IUTEST_OS_MAC)
#  include <unistd.h>
#  include <locale.h>
#endif

#if IUTEST_HAS_FILE_STAT
#  include <sys/stat.h>
#endif

//======================================================================
// define
#if !defined(IUTEST_MAX_PATH)
#  if   defined(MAX_PATH) && MAX_PATH
#    define IUTEST_MAX_PATH MAX_PATH
#  elif defined(PATH_MAX) && PATH_MAX
#    define IUTEST_MAX_PATH PATH_MAX
#  elif defined(FILENAME_MAX) && FILENAME_MAX
#    define IUTEST_MAX_PATH FILENAME_MAX
#  else
#    define IUTEST_MAX_PATH 1024
#  endif
#endif

/**
 * @brief   ログメッセージストリーム
*/
#define IUTEST_LOG_(level)          \
    ::iutest::detail::IUTestLog(    \
        ::iutest::detail::IUTestLog::LOG_##level, __FILE__, __LINE__).GetStream()

/**
 * @brief   内部エラーチェック
*/
#define IUTEST_CHECK_(condition)                \
    IUTEST_AMBIGUOUS_ELSE_BLOCKER_              \
    if( !::iutest::detail::IsTrue(condition) )  \
        IUTEST_LOG_(FATAL) << "Condition " #condition " failed. "

namespace iutest {

#ifdef IUTEST_OS_NACL
namespace nacl
{

/**
 * @brief   printf
*/
void vprint_message(const char *fmt, va_list va);
void print_message(const char *fmt, ...);

}
#endif

namespace internal {
namespace posix
{

const char* GetEnv(const char* name);
int PutEnv(const char* expr);
int SetEnv(const char* name, const char* value, int overwrite);

const char* GetCWD(char* buf, size_t length);
::std::string GetCWD();

void SleepMillisec(unsigned int millisec);

#if defined(IUTEST_OS_WINDOWS_MOBILE)
void Abort();
#else
IUTEST_ATTRIBUTE_NORETURN_ void Abort();
inline void Abort() { abort(); }
#endif

#if IUTEST_HAS_FILENO

#if defined(_MSC_VER)
inline int Fileno(FILE* fp) { return _fileno(fp); }
#else
inline int Fileno(FILE* fp) { return fileno(fp); }
#endif

#else

inline int Fileno(FILE*) { return -1; }

#endif

#if IUTEST_HAS_FILE_STAT

#if defined(IUTEST_OS_WINDOWS) && !defined(IUTEST_OS_WINDOWS_WINE)

typedef struct _stat StatStruct;

inline int FileStat(int fd, StatStruct* buf) { return _fstat(fd, buf); }
inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return (st.st_mode & _S_IFDIR) != 0; }

#else

typedef struct stat StatStruct;

inline int FileStat(int fd, StatStruct* buf) { return fstat(fd, buf); }
inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }

#endif

inline int Stat(FILE* fp, StatStruct* buf)
{
    int fd = Fileno(fp);
    return fd >= 0 ? FileStat(fd, buf) : fd;
}

#endif

}   // end of namespace posix

inline void SleepMilliseconds(int n) { posix::SleepMillisec(static_cast<unsigned int>(n)); }

}   // end of namespace internal

namespace detail
{

namespace posix = internal::posix;

/**
 * @brief   パス区切り文字の取得
*/
char GetPathSeparator() IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   パス区切り文字かどうか
*/
bool IsAltPathSeparator(char c) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   一番後ろのパスセパレータのアドレスを取得
*/
const char* FindLastPathSeparator(const char* path, size_t length) IUTEST_CXX_NOEXCEPT_SPEC;

/**
 * @brief   環境変数の設定
*/
bool SetEnvironmentVariable(const char* name, const char* value);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] buf     = 出力バッファ
 * @return  成否
*/
bool GetEnvironmentVariable(const char* name, char* buf, size_t size);

#if !defined(IUTEST_NO_FUNCTION_TEMPLATE_ORDERING)

template<size_t SIZE>
inline bool GetEnvironmentVariable(const char* name, char (&buf)[SIZE])
{
return GetEnvironmentVariable(name, buf, SIZE);
}

#endif

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力文字列
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentVariable(const char* name, ::std::string& var);

/**
 * @brief   環境変数の取得
 * @param [in]  name    = 環境変数名
 * @param [out] var     = 出力数値
 * @return  成否
 */
bool IUTEST_ATTRIBUTE_UNUSED_ GetEnvironmentInt(const char* name, int& var);

#if defined(IUTEST_OS_WINDOWS)
namespace win
{

    /**
     * @brief   文字列変換
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ WideStringToMultiByteString(const wchar_t* wide_c_str);

    /**
     * @brief   HRESULT のエラー文字列を取得
     * @param [in]  hr  = エラー値
     * @return  文字列
     */
    ::std::string IUTEST_ATTRIBUTE_UNUSED_ GetHResultString(HRESULT hr);

}   // end of namespace win
#endif

/**
 * @brief   ログ
 */
class IUTestLog
{
public:
    enum Level
    {
          LOG_INFO
        , LOG_WARNING
        , LOG_ERROR
        , LOG_FATAL
        , LOG_LEVEL_NUM
    };
public:
    IUTestLog(Level level, const char* file, int line);

    ~IUTestLog();

public:
    iu_stringstream& GetStream() { return m_stream; }

public:
    static int GetCount(Level level) { return GetCountTable().count[level]; }
    static bool HasWarning() { return GetCount(LOG_WARNING) > 0; }
    static bool HasError() { return GetCount(LOG_ERROR) > 0 || GetCount(LOG_FATAL) > 0; }

private:
    struct Count
    {
        int count[LOG_LEVEL_NUM];
    };

    static Count& GetCountTable() { static Count count = { {0} }; return count; }
    static void CountUp(int level);

private:
    const Level kLevel;
    iu_stringstream m_stream;

    IUTEST_PP_DISALLOW_COPY_AND_ASSIGN(IUTestLog);
};

#if IUTEST_HAS_STREAM_BUFFER

/**
 * @brief   stream buffer
*/
template<int SIZE=BUFSIZ>
class IUStreamBuffer
{
public:
    explicit IUStreamBuffer(FILE* fp)
        : m_fp(fp)
    {
        m_buf[0] = '\0';
        fflush(fp);
        setvbuf(fp, m_buf, _IOFBF, SIZE);
    }

    ~IUStreamBuffer()
    {
        fflush(m_fp);
        setvbuf(m_fp, NULL, _IONBF, 0);
    }

public:
    ::std::string GetStreamString() { return m_buf; }

private:
    FILE* m_fp;
    char m_buf[SIZE];
};

/**
* @brief    stream capture
*/

#endif

}   // end of namespace detail
}   // end of namespace iutest

#if !IUTEST_HAS_LIB
#  include "../impl/iutest_port.ipp"
#endif

#endif // INCG_IRIS_IUTEST_PORT_HPP_7893F685_A1A9_477A_82E8_BF06237697FF_
<|endoftext|>