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

#include <string>
#include <cstdio>
#include <stdexcept>
#include <kernel/syscalls.hpp>
#include <kernel/elf.hpp>
#include <kprint>

/**
 * This header is for instantiating and implementing
 * missing functionality gluing libc++ to the kernel
 *
 **/

extern "C"
{
  /// Linux standard base (locale)
  size_t __mbrlen (const char*, size_t, mbstate_t*)
  {
    printf("WARNING: mbrlen was called - which we don't currently support - returning bogus value\n");
    return (size_t) 1;
  }

  char _IO_getc()
  {
    /// NOTE: IMPLEMENT ME
    printf("_IO_getc(): returning bogus character as input from stdin\n");
    return 'x';
  }

  struct source_location {
  	const char *file_name;
		struct {
			uint32_t line;
			uint32_t column;
		};
  };
  struct type_descriptor {
	   uint16_t type_kind;
	   uint16_t type_info;
	   char type_name[1];
  };
  const char* type_kind_string[] = {
    "load of", "store to", "reference binding to", "member access within",
    "member call on", "constructor call on", "downcast of", "downcast of"
  };

  struct out_of_bounds {
	   source_location  src;
	   type_descriptor* array_type;
	   type_descriptor* index_type;
  };
  struct overflow {
    source_location src;
  };
  struct mismatch {
    source_location  src;
    type_descriptor& type;
    unsigned char    log_align;
    unsigned char    type_kind;
  };
  struct function_type_mismatch {
    const source_location  src;
    const type_descriptor& type;
  };
  struct nonnull_return {
    source_location src;
    source_location attr;
  };
  struct unreachable {
    source_location src;
  };
  using ub_error = std::runtime_error;
  void print_src_location(const source_location& src) {
    printf("ubsan: %s at line %u col %u\n",
            src.file_name, src.line, src.column);
  }
  void undefined_throw(const char* error) {
    kprintf("ubsan: %s", error);
    print_backtrace();
    kprintf("\n");
  }

  /// Undefined-behavior sanitizer
  void __ubsan_handle_out_of_bounds(struct out_of_bounds* data)
  {
    print_src_location(data->src);
    undefined_throw("Out-of-bounds access");
  }
  void __ubsan_handle_missing_return()
  {
    undefined_throw("Missing return");
  }
  void __ubsan_handle_nonnull_return(struct nonnull_return* data)
  {
    print_src_location(data->src);
    undefined_throw("Non-null return");
  }

  void __ubsan_handle_add_overflow()
  {
    undefined_throw("Overflow on addition");
  }
  void __ubsan_handle_sub_overflow()
  {
    undefined_throw("Overflow on subtraction");
  }
  void __ubsan_handle_mul_overflow()
  {
    undefined_throw("Overflow on multiplication");
  }
  void __ubsan_handle_negate_overflow()
  {
    undefined_throw("Overflow on negation");
  }
  void __ubsan_handle_pointer_overflow()
  {
    undefined_throw("Pointer overflow");
  }
  void __ubsan_handle_divrem_overflow(struct overflow* data,
                                      unsigned long lhs,
                                      unsigned long rhs)
  {
    print_src_location(data->src);
    printf("ubsan: LHS %lu / RHS %lu\n", lhs, rhs);
    undefined_throw("Division remainder overflow");
  }
  void __ubsan_handle_float_cast_overflow()
  {
    undefined_throw("Float-cast overflow");
  }
  void __ubsan_handle_shift_out_of_bounds()
  {
    undefined_throw("Shift out-of-bounds");
  }

  void __ubsan_handle_type_mismatch_v1(struct mismatch* data, unsigned long ptr)
  {
    print_src_location(data->src);
    char sbuf[1024];
    auto res = Elf::safe_resolve_symbol((void*) ptr, sbuf, sizeof(sbuf));

    const char* reason = "Type mismatch";
    const long alignment = 1 << data->log_align;

    if (alignment && (ptr & (alignment-1)) != 0) {
      reason = "Misaligned access";
    }
    else if (ptr == 0) {
      reason = "Null-pointer access";
    }
    char buffer[2048];
    snprintf(buffer, sizeof(buffer),
            "%s on ptr %p  (aligned %lu)\n"
            "ubsan: type name %s\n"
            "ubsan: symbol    %s",
            reason,
            (void*) ptr,
            alignment,
            data->type.type_name,
            res.name);
    undefined_throw(buffer);
  }
  void __ubsan_handle_function_type_mismatch(
          struct function_type_mismatch* data,
          unsigned long ptr)
  {
    print_src_location(data->src);
    char sbuf[1024];
    auto res = Elf::safe_resolve_symbol((void*) ptr, sbuf, sizeof(sbuf));

    char buffer[2048];
    snprintf(buffer, sizeof(buffer),
            "Function type mismatch on ptr %p\n"
            "ubsan: type name %s\n"
            "ubsan: function  %s",
            (void*) ptr,
            data->type.type_name,
            res.name);
    undefined_throw(buffer);
  }
  void __ubsan_handle_nonnull_arg()
  {
    undefined_throw("Non-null argument violated");
  }

  void __ubsan_handle_invalid_builtin()
  {
    undefined_throw("Invalid built-in function");
  }
  void __ubsan_handle_load_invalid_value()
  {
    undefined_throw("Load of invalid value");
  }
  [[noreturn]]
  void __ubsan_handle_builtin_unreachable(struct unreachable* data)
  {
    print_src_location(data->src);
    panic("Unreachable code reached");
  }
}
<commit_msg>libc_compat: added missing math functions needed by protobuf buildt for libc<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <string>
#include <cstdio>
#include <stdexcept>
#include <kernel/syscalls.hpp>
#include <kernel/elf.hpp>
#include <kprint>
#include <cmath>

/**
 * This header is for instantiating and implementing
 * missing functionality gluing libc++ to the kernel
 *
 **/

extern "C"
{

  int __isnan(double val)
  {
    return std::isnan(val);
  }

  int __isnanf(float val)
  {
      return std::isnan(val);
  }

  /// Linux standard base (locale)
  size_t __mbrlen (const char*, size_t, mbstate_t*)
  {
    printf("WARNING: mbrlen was called - which we don't currently support - returning bogus value\n");
    return (size_t) 1;
  }

  char _IO_getc()
  {
    /// NOTE: IMPLEMENT ME
    printf("_IO_getc(): returning bogus character as input from stdin\n");
    return 'x';
  }

  struct source_location {
  	const char *file_name;
		struct {
			uint32_t line;
			uint32_t column;
		};
  };
  struct type_descriptor {
	   uint16_t type_kind;
	   uint16_t type_info;
	   char type_name[1];
  };
  const char* type_kind_string[] = {
    "load of", "store to", "reference binding to", "member access within",
    "member call on", "constructor call on", "downcast of", "downcast of"
  };

  struct out_of_bounds {
	   source_location  src;
	   type_descriptor* array_type;
	   type_descriptor* index_type;
  };
  struct overflow {
    source_location src;
  };
  struct mismatch {
    source_location  src;
    type_descriptor& type;
    unsigned char    log_align;
    unsigned char    type_kind;
  };
  struct function_type_mismatch {
    const source_location  src;
    const type_descriptor& type;
  };
  struct nonnull_return {
    source_location src;
    source_location attr;
  };
  struct unreachable {
    source_location src;
  };
  using ub_error = std::runtime_error;
  void print_src_location(const source_location& src) {
    printf("ubsan: %s at line %u col %u\n",
            src.file_name, src.line, src.column);
  }
  void undefined_throw(const char* error) {
    kprintf("ubsan: %s", error);
    print_backtrace();
    kprintf("\n");
  }

  /// Undefined-behavior sanitizer
  void __ubsan_handle_out_of_bounds(struct out_of_bounds* data)
  {
    print_src_location(data->src);
    undefined_throw("Out-of-bounds access");
  }
  void __ubsan_handle_missing_return()
  {
    undefined_throw("Missing return");
  }
  void __ubsan_handle_nonnull_return(struct nonnull_return* data)
  {
    print_src_location(data->src);
    undefined_throw("Non-null return");
  }

  void __ubsan_handle_add_overflow()
  {
    undefined_throw("Overflow on addition");
  }
  void __ubsan_handle_sub_overflow()
  {
    undefined_throw("Overflow on subtraction");
  }
  void __ubsan_handle_mul_overflow()
  {
    undefined_throw("Overflow on multiplication");
  }
  void __ubsan_handle_negate_overflow()
  {
    undefined_throw("Overflow on negation");
  }
  void __ubsan_handle_pointer_overflow()
  {
    undefined_throw("Pointer overflow");
  }
  void __ubsan_handle_divrem_overflow(struct overflow* data,
                                      unsigned long lhs,
                                      unsigned long rhs)
  {
    print_src_location(data->src);
    printf("ubsan: LHS %lu / RHS %lu\n", lhs, rhs);
    undefined_throw("Division remainder overflow");
  }
  void __ubsan_handle_float_cast_overflow()
  {
    undefined_throw("Float-cast overflow");
  }
  void __ubsan_handle_shift_out_of_bounds()
  {
    undefined_throw("Shift out-of-bounds");
  }

  void __ubsan_handle_type_mismatch_v1(struct mismatch* data, unsigned long ptr)
  {
    print_src_location(data->src);
    char sbuf[1024];
    auto res = Elf::safe_resolve_symbol((void*) ptr, sbuf, sizeof(sbuf));

    const char* reason = "Type mismatch";
    const long alignment = 1 << data->log_align;

    if (alignment && (ptr & (alignment-1)) != 0) {
      reason = "Misaligned access";
    }
    else if (ptr == 0) {
      reason = "Null-pointer access";
    }
    char buffer[2048];
    snprintf(buffer, sizeof(buffer),
            "%s on ptr %p  (aligned %lu)\n"
            "ubsan: type name %s\n"
            "ubsan: symbol    %s",
            reason,
            (void*) ptr,
            alignment,
            data->type.type_name,
            res.name);
    undefined_throw(buffer);
  }
  void __ubsan_handle_function_type_mismatch(
          struct function_type_mismatch* data,
          unsigned long ptr)
  {
    print_src_location(data->src);
    char sbuf[1024];
    auto res = Elf::safe_resolve_symbol((void*) ptr, sbuf, sizeof(sbuf));

    char buffer[2048];
    snprintf(buffer, sizeof(buffer),
            "Function type mismatch on ptr %p\n"
            "ubsan: type name %s\n"
            "ubsan: function  %s",
            (void*) ptr,
            data->type.type_name,
            res.name);
    undefined_throw(buffer);
  }
  void __ubsan_handle_nonnull_arg()
  {
    undefined_throw("Non-null argument violated");
  }

  void __ubsan_handle_invalid_builtin()
  {
    undefined_throw("Invalid built-in function");
  }
  void __ubsan_handle_load_invalid_value()
  {
    undefined_throw("Load of invalid value");
  }
  [[noreturn]]
  void __ubsan_handle_builtin_unreachable(struct unreachable* data)
  {
    print_src_location(data->src);
    panic("Unreachable code reached");
  }
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <QDir>
#include <QProcess>
#include <QStandardPaths>
#include "debug.h"
#include "settingsmodel.h"
#include "settingsmodel.h"
#include "repository.h"
#include "installer.h"
#include "modviewadapter.h"

Repository::Repository(const QString& name, const QString& serverAddress, unsigned port,
                      QString password, RootItem* parent):
    SyncItem(name, parent),
    btsync_(parent->btsync()),
    serverAddress_(serverAddress),
    port_(port),
    password_(password),
    ready_(true)
{
    DBG << "Created repo name =" << name;
    updateTimer_.setInterval(1000);
    updateTimer_.start();
    connect(&updateTimer_, SIGNAL(timeout()), this, SLOT(update()));
}

void Repository::update()
{
    updateEtaAndStatus();
    updateView(this);
}

Repository::~Repository()
{
    DBG << "name =" << name();
    for (Mod* mod : mods())
    {
        mod->removeRepository(this);
        if (mod->repositories().size() == 0)
        {
            DBG << "Deleting mod: " << mod->name()
                     << "from repo: " << name();
            delete mod;
        }
    }
    for (TreeItem* modAdapter : childItems())
    {
        delete modAdapter;
    }
}

void Repository::processCompletion()
{
    ready_ = true;
    DBG << "LastModified: " << lastModified();
    for (Mod* mod : mods())
    {
        mod->deleteExtraFiles();
        Installer::install(mod);
    }
}

int Repository::lastModified()
{
    int lastModified = 0;
    for (Mod* mod : mods())
    {
        lastModified = std::max(lastModified, mod->lastModified());
    }
    return lastModified;
}

void Repository::updateView(TreeItem* item, int row)
{
    parentItem()->updateView(item, row);
}

void Repository::checkboxClicked(bool offline)
{
    SyncItem::checkboxClicked();
    updateTimer_.stop();
    setStatus("Processing new mods...");
    updateView(this);
    for (Mod* mod : mods())
    {
        QMetaObject::invokeMethod(mod, "repositoryEnableChanged",
                                  Qt::QueuedConnection, Q_ARG(bool, offline));
    }
    updateTimer_.start();
    DBG << "checked()=" << checked();
}

void Repository::checkboxClicked()
{
    checkboxClicked(false);
}

void Repository::join()
{
    generalLaunch(joinParameters());
}

void Repository::launch()
{
    generalLaunch();
}

void Repository::generalLaunch(const QStringList& extraParams)
{
    QString executable = SettingsModel::arma3Path() + "\\arma3launcher.exe";
    QString steamExecutable = SettingsModel::steamPath() + "\\Steam.exe";
    QStringList arguments;

    if (QFileInfo(steamExecutable).exists())
    {
        //arma3launcher wont start the game with correct parameters
        //if steam isn't running.
        //Create tmp file containing parameters because steam.exe can only pass
        //~1000 characters in parameters
        QString paramsFile = createParFile(modsParameter());
        arguments << "-applaunch" << "107410" << "-par=" + paramsFile;
        executable = steamExecutable;
    }
    else if (modsParameter().size() > 0)
    {
        arguments << modsParameter();
    }
    arguments << "-noLauncher";
    if (SettingsModel::battlEyeEnabled())
    {
        //executable = SettingsModel::arma3Path() + "/arma3battleye.exe";
        //arguments << "0" << "1"; //Be requires
        arguments << "-useBe";
    }
    if (extraParams.size() > 0)
    {
        arguments << extraParams;
    }
    QString paramsString = SettingsModel::launchParameters();
    if (paramsString.size() > 0)
    {
        QStringList userParams = paramsString.split(" ");
        arguments << userParams;
    }
    DBG << " name() =" << name()
             << "executable =" << executable
             << "arguments =" << arguments;
    QProcess::startDetached(executable, arguments);
}

QString Repository::createParFile(const QString& parameters)
{
    QString path = "\"" + QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/afiSyncParameters.txt\"";
    DBG << path;
    QFile file(path);
    file.remove();
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream fileStream(&file);
    fileStream << parameters;
    file.close();
    return QDir::toNativeSeparators(path);
}

void Repository::updateEtaAndStatus()
{
    //Eta
    int eta = 0;
    QSet<QString> modStatuses;
    for (Mod* item : mods())
    {
        eta = std::max(item->eta(), eta);
        modStatuses.insert(item->status());
    }
    setEta(eta);
    //Status
    QSet<QString> readyStatuses;
    readyStatuses.insert(SyncStatus::READY);
    readyStatuses.insert(SyncStatus::INACTIVE);
    if (!checked())
    {
        setStatus(SyncStatus::INACTIVE);
    }
    else if ((modStatuses - readyStatuses).size() == 0)
    {
        //All mods are ready so repo is ready.
        setStatus(SyncStatus::READY);
        if (!ready_)
        {
            processCompletion(); //Runs only once.
        }
    }
    else if (modStatuses.contains(SyncStatus::DOWNLOADING))
    {
        setStatus(SyncStatus::DOWNLOADING);
        ready_ = false;
    }
    else if (modStatuses.find(SyncStatus::INDEXING) != modStatuses.end())
    {
        setStatus(SyncStatus::INDEXING);
    }
    else
    {
        setStatus(SyncStatus::WAITING);
    }
}

QString Repository::modsParameter() const
{
    if (childItems().size() == 0)
    {
        return "";
    }
    QString rVal = "-mod=";
    for (const Mod* mod : mods())
    {
        if (mod->checked())
        {
            QDir modDir(SettingsModel::modDownloadPath() + "/" + mod->name());
            rVal += modDir.absolutePath() + ";";
        }
    }
    rVal.remove(rVal.length() - 1, 1);
    return rVal;
}

QStringList Repository::joinParameters() const
{
    QStringList rVal;
    rVal << "-connect=" + serverAddress_
         << "-port=" + QString::number(port_);
    if (password_ != "")
    {
        rVal << "-password=" + password_;
    }
    return rVal;
}

void Repository::appendMod(Mod* item)
{
    item->addRepository(this);
    TreeItem::appendChild(new ModViewAdapter(item, this));
}

QString Repository::startText()
{
    if (checked() == false)
    {
        return "Start Disabled";
    }
    if (status() == SyncStatus::READY)
    {
        return "Start";
    }
    return "Start Disabled";
}

QString Repository::joinText()
{
    if (checked() == false)
    {
        return "Join Disabled";
    }
    if (status() == SyncStatus::READY)
    {
        return "Join";
    }
    return "Join Disabled";
}

BtsApi2* Repository::btsync() const
{
    DBG;
    return btsync_;
}

void Repository::enableMods()
{
    DBG << "name =" << name();
    for (Mod* mod : mods())
    {
        if (!mod->checked())
        {
            mod->checkboxClicked();
        }
    }
}

QList<Mod*> Repository::mods() const
{
    QList<Mod*> rVal;
    for (TreeItem* item : TreeItem::childItems())
    {
        rVal.append(static_cast<ModViewAdapter*>(item)->mod());
    }
    return rVal;
}

RootItem* Repository::parentItem()
{
    return static_cast<RootItem*>(TreeItem::parentItem());
}
<commit_msg>Fixed: Mod loading....<commit_after>#include <algorithm>
#include <QDir>
#include <QProcess>
#include <QStandardPaths>
#include "debug.h"
#include "settingsmodel.h"
#include "settingsmodel.h"
#include "repository.h"
#include "installer.h"
#include "modviewadapter.h"

Repository::Repository(const QString& name, const QString& serverAddress, unsigned port,
                      QString password, RootItem* parent):
    SyncItem(name, parent),
    btsync_(parent->btsync()),
    serverAddress_(serverAddress),
    port_(port),
    password_(password),
    ready_(true)
{
    DBG << "Created repo name =" << name;
    updateTimer_.setInterval(1000);
    updateTimer_.start();
    connect(&updateTimer_, SIGNAL(timeout()), this, SLOT(update()));
}

void Repository::update()
{
    updateEtaAndStatus();
    updateView(this);
}

Repository::~Repository()
{
    DBG << "name =" << name();
    for (Mod* mod : mods())
    {
        mod->removeRepository(this);
        if (mod->repositories().size() == 0)
        {
            DBG << "Deleting mod: " << mod->name()
                     << "from repo: " << name();
            delete mod;
        }
    }
    for (TreeItem* modAdapter : childItems())
    {
        delete modAdapter;
    }
}

void Repository::processCompletion()
{
    ready_ = true;
    DBG << "LastModified: " << lastModified();
    for (Mod* mod : mods())
    {
        mod->deleteExtraFiles();
        Installer::install(mod);
    }
}

int Repository::lastModified()
{
    int lastModified = 0;
    for (Mod* mod : mods())
    {
        lastModified = std::max(lastModified, mod->lastModified());
    }
    return lastModified;
}

void Repository::updateView(TreeItem* item, int row)
{
    parentItem()->updateView(item, row);
}

void Repository::checkboxClicked(bool offline)
{
    SyncItem::checkboxClicked();
    updateTimer_.stop();
    setStatus("Processing new mods...");
    updateView(this);
    for (Mod* mod : mods())
    {
        QMetaObject::invokeMethod(mod, "repositoryEnableChanged",
                                  Qt::QueuedConnection, Q_ARG(bool, offline));
    }
    updateTimer_.start();
    DBG << "checked()=" << checked();
}

void Repository::checkboxClicked()
{
    checkboxClicked(false);
}

void Repository::join()
{
    generalLaunch(joinParameters());
}

void Repository::launch()
{
    generalLaunch();
}

void Repository::generalLaunch(const QStringList& extraParams)
{
    QString executable = SettingsModel::arma3Path() + "\\arma3launcher.exe";
    QString steamExecutable = SettingsModel::steamPath() + "\\Steam.exe";
    QStringList arguments;

    if (QFileInfo(steamExecutable).exists())
    {
        //arma3launcher wont start the game with correct parameters
        //if steam isn't running.
        //Create tmp file containing parameters because steam.exe can only pass
        //~1000 characters in parameters
        QString paramsFile = createParFile(modsParameter());
        arguments << "-applaunch" << "107410" << "-par=" + paramsFile;
        executable = steamExecutable;
    }
    else if (modsParameter().size() > 0)
    {
        arguments << modsParameter();
    }
    arguments << "-noLauncher";
    if (SettingsModel::battlEyeEnabled())
    {
        //executable = SettingsModel::arma3Path() + "/arma3battleye.exe";
        //arguments << "0" << "1"; //Be requires
        arguments << "-useBe";
    }
    if (extraParams.size() > 0)
    {
        arguments << extraParams;
    }
    QString paramsString = SettingsModel::launchParameters();
    if (paramsString.size() > 0)
    {
        QStringList userParams = paramsString.split(" ");
        arguments << userParams;
    }
    DBG << " name() =" << name()
             << "executable =" << executable
             << "arguments =" << arguments;
    QProcess::startDetached(executable, arguments);
}

QString Repository::createParFile(const QString& parameters)
{
    QString path = QFileInfo("afiSyncParameters.txt").absoluteFilePath();
    DBG << path;
    QFile file(path);
    file.remove();
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream fileStream(&file);
    fileStream << parameters;
    file.close();
    return QDir::toNativeSeparators(path);
}

void Repository::updateEtaAndStatus()
{
    //Eta
    int eta = 0;
    QSet<QString> modStatuses;
    for (Mod* item : mods())
    {
        eta = std::max(item->eta(), eta);
        modStatuses.insert(item->status());
    }
    setEta(eta);
    //Status
    QSet<QString> readyStatuses;
    readyStatuses.insert(SyncStatus::READY);
    readyStatuses.insert(SyncStatus::INACTIVE);
    if (!checked())
    {
        setStatus(SyncStatus::INACTIVE);
    }
    else if ((modStatuses - readyStatuses).size() == 0)
    {
        //All mods are ready so repo is ready.
        setStatus(SyncStatus::READY);
        if (!ready_)
        {
            processCompletion(); //Runs only once.
        }
    }
    else if (modStatuses.contains(SyncStatus::DOWNLOADING))
    {
        setStatus(SyncStatus::DOWNLOADING);
        ready_ = false;
    }
    else if (modStatuses.find(SyncStatus::INDEXING) != modStatuses.end())
    {
        setStatus(SyncStatus::INDEXING);
    }
    else
    {
        setStatus(SyncStatus::WAITING);
    }
}

QString Repository::modsParameter() const
{
    if (childItems().size() == 0)
    {
        return "";
    }
    QString rVal = "-mod=";
    for (const Mod* mod : mods())
    {
        if (mod->checked())
        {
            QDir modDir(SettingsModel::modDownloadPath() + "/" + mod->name());
            rVal += modDir.absolutePath() + ";";
        }
    }
    rVal.remove(rVal.length() - 1, 1);
    return rVal;
}

QStringList Repository::joinParameters() const
{
    QStringList rVal;
    rVal << "-connect=" + serverAddress_
         << "-port=" + QString::number(port_);
    if (password_ != "")
    {
        rVal << "-password=" + password_;
    }
    return rVal;
}

void Repository::appendMod(Mod* item)
{
    item->addRepository(this);
    TreeItem::appendChild(new ModViewAdapter(item, this));
}

QString Repository::startText()
{
    if (checked() == false)
    {
        return "Start Disabled";
    }
    if (status() == SyncStatus::READY)
    {
        return "Start";
    }
    return "Start Disabled";
}

QString Repository::joinText()
{
    if (checked() == false)
    {
        return "Join Disabled";
    }
    if (status() == SyncStatus::READY)
    {
        return "Join";
    }
    return "Join Disabled";
}

BtsApi2* Repository::btsync() const
{
    DBG;
    return btsync_;
}

void Repository::enableMods()
{
    DBG << "name =" << name();
    for (Mod* mod : mods())
    {
        if (!mod->checked())
        {
            mod->checkboxClicked();
        }
    }
}

QList<Mod*> Repository::mods() const
{
    QList<Mod*> rVal;
    for (TreeItem* item : TreeItem::childItems())
    {
        rVal.append(static_cast<ModViewAdapter*>(item)->mod());
    }
    return rVal;
}

RootItem* Repository::parentItem()
{
    return static_cast<RootItem*>(TreeItem::parentItem());
}
<|endoftext|>


<commit_before><commit_msg>rsz<commit_after><|endoftext|>


<commit_before>#include "run_test_files.hpp"

#include "test_compiler.hpp"

namespace caliber {

namespace detail {
  void run_test_file(
    const std::string &file, mettle::log::test_logger &logger,
    const mettle::filter_set &/*filter*/, test_compiler &compiler
  ) {
    const mettle::test_name name = {{"Compilation tests"}, file, 0};
    logger.started_test(name);

    mettle::log::test_output output;

    using namespace std::chrono;
    auto then = steady_clock::now();
    int err = compiler(file, output);
    auto now = steady_clock::now();
    auto duration = duration_cast<mettle::log::test_duration>(now - then);

    if(!err)
      logger.passed_test(name, output, duration);
    else
      logger.failed_test(name, "Compilation failed", output, duration);
  }
}

void run_test_files(
  const std::vector<std::string> &files, mettle::log::test_logger &logger,
  const mettle::filter_set &filter
) {
  logger.started_run();
  logger.started_suite({"Compilation tests"});

  test_compiler compiler("/tmp/caliber-XXXXXX");

  for(const auto &file : files)
    detail::run_test_file(file, logger, filter, compiler);

  logger.ended_suite({"Compilation tests"});
  logger.ended_run();
}

} // namespace caliber
<commit_msg>Give each test a unique id. (This is important!)<commit_after>#include "run_test_files.hpp"

#include "test_compiler.hpp"

namespace caliber {

namespace detail {
  inline uint64_t generate_id() {
    static std::atomic<uint64_t> id_(0);
    return id_++;
  }

  void run_test_file(
    const std::string &file, mettle::log::test_logger &logger,
    const mettle::filter_set &/*filter*/, test_compiler &compiler
  ) {
    const mettle::test_name name = {{"Compilation tests"}, file, generate_id()};
    logger.started_test(name);

    mettle::log::test_output output;

    using namespace std::chrono;
    auto then = steady_clock::now();
    int err = compiler(file, output);
    auto now = steady_clock::now();
    auto duration = duration_cast<mettle::log::test_duration>(now - then);

    if(!err)
      logger.passed_test(name, output, duration);
    else
      logger.failed_test(name, "Compilation failed", output, duration);
  }
}

void run_test_files(
  const std::vector<std::string> &files, mettle::log::test_logger &logger,
  const mettle::filter_set &filter
) {
  logger.started_run();
  logger.started_suite({"Compilation tests"});

  test_compiler compiler("/tmp/caliber-XXXXXX");

  for(const auto &file : files)
    detail::run_test_file(file, logger, filter, compiler);

  logger.ended_suite({"Compilation tests"});
  logger.ended_run();
}

} // namespace caliber
<|endoftext|>


<commit_before>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.19
 * @brief Implementation of block Geräte base classes
 */

#include <algorithm>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cassert>

#include <SDL.h>

#include "block_geraet.hxx"
#include "io.hxx"

#include "src/exit_conditions.hxx"

using namespace std;

//Don't have more than this many outstanding synchronous packets
//at one time.
#define MAX_SYNC_OUTPACK 32

InputBlockGeraet::InputBlockGeraet(unsigned sz, AsyncAckGeraet* aag,
                                   DeletionStrategy ds)
: AAGReceiver(aag, ds),
  lastSeq(0), state(sz, 0), dirty(sz, true)
{
}

void InputBlockGeraet::receiveAccepted(NetworkConnection::seq_t,
                                       const byte* data, unsigned len)
throw () {
  //Ignore if too short
  if (len <= sizeof(block_geraet_seq)+2*sizeof(Uint16)) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring block packet of invalid size " << len << endl;
    #endif
    return;
  }

  const byte* end = data+len;

  block_geraet_seq seq;
  Uint16 fragix, nfrags;
  io::read(data, seq);
  io::read(data, fragix);
  io::read(data, nfrags);

  if (seq <= lastSeq) return; //Obsolete

  if (fragix >= nfrags) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring block update fragment " << fragix << '/'
         << nfrags << endl;
    #endif
    return;
  }

  //Create the fragment series if it does not yet exist
  if (!frags.count(seq)) {
    frags.insert(make_pair(seq, vector<vector<byte> >(nfrags)));
  }

  vector<vector<byte> >& frg = frags[seq];
  if (frg.size() != nfrags) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring incorrect nfrags in block update" << endl;
    cerr << "Reported: " << nfrags << "; actual: " << frg.size() << endl;
    #endif
    return;
  }

  if (!frg[fragix].empty()) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring duplicate block update fragment" << endl;
    #endif
    return;
  }

  //OK
  frg[fragix].assign(data, end);

  //See if this mutation is complete, and accumulate total size.
  //If it isn't, we're done for now.
  unsigned size = 0;
  for (unsigned i=0; i<nfrags; ++i)
    if (frg[i].empty())
      return;
    else
      size += frg[i].size();

  //Ready to reassemble
  vector<byte> assembled;
  assembled.reserve(size);
  for (unsigned i=0; i<nfrags; ++i)
    assembled.insert(assembled.end(),
                     frg[i].begin(), frg[i].end());

  data = &assembled[0];
  end = data+size;

  //Set seq information
  lastSeq = seq;
  //Remove any obsoleted mutations, including this one
  while (!frags.empty() && frags.begin()->first <= seq)
    frags.erase(frags.begin());

  //Parse data
  unsigned ix=0;
  while (data < end) {
    byte head = *data++;
    unsigned off, len;

    #define STOPLEN(l) if (data+(l) >= end) goto endloop

    //Interpret offset/size information
    if (head & 1) {
      off = ((head >> 1) & 0xF);
      len = ((head >> 5) & 0x7);
    } else {
      switch ((head >> 1) & 0x7) {
        Uint16 u16;
        unsigned u0, u1, u2;
        case 0:
          //4-4
          STOPLEN(1);
          off = (*data & 0xF);
          len = ((*data >> 4) & 0xF);
          ++data;
          break;

        case 1:
          //6-2
          STOPLEN(1);
          off = (*data & 0x3F);
          len = ((*data >> 6) & 0x3);
          ++data;
          break;

        case 2:
          //8-8
          STOPLEN(2);
          off = *data++;
          len = *data++;
          break;

        case 3:
          //12-4
          STOPLEN(2);
          u0 = *data++;
          u1 = *data++;
          off = u0 | ((u1 & 0xF) << 8);
          len = ((u1 >> 4) & 0xF);
          break;

        case 4:
          //16-8
          STOPLEN(3);
          io::read(data, u16);
          off = u16;
          len = *data++;
          break;

        case 5:
          //20-4
          STOPLEN(3);
          u0 = *data++;
          u1 = *data++;
          u2 = *data++;
          off = u0 | (u1 << 8) | ((u2 & 0xF) << 16);
          len = ((u2 >> 4) & 0xF);
          break;

        case 6:
          //24-8
          STOPLEN(4);
          io::read24(data, off);
          len = *data++;
          break;

        case 7:
          //8-4 embedded
          STOPLEN(1);
          off = *data++;
          len = ((head >> 4) & 0xF);
          break;

        default:
          assert(false);
          exit(EXIT_PROGRAM_BUG);
      }
    }

    ix += off;
    ++len; //Length is stored as one less than it actually is
    STOPLEN(len);
    if (ix+len > state.size()) break; //No longer in valid bounds

    //OK, apply changes
    memcpy(&state[ix], data, len);
    //Mark dirty
    fill_n(dirty.begin()+ix, len, true);
    //Update indices
    ix += len;
    data += len;
  }

  endloop:
  //Notify subclass of modification
  modified();
}

OutputBlockGeraet::OutputBlockGeraet(unsigned sz, AsyncAckGeraet* aag,
                                     DeletionStrategy ds)
: AAGSender(aag, ds),
  nextSeq(1),
  old(sz, 0), state(sz, 0),
  dirty(false)
{
}

void OutputBlockGeraet::update(unsigned) throw() {
  //Send new packet if dirty and not waiting in synchronous mode
  if (dirty && syncPending.empty()) {
    vector<byte> packet;
    block_geraet_seq seq = nextSeq++;
    packet.reserve(64);

    //Scan for changes between states
    unsigned index = 0;
    for (unsigned i=0; i < state.size(); ++i) {
      if (old[i] != state[i]) {
        //Found change.
        //Search for continguous changes; only stop if more than one consecutive
        //non-changed byte is encountered.
        //Additionally, note that we cannot encode more than 256 bytes in
        //one chunk.
        unsigned begin = i;
        while (i < state.size() && i-begin < 256
        &&     (old[i] != state[i]
            ||  (i+1 < state.size() && old[i+1] != state[i+1])))
          ++i;

        //i is now one past the last changed byte, or at the maximum length
        unsigned len = i-begin;
        unsigned elen = len-1;

        //Move back one byte since the outer loop will increment i again
        --i;

        //Pick the most compact encoding for offset and length
        unsigned off = begin - index;
        byte head[5];
        unsigned headlen;
        //See newnetworking.txt for the significance of the numbers below.
        if (off < 16 && elen < 8) {
          //Embedded
          head[0] = 1 | (off << 1) | (elen << 5);
          headlen = 1;
        } else if (off < 16 && elen < 16) {
          //4-4
          head[0] = 0;
          head[1] = off | (elen << 4);
          headlen = 2;
        } else if (off < 64 && elen < 4) {
          //6-2
          head[0] = 2;
          head[1] = off | (elen << 6);
          headlen = 2;
        } else if (off < 256 && elen < 16) {
          //8-4 embedded
          head[0] = 14 | (elen << 4);
          head[1] = off;
          headlen = 2;
        } else if (off < 256 && elen < 256) {
          //8-8
          head[0] = 4;
          head[1] = off;
          head[2] = elen;
          headlen = 3;
        } else if (off < 4096 && elen < 16) {
          //12-4
          head[0] = 6;
          head[1] = (off & 0xFF);
          head[2] = (off >> 8) | (elen << 4);
          headlen = 3;
        } else if (off < 65536 && elen < 256) {
          //16-8
          head[0] = 8;
          head[1] = (off & 0xFF);
          head[2] = (off >> 8);
          head[3] = elen;
          headlen = 4;
        } else if (off < (1 << 20) && elen < 16) {
          //20-4
          head[0] = 10;
          head[1] = (off & 0xFF);
          head[2] = ((off >> 8) & 0xFF);
          head[3] = ((off >> 16) | (elen << 4));
          headlen = 4;
        } else {
          //24-8
          head[0] = 12;
          head[1] = (off & 0xFF);
          head[2] = ((off >> 8) & 0xFF);
          head[3] = (off >> 16);
          head[4] = elen;
          headlen = 5;
        }

        //Copy header then data
        packet.insert(packet.end(), head, head+headlen);
        packet.insert(packet.end(),
                      state.begin()+begin, state.begin()+begin+len);

        //Advance index
        index = begin+len;
      }
    }

    //If nothing changed, unset dirty and finish
    if (packet.empty()) {
      dirty = false;
      return;
    }

    //The maximum amount of data that each packet can hold
    static const unsigned capacity =
        256-NetworkConnection::headerSize -
        sizeof(block_geraet_seq)-2*sizeof(Uint16);
    Uint16 nfrags = (packet.size()+capacity-1)/capacity;
    //Enter synchronous mode if this will push the size of
    //remoteStates to 8, or if nfrags != 1
    bool enterSync = (nfrags != 1 || remoteStates.size() >= 7);

    //Transmit fragments
    for (Uint16 i=0; i < nfrags; ++i) {
      static byte pack[256];
      byte* dat = pack;
      dat += NetworkConnection::headerSize;
      io::write(dat, seq);
      io::write(dat, i);
      io::write(dat, nfrags);
      //Copy data
      unsigned datlen = (i+1==nfrags? packet.size()-i*capacity : capacity);
      memcpy(dat, &packet[i*capacity], datlen);
      dat += datlen;
      //Send and record
      if (i < MAX_SYNC_OUTPACK) {
        NetworkConnection::seq_t netseq = send(pack, dat-pack);
        pending.insert(make_pair(netseq, seq));
        if (enterSync)
          syncPending.insert(make_pair(netseq, vector<byte>(pack, dat)));
      } else {
        //Maximum transmission rate exceeded, queue for later
        syncQueue.push_back(vector<byte>(pack, dat));
      }
    }

    //Record current state
    remoteStates.insert(make_pair(seq, state));

    //Mark clean
    dirty = false;
  }
}

void OutputBlockGeraet::ack(NetworkConnection::seq_t seq) throw() {
  //Remove synchronous entry if exists
  syncPending.erase(seq);
  //Get the mutation sequence number
  block_geraet_seq mseq;
  pending_t::iterator it = pending.find(seq);
  //This must ALWAYS exist
  assert(it != pending.end());
  mseq = it->second;
  pending.erase(it);

  //If there is a queued synchronous packet, send it now
  if (!syncQueue.empty()) {
    vector<byte>& packet = syncQueue.front();
    NetworkConnection::seq_t netseq = send(&packet[0], packet.size());
    syncPending.insert(make_pair(netseq, packet));
    pending.insert(make_pair(netseq, mseq));
    syncQueue.pop_front();
  }

  //Do nothing else unless we are no longer in synchronous mode (due to the
  //above syncPending operation)
  if (syncPending.empty()) {
    //See if this is a non-obsolete state
    remoteStates_t::iterator sit = remoteStates.find(mseq);
    if (sit != remoteStates.end()) {
      //Update to remote state
      old = sit->second;
      //Remove all states before and including this one
      while (!remoteStates.empty() && remoteStates.begin()->first <= mseq)
        remoteStates.erase(remoteStates.begin());
    }
  }
}

void OutputBlockGeraet::nak(NetworkConnection::seq_t seq) throw() {
  //Get the mutation sequence number
  pending_t::iterator it = pending.find(seq);
  assert(it != pending.end());
  block_geraet_seq mseq = it->second;
  pending.erase(it);

  /* If in synchronous mode, we only care about fragments of the
   * last state; the NAK can be ignored otherwise (the old states
   * will be cleared when the last packet is confirmed received).
   * If it is one of the synchronous packet fragments, retransmit
   * it and move it to its new location in the map.
   *
   * In high-speed mode, delete the remoteState corresponding to
   * the mseq; if this leaves remoteStates empty, set dirty to
   * true to retransmit the changes on the next update.
   */
  if (syncPending.empty()) {
    remoteStates.erase(mseq);
    if (remoteStates.empty())
      dirty = true;
  } else {
    syncPending_t::iterator sit = syncPending.find(seq);
    if (sit != syncPending.end()) {
      //Retransmit and move to new location in map
      vector<byte> packet(sit->second);
      syncPending.erase(sit);
      NetworkConnection::seq_t netseq = send(&packet[0], packet.size());
      syncPending.insert(make_pair(netseq, packet));
      pending.insert(make_pair(netseq, mseq));
    }
  }
}
<commit_msg>Fix input side of block Geräte dropping modifications that touch the end.<commit_after>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.19
 * @brief Implementation of block Geräte base classes
 */

#include <algorithm>
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cassert>

#include <SDL.h>

#include "block_geraet.hxx"
#include "io.hxx"

#include "src/exit_conditions.hxx"

using namespace std;

//Don't have more than this many outstanding synchronous packets
//at one time.
#define MAX_SYNC_OUTPACK 32

InputBlockGeraet::InputBlockGeraet(unsigned sz, AsyncAckGeraet* aag,
                                   DeletionStrategy ds)
: AAGReceiver(aag, ds),
  lastSeq(0), state(sz, 0), dirty(sz, true)
{
}

void InputBlockGeraet::receiveAccepted(NetworkConnection::seq_t,
                                       const byte* data, unsigned len)
throw () {
  //Ignore if too short
  if (len <= sizeof(block_geraet_seq)+2*sizeof(Uint16)) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring block packet of invalid size " << len << endl;
    #endif
    return;
  }

  const byte* end = data+len;

  block_geraet_seq seq;
  Uint16 fragix, nfrags;
  io::read(data, seq);
  io::read(data, fragix);
  io::read(data, nfrags);

  if (seq <= lastSeq) return; //Obsolete

  if (fragix >= nfrags) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring block update fragment " << fragix << '/'
         << nfrags << endl;
    #endif
    return;
  }

  //Create the fragment series if it does not yet exist
  if (!frags.count(seq)) {
    frags.insert(make_pair(seq, vector<vector<byte> >(nfrags)));
  }

  vector<vector<byte> >& frg = frags[seq];
  if (frg.size() != nfrags) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring incorrect nfrags in block update" << endl;
    cerr << "Reported: " << nfrags << "; actual: " << frg.size() << endl;
    #endif
    return;
  }

  if (!frg[fragix].empty()) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring duplicate block update fragment" << endl;
    #endif
    return;
  }

  //OK
  frg[fragix].assign(data, end);

  //See if this mutation is complete, and accumulate total size.
  //If it isn't, we're done for now.
  unsigned size = 0;
  for (unsigned i=0; i<nfrags; ++i)
    if (frg[i].empty())
      return;
    else
      size += frg[i].size();

  //Ready to reassemble
  vector<byte> assembled;
  assembled.reserve(size);
  for (unsigned i=0; i<nfrags; ++i)
    assembled.insert(assembled.end(),
                     frg[i].begin(), frg[i].end());

  data = &assembled[0];
  end = data+size;

  //Set seq information
  lastSeq = seq;
  //Remove any obsoleted mutations, including this one
  while (!frags.empty() && frags.begin()->first <= seq)
    frags.erase(frags.begin());

  //Parse data
  unsigned ix=0;
  while (data < end) {
    byte head = *data++;
    unsigned off, len;

    #define STOPLEN(l) if (data+(l) > end) goto endloop

    //Interpret offset/size information
    if (head & 1) {
      off = ((head >> 1) & 0xF);
      len = ((head >> 5) & 0x7);
    } else {
      switch ((head >> 1) & 0x7) {
        Uint16 u16;
        unsigned u0, u1, u2;
        case 0:
          //4-4
          STOPLEN(1);
          off = (*data & 0xF);
          len = ((*data >> 4) & 0xF);
          ++data;
          break;

        case 1:
          //6-2
          STOPLEN(1);
          off = (*data & 0x3F);
          len = ((*data >> 6) & 0x3);
          ++data;
          break;

        case 2:
          //8-8
          STOPLEN(2);
          off = *data++;
          len = *data++;
          break;

        case 3:
          //12-4
          STOPLEN(2);
          u0 = *data++;
          u1 = *data++;
          off = u0 | ((u1 & 0xF) << 8);
          len = ((u1 >> 4) & 0xF);
          break;

        case 4:
          //16-8
          STOPLEN(3);
          io::read(data, u16);
          off = u16;
          len = *data++;
          break;

        case 5:
          //20-4
          STOPLEN(3);
          u0 = *data++;
          u1 = *data++;
          u2 = *data++;
          off = u0 | (u1 << 8) | ((u2 & 0xF) << 16);
          len = ((u2 >> 4) & 0xF);
          break;

        case 6:
          //24-8
          STOPLEN(4);
          io::read24(data, off);
          len = *data++;
          break;

        case 7:
          //8-4 embedded
          STOPLEN(1);
          off = *data++;
          len = ((head >> 4) & 0xF);
          break;

        default:
          assert(false);
          exit(EXIT_PROGRAM_BUG);
      }
    }

    ix += off;
    ++len; //Length is stored as one less than it actually is
    STOPLEN(len);
    if (ix+len > state.size()) break; //No longer in valid bounds

    //OK, apply changes
    memcpy(&state[ix], data, len);
    //Mark dirty
    fill_n(dirty.begin()+ix, len, true);
    //Update indices
    ix += len;
    data += len;
  }

  endloop:
  //Notify subclass of modification
  modified();
  #undef STOPLEN
}

OutputBlockGeraet::OutputBlockGeraet(unsigned sz, AsyncAckGeraet* aag,
                                     DeletionStrategy ds)
: AAGSender(aag, ds),
  nextSeq(1),
  old(sz, 0), state(sz, 0),
  dirty(false)
{
}

void OutputBlockGeraet::update(unsigned) throw() {
  //Send new packet if dirty and not waiting in synchronous mode
  if (dirty && syncPending.empty()) {
    vector<byte> packet;
    block_geraet_seq seq = nextSeq++;
    packet.reserve(64);

    //Scan for changes between states
    unsigned index = 0;
    for (unsigned i=0; i < state.size(); ++i) {
      if (old[i] != state[i]) {
        //Found change.
        //Search for continguous changes; only stop if more than one consecutive
        //non-changed byte is encountered.
        //Additionally, note that we cannot encode more than 256 bytes in
        //one chunk.
        unsigned begin = i;
        while (i < state.size() && i-begin < 256
        &&     (old[i] != state[i]
            ||  (i+1 < state.size() && old[i+1] != state[i+1])))
          ++i;

        //i is now one past the last changed byte, or at the maximum length
        unsigned len = i-begin;
        unsigned elen = len-1;

        //Move back one byte since the outer loop will increment i again
        --i;

        //Pick the most compact encoding for offset and length
        unsigned off = begin - index;
        byte head[5];
        unsigned headlen;
        //See newnetworking.txt for the significance of the numbers below.
        if (off < 16 && elen < 8) {
          //Embedded
          head[0] = 1 | (off << 1) | (elen << 5);
          headlen = 1;
        } else if (off < 16 && elen < 16) {
          //4-4
          head[0] = 0;
          head[1] = off | (elen << 4);
          headlen = 2;
        } else if (off < 64 && elen < 4) {
          //6-2
          head[0] = 2;
          head[1] = off | (elen << 6);
          headlen = 2;
        } else if (off < 256 && elen < 16) {
          //8-4 embedded
          head[0] = 14 | (elen << 4);
          head[1] = off;
          headlen = 2;
        } else if (off < 256 && elen < 256) {
          //8-8
          head[0] = 4;
          head[1] = off;
          head[2] = elen;
          headlen = 3;
        } else if (off < 4096 && elen < 16) {
          //12-4
          head[0] = 6;
          head[1] = (off & 0xFF);
          head[2] = (off >> 8) | (elen << 4);
          headlen = 3;
        } else if (off < 65536 && elen < 256) {
          //16-8
          head[0] = 8;
          head[1] = (off & 0xFF);
          head[2] = (off >> 8);
          head[3] = elen;
          headlen = 4;
        } else if (off < (1 << 20) && elen < 16) {
          //20-4
          head[0] = 10;
          head[1] = (off & 0xFF);
          head[2] = ((off >> 8) & 0xFF);
          head[3] = ((off >> 16) | (elen << 4));
          headlen = 4;
        } else {
          //24-8
          head[0] = 12;
          head[1] = (off & 0xFF);
          head[2] = ((off >> 8) & 0xFF);
          head[3] = (off >> 16);
          head[4] = elen;
          headlen = 5;
        }

        //Copy header then data
        packet.insert(packet.end(), head, head+headlen);
        packet.insert(packet.end(),
                      state.begin()+begin, state.begin()+begin+len);

        //Advance index
        index = begin+len;
      }
    }

    //If nothing changed, unset dirty and finish
    if (packet.empty()) {
      dirty = false;
      return;
    }

    //The maximum amount of data that each packet can hold
    static const unsigned capacity =
        256-NetworkConnection::headerSize -
        sizeof(block_geraet_seq)-2*sizeof(Uint16);
    Uint16 nfrags = (packet.size()+capacity-1)/capacity;
    //Enter synchronous mode if this will push the size of
    //remoteStates to 8, or if nfrags != 1
    bool enterSync = (nfrags != 1 || remoteStates.size() >= 7);

    //Transmit fragments
    for (Uint16 i=0; i < nfrags; ++i) {
      static byte pack[256];
      byte* dat = pack;
      dat += NetworkConnection::headerSize;
      io::write(dat, seq);
      io::write(dat, i);
      io::write(dat, nfrags);
      //Copy data
      unsigned datlen = (i+1==nfrags? packet.size()-i*capacity : capacity);
      memcpy(dat, &packet[i*capacity], datlen);
      dat += datlen;
      //Send and record
      if (i < MAX_SYNC_OUTPACK) {
        NetworkConnection::seq_t netseq = send(pack, dat-pack);
        pending.insert(make_pair(netseq, seq));
        if (enterSync)
          syncPending.insert(make_pair(netseq, vector<byte>(pack, dat)));
      } else {
        //Maximum transmission rate exceeded, queue for later
        syncQueue.push_back(vector<byte>(pack, dat));
      }
    }

    //Record current state
    remoteStates.insert(make_pair(seq, state));

    //Mark clean
    dirty = false;
  }
}

void OutputBlockGeraet::ack(NetworkConnection::seq_t seq) throw() {
  //Remove synchronous entry if exists
  syncPending.erase(seq);
  //Get the mutation sequence number
  block_geraet_seq mseq;
  pending_t::iterator it = pending.find(seq);
  //This must ALWAYS exist
  assert(it != pending.end());
  mseq = it->second;
  pending.erase(it);

  //If there is a queued synchronous packet, send it now
  if (!syncQueue.empty()) {
    vector<byte>& packet = syncQueue.front();
    NetworkConnection::seq_t netseq = send(&packet[0], packet.size());
    syncPending.insert(make_pair(netseq, packet));
    pending.insert(make_pair(netseq, mseq));
    syncQueue.pop_front();
  }

  //Do nothing else unless we are no longer in synchronous mode (due to the
  //above syncPending operation)
  if (syncPending.empty()) {
    //See if this is a non-obsolete state
    remoteStates_t::iterator sit = remoteStates.find(mseq);
    if (sit != remoteStates.end()) {
      //Update to remote state
      old = sit->second;
      //Remove all states before and including this one
      while (!remoteStates.empty() && remoteStates.begin()->first <= mseq)
        remoteStates.erase(remoteStates.begin());
    }
  }
}

void OutputBlockGeraet::nak(NetworkConnection::seq_t seq) throw() {
  //Get the mutation sequence number
  pending_t::iterator it = pending.find(seq);
  assert(it != pending.end());
  block_geraet_seq mseq = it->second;
  pending.erase(it);

  /* If in synchronous mode, we only care about fragments of the
   * last state; the NAK can be ignored otherwise (the old states
   * will be cleared when the last packet is confirmed received).
   * If it is one of the synchronous packet fragments, retransmit
   * it and move it to its new location in the map.
   *
   * In high-speed mode, delete the remoteState corresponding to
   * the mseq; if this leaves remoteStates empty, set dirty to
   * true to retransmit the changes on the next update.
   */
  if (syncPending.empty()) {
    remoteStates.erase(mseq);
    if (remoteStates.empty())
      dirty = true;
  } else {
    syncPending_t::iterator sit = syncPending.find(seq);
    if (sit != syncPending.end()) {
      //Retransmit and move to new location in map
      vector<byte> packet(sit->second);
      syncPending.erase(sit);
      NetworkConnection::seq_t netseq = send(&packet[0], packet.size());
      syncPending.insert(make_pair(netseq, packet));
      pending.insert(make_pair(netseq, mseq));
    }
  }
}
<|endoftext|>


<commit_before>#ifndef NETWORK_GAME_HXX_
#define NETWORK_GAME_HXX_

/**
 * @file
 * @author Jason Lingle
 * @date 2012.03.15
 * @brief Contains classes to bridge the C++ networking to the Tcl game classes.
 */

#include <string>
#include <map>

#include "src/core/aobject.hxx"
#include "globalid.hxx"
#include "network_assembly.hxx"

class NetworkConnection;
class GameAdvertiser;
class GameDiscoverer;
class GameField;

/**
 * Contains the data associated with a single Peer, which is shared across
 * possibly multiple (non-coincident) NetworkConnection objects (eg, across
 * temporary drops).
 */
class Peer: public AObject {
public:
  ///The global ID information for the peer, for purposes of connections
  GlobalID gid;
  ///The numeric ID of the peer, for purposes of determing who's overseer
  unsigned nid;
  ///Whether this peer is ready to perform the role of overseer
  bool overseerReady;
  ///The cumulative number of times a connection attempt was made. This is
  ///decremented if non-zero once every so often. Reconnect attempts will not be
  ///made if this exceeds a certain value.
  unsigned connectionAttempts;
  ///The current NetworkConnection associated with this peer
  NetworkConnection* cxn;
};

/**
 * Abstract class used to relay events to the Tcl game system.
 */
class NetIface: public AObject {
public:
  ///Called when the given Peer has been created
  virtual void addPeer(Peer*) = 0;
  ///Called immediately before the given Peer will be removed
  virtual void delPeer(Peer*) = 0;
  ///Called when the overseer Peer changes
  virtual void setOverseer(Peer*) = 0;

  ///Called when a broadcast message from the given peer is received
  virtual void receiveBroadcast(Peer*, const char*) = 0;
  ///Called when a to-overseer message from the given peer is received
  virtual void receiveOverseer(Peer*, const char*) = 0;
  ///Called when a unicast message from the given peer is received
  virtual void receiveUnicast(Peer*, const char*) = 0;

  ///Called when a datp alteration is received from the given Peer.
  ///Return true if the changes are accepted.
  virtual bool alterDatp(Peer*, const char* key, const char* val) = 0;
  ///Called when a dats alteration is received from the current overseer.
  ///Return true if the changes arv accepted.
  virtual bool alterDats(const char* key, const char* val) = 0;

  ///Called when all network connectivity has been lost, with the given reason.
  virtual void connectionLost(const char*) = 0;
};

/**
 * Provides a façade to the networking system which is easily accessible by Tcl.
 * While it primarily serves to manage associating Peers with
 * NetworkConnections (including peer discovery and topology discovery), it also
 * has some secondary utilities, such as game discovery, which would be hard
 * for Tcl to use by itself (since it requires manipulation of asio classes).
 */
class NetworkGame: public AObject {
  //The reason given (localised) for the most recent disconnect
  std::string lastDisconnectReason;
  //Map of NetworkConnection*s to Peer*s.
  typedef std::map<NetworkConnection*, Peer*> peers_t;
  peers_t peers;
  //The current overseer
  Peer* overseer;

  //Peer representing the local system
  Peer localPeer;

  NetworkAssembly assembly;
  //The current NetIface to use, or NULL if none
  NetIface* interface;

  GameAdvertiser* advertiser;
  GameDiscoverer* discoverer;

public:
  /**
   * Constructs a NetworkGame with the given initial GameField.
   */
  NetworkGame(GameField*);

  /**
   * Returns a pointer to the Peer object representing the local peer.
   */
  Peer* getLocalPeer() throw() { return &localPeer; }
  /**
   * Returns the Peer* which is the current overseer, or NULL for the local
   * peer.
   */
  Peer* getOverseer() const throw() { return overseer; }
  /**
   * Returns the stated reason for the most recent connection failure.
   */
  const std::string& getDisconnectReason() const throw() {
    return lastDisconnectReason;
  }

  /**
   * Alters the NetIface used. May be NULL.
   */
  void setNetIface(NetIface*) throw();

  /**
   * Initiates game advertising if not done already, then sets the gameMode
   * parm appropriately.
   */
  void setAdvertising(const char* gameMode) throw();
  /**
   * Terminates any ongoing game advertisement.
   */
  void stopAdvertising() throw();

  /**
   * Begins a scan using a GameDiscoverer. If a scan is currently ongoing,
   * nothing happens.
   */
  void startDiscoveryScan() throw();
  /**
   * Returns the current progress of the GameDiscoverer scan, between 0 and 1
   * inclusive. Returns -1 if no scan is in progress.
   */
  float discoveryScanProgress() const throw();
  /**
   * Returns whether the current scan has completed.
   * Returns false if no scan has been initiated.
   */
  bool discoveryScanDone() const throw()
  /**
   * Returns a Tcl list of scan results, suitable for display to the user.
   * To start a game.
   */
  std::string getDiscoveryResults() throw();

  /**
   * Begins listining for new connections. This is used to start hosting a game.
   */
  void connectToNothing() throw();
  /**
   * Initiates a game using the discovery result at the given index.
   * Begins listening automatically.
   */
  void connectToDiscovery(unsigned) throw();
  /**
   * Initiates a game to the given LAN IP address/port combination.
   */
  void connectToLan(const char*, unsigned) throw();
  /**
   * Initiates a game to the given la:lp/ia:ip string (ie, an Internet game).
   */
  void connectToInternet(const char*) throw()
};

#endif /* NETWORK_GAME_HXX_ */
<commit_msg>Add missing semicolon.<commit_after>#ifndef NETWORK_GAME_HXX_
#define NETWORK_GAME_HXX_

/**
 * @file
 * @author Jason Lingle
 * @date 2012.03.15
 * @brief Contains classes to bridge the C++ networking to the Tcl game classes.
 */

#include <string>
#include <map>

#include "src/core/aobject.hxx"
#include "globalid.hxx"
#include "network_assembly.hxx"

class NetworkConnection;
class GameAdvertiser;
class GameDiscoverer;
class GameField;

/**
 * Contains the data associated with a single Peer, which is shared across
 * possibly multiple (non-coincident) NetworkConnection objects (eg, across
 * temporary drops).
 */
class Peer: public AObject {
public:
  ///The global ID information for the peer, for purposes of connections
  GlobalID gid;
  ///The numeric ID of the peer, for purposes of determing who's overseer
  unsigned nid;
  ///Whether this peer is ready to perform the role of overseer
  bool overseerReady;
  ///The cumulative number of times a connection attempt was made. This is
  ///decremented if non-zero once every so often. Reconnect attempts will not be
  ///made if this exceeds a certain value.
  unsigned connectionAttempts;
  ///The current NetworkConnection associated with this peer
  NetworkConnection* cxn;
};

/**
 * Abstract class used to relay events to the Tcl game system.
 */
class NetIface: public AObject {
public:
  ///Called when the given Peer has been created
  virtual void addPeer(Peer*) = 0;
  ///Called immediately before the given Peer will be removed
  virtual void delPeer(Peer*) = 0;
  ///Called when the overseer Peer changes
  virtual void setOverseer(Peer*) = 0;

  ///Called when a broadcast message from the given peer is received
  virtual void receiveBroadcast(Peer*, const char*) = 0;
  ///Called when a to-overseer message from the given peer is received
  virtual void receiveOverseer(Peer*, const char*) = 0;
  ///Called when a unicast message from the given peer is received
  virtual void receiveUnicast(Peer*, const char*) = 0;

  ///Called when a datp alteration is received from the given Peer.
  ///Return true if the changes are accepted.
  virtual bool alterDatp(Peer*, const char* key, const char* val) = 0;
  ///Called when a dats alteration is received from the current overseer.
  ///Return true if the changes arv accepted.
  virtual bool alterDats(const char* key, const char* val) = 0;

  ///Called when all network connectivity has been lost, with the given reason.
  virtual void connectionLost(const char*) = 0;
};

/**
 * Provides a façade to the networking system which is easily accessible by Tcl.
 * While it primarily serves to manage associating Peers with
 * NetworkConnections (including peer discovery and topology discovery), it also
 * has some secondary utilities, such as game discovery, which would be hard
 * for Tcl to use by itself (since it requires manipulation of asio classes).
 */
class NetworkGame: public AObject {
  //The reason given (localised) for the most recent disconnect
  std::string lastDisconnectReason;
  //Map of NetworkConnection*s to Peer*s.
  typedef std::map<NetworkConnection*, Peer*> peers_t;
  peers_t peers;
  //The current overseer
  Peer* overseer;

  //Peer representing the local system
  Peer localPeer;

  NetworkAssembly assembly;
  //The current NetIface to use, or NULL if none
  NetIface* interface;

  GameAdvertiser* advertiser;
  GameDiscoverer* discoverer;

public:
  /**
   * Constructs a NetworkGame with the given initial GameField.
   */
  NetworkGame(GameField*);

  /**
   * Returns a pointer to the Peer object representing the local peer.
   */
  Peer* getLocalPeer() throw() { return &localPeer; }
  /**
   * Returns the Peer* which is the current overseer, or NULL for the local
   * peer.
   */
  Peer* getOverseer() const throw() { return overseer; }
  /**
   * Returns the stated reason for the most recent connection failure.
   */
  const std::string& getDisconnectReason() const throw() {
    return lastDisconnectReason;
  }

  /**
   * Alters the NetIface used. May be NULL.
   */
  void setNetIface(NetIface*) throw();

  /**
   * Initiates game advertising if not done already, then sets the gameMode
   * parm appropriately.
   */
  void setAdvertising(const char* gameMode) throw();
  /**
   * Terminates any ongoing game advertisement.
   */
  void stopAdvertising() throw();

  /**
   * Begins a scan using a GameDiscoverer. If a scan is currently ongoing,
   * nothing happens.
   */
  void startDiscoveryScan() throw();
  /**
   * Returns the current progress of the GameDiscoverer scan, between 0 and 1
   * inclusive. Returns -1 if no scan is in progress.
   */
  float discoveryScanProgress() const throw();
  /**
   * Returns whether the current scan has completed.
   * Returns false if no scan has been initiated.
   */
  bool discoveryScanDone() const throw()
  /**
   * Returns a Tcl list of scan results, suitable for display to the user.
   * To start a game.
   */
  std::string getDiscoveryResults() throw();

  /**
   * Begins listining for new connections. This is used to start hosting a game.
   */
  void connectToNothing() throw();
  /**
   * Initiates a game using the discovery result at the given index.
   * Begins listening automatically.
   */
  void connectToDiscovery(unsigned) throw();
  /**
   * Initiates a game to the given LAN IP address/port combination.
   */
  void connectToLan(const char*, unsigned) throw();
  /**
   * Initiates a game to the given la:lp/ia:ip string (ie, an Internet game).
   */
  void connectToInternet(const char*) throw();
};

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


<commit_before>#ifndef OBJECT_CXX_OBJECT_HH
# define OBJECT_CXX_OBJECT_HH

# include <vector>

# include <boost/optional.hpp>

# include <object/object.hh>

#define URBI_CXX_OBJECT(Name)                                   \
public:                                                         \
  static void initialize(CxxObject::Binder<Name>& binder);      \
  static const std::string type_name;                           \
  virtual std::string type_name_get() const;                    \
  static rObject proto;                                         \
private:                                                        \
  friend class TypeInitializer<Name>;                           \
  static rObject proto_make();                                  \

#define URBI_CXX_OBJECT_REGISTER(Name)                          \
  static bool Name ## _added__  = CxxObject::add<Name>();       \
  const std::string Name::type_name = #Name;                    \
  rObject Name::proto;                                          \
                                                                \
  std::string                                                   \
  Name::type_name_get() const                                   \
  {                                                             \
  return type_name;                                             \
  }                                                             \

namespace object
{
  /// Base class for Urbi bound C++ classes.
  class CxxObject: public Object
  {
  public:

    /// Build a CxxObject.
    CxxObject();

    /// Bind all registered objects.
    /** This function should be called once to bind C++ objects.
     *  \param global Where to store the new classes.
     */
    static void initialize(rObject global);
    static void create();
    static void cleanup();

    /// Register a C++ class to be bound on the urbi side.
    /** \param T      The class to bind.
     *  \param name   Name of the class on the Urbi side.
     *  \param tgt    Where to store the result.
     */
    template<typename T>
    static bool add();

    virtual std::string type_name_get() const = 0;

  private:

    class Initializer
    {
    public:
      Initializer(rObject& tgt);
      virtual ~Initializer();
      virtual rObject make_class() = 0;
      virtual void create() = 0;
      virtual libport::Symbol name() = 0;
    protected:
      rObject& res_;
    };

    template <typename T>
    class TypeInitializer: public Initializer
    {
    public:
      TypeInitializer();
      virtual rObject make_class();
      virtual void create();
      virtual libport::Symbol name();
    };

    typedef std::vector<Initializer*> initializers_type;
    static initializers_type& initializers_get();

  public:
    /// Functor to bind methods on the urbi side.
    /** An instance of this class is given to the static initialize
     *  method of the bound classes. It can then be used to bind
     *  method and/or attributes on the Urbi side.
     */
    template <typename T>
    class Binder
    {
    public:
      /// Bind \a method with \a name
      template <typename M>
      void operator()(const libport::Symbol& name, M method);

    private:
      Binder(rObject tgt);
      // This method is allowed to construct a Binder.
      // VC++ is not a friend of friend method templates, so friend the class.
      friend class TypeInitializer<T>;
      rObject tgt_;
    };

  };

  /// Raise an exception if \a o is not a \a exp. If \a idx is given,
  /// report the type error for argument \a idx.
  void type_check(const rObject& o, const rObject& exp,
                  boost::optional<unsigned> idx = boost::optional<unsigned>());

  /// Throw an exception if formal != effective.
  /// \note: \c self is included in the count.
  void check_arg_count (unsigned effective, unsigned formal);

  /// Same as above, with a minimum and maximum number of
  /// formal parameters.
  void check_arg_count (unsigned effective, unsigned minformal, unsigned maxformal);

}

# if  ! defined(OBJECT_STRING_CLASS_HH) && ! defined(OBJECT_FLOAT_CLASS_HH) \
  && ! defined(OBJECT_LIST_CLASS_HH) && !defined(OBJECT_TAG_CLASS_HH)
#  include <object/cxx-object.hxx>
# endif

#endif
<commit_msg>The "TypeInitializer" class must be seen by child classes.<commit_after>#ifndef OBJECT_CXX_OBJECT_HH
# define OBJECT_CXX_OBJECT_HH

# include <vector>

# include <boost/optional.hpp>

# include <object/object.hh>

#define URBI_CXX_OBJECT(Name)                                   \
public:                                                         \
  static void initialize(CxxObject::Binder<Name>& binder);      \
  static const std::string type_name;                           \
  virtual std::string type_name_get() const;                    \
  static rObject proto;                                         \
private:                                                        \
  friend class TypeInitializer<Name>;                           \
  static rObject proto_make();                                  \

#define URBI_CXX_OBJECT_REGISTER(Name)                          \
  static bool Name ## _added__  = CxxObject::add<Name>();       \
  const std::string Name::type_name = #Name;                    \
  rObject Name::proto;                                          \
                                                                \
  std::string                                                   \
  Name::type_name_get() const                                   \
  {                                                             \
  return type_name;                                             \
  }                                                             \

namespace object
{
  /// Base class for Urbi bound C++ classes.
  class CxxObject: public Object
  {
  public:

    /// Build a CxxObject.
    CxxObject();

    /// Bind all registered objects.
    /** This function should be called once to bind C++ objects.
     *  \param global Where to store the new classes.
     */
    static void initialize(rObject global);
    static void create();
    static void cleanup();

    /// Register a C++ class to be bound on the urbi side.
    /** \param T      The class to bind.
     *  \param name   Name of the class on the Urbi side.
     *  \param tgt    Where to store the result.
     */
    template<typename T>
    static bool add();

    virtual std::string type_name_get() const = 0;

  protected:

    class Initializer
    {
    public:
      Initializer(rObject& tgt);
      virtual ~Initializer();
      virtual rObject make_class() = 0;
      virtual void create() = 0;
      virtual libport::Symbol name() = 0;
    protected:
      rObject& res_;
    };

    template <typename T>
    class TypeInitializer: public Initializer
    {
    public:
      TypeInitializer();
      virtual rObject make_class();
      virtual void create();
      virtual libport::Symbol name();
    };

    typedef std::vector<Initializer*> initializers_type;
    static initializers_type& initializers_get();

  public:
    /// Functor to bind methods on the urbi side.
    /** An instance of this class is given to the static initialize
     *  method of the bound classes. It can then be used to bind
     *  method and/or attributes on the Urbi side.
     */
    template <typename T>
    class Binder
    {
    public:
      /// Bind \a method with \a name
      template <typename M>
      void operator()(const libport::Symbol& name, M method);

    private:
      Binder(rObject tgt);
      // This method is allowed to construct a Binder.
      // VC++ is not a friend of friend method templates, so friend the class.
      friend class TypeInitializer<T>;
      rObject tgt_;
    };

  };

  /// Raise an exception if \a o is not a \a exp. If \a idx is given,
  /// report the type error for argument \a idx.
  void type_check(const rObject& o, const rObject& exp,
                  boost::optional<unsigned> idx = boost::optional<unsigned>());

  /// Throw an exception if formal != effective.
  /// \note: \c self is included in the count.
  void check_arg_count (unsigned effective, unsigned formal);

  /// Same as above, with a minimum and maximum number of
  /// formal parameters.
  void check_arg_count (unsigned effective, unsigned minformal, unsigned maxformal);

}

# if  ! defined(OBJECT_STRING_CLASS_HH) && ! defined(OBJECT_FLOAT_CLASS_HH) \
  && ! defined(OBJECT_LIST_CLASS_HH) && !defined(OBJECT_TAG_CLASS_HH)
#  include <object/cxx-object.hxx>
# endif

#endif
<|endoftext|>


<commit_before>#include "Factory.h"

#include "../ob_instance/Instance.h"

namespace OpenBlox{
	void Factory::addClass(std::string className, ClassMaker* const newClassMaker){
		lokupTable[className] = newClassMaker;
		registered.push_back(className);
	}

	ob_instance::Instance* Factory::create(std::string className){
		if(lokupTable[className]){
			ClassMaker* maker = lokupTable[className];
			if(maker->isInstantiatable()){
				return maker->getInstance();
			}
		}

		return NULL;
	}

	ob_instance::Instance* Factory::createService(std::string className, bool isDataModel){
		if(lokupTable[className]){
			ClassMaker* maker = lokupTable[className];
			std::cout << maker << std::endl;
			if(maker->isService(isDataModel)){
				return maker->getInstance();
			}
		}

		return NULL;
	}

	std::vector<std::string> Factory::getRegisteredMetatables(){
		return registered;
	}

	bool Factory::isA(const ob_instance::Instance* obj, std::string className){
		if(lokupTable[className]){
			ClassMaker* maker = lokupTable[className];
			return maker->isA(obj);
		}
		return false;
	}

	void Factory::releaseTable(){}
}
<commit_msg>Removed debug code<commit_after>#include "Factory.h"

#include "../ob_instance/Instance.h"

namespace OpenBlox{
	void Factory::addClass(std::string className, ClassMaker* const newClassMaker){
		lokupTable[className] = newClassMaker;
		registered.push_back(className);
	}

	ob_instance::Instance* Factory::create(std::string className){
		if(lokupTable[className]){
			ClassMaker* maker = lokupTable[className];
			if(maker->isInstantiatable()){
				return maker->getInstance();
			}
		}

		return NULL;
	}

	ob_instance::Instance* Factory::createService(std::string className, bool isDataModel){
		if(lokupTable[className]){
			ClassMaker* maker = lokupTable[className];
			if(maker->isService(isDataModel)){
				return maker->getInstance();
			}
		}

		return NULL;
	}

	std::vector<std::string> Factory::getRegisteredMetatables(){
		return registered;
	}

	bool Factory::isA(const ob_instance::Instance* obj, std::string className){
		if(lokupTable[className]){
			ClassMaker* maker = lokupTable[className];
			return maker->isA(obj);
		}
		return false;
	}

	void Factory::releaseTable(){}
}
<|endoftext|>


<commit_before>/*
This file is part of Groho, a simulator for inter-planetary travel and warfare.
Copyright (c) 2017-2018 by Kaushik Ghose. Some rights reserved, see LICENSE

Subclasses Orrery and incorporates code to read JPL/NASA SPK/DAF files.
One or more SPK files can be loaded into memory and body position computed
at given times.
*/

#include <unordered_set>

#define LOGURU_WITH_STREAMS 1
#include "loguru.hpp"

#include "solar_system.hpp"
#include "spkorrery.hpp"

namespace orrery {

EphemerisVec combine_ephemerides(
    const EphemerisVec& old_ephemera, const EphemerisVec& new_ephemera)
{
    EphemerisVec unsorted_ephemera;

    std::unordered_set<int> centers;

    for (auto e : old_ephemera) {
        unsorted_ephemera.push_back(e);
        centers.insert(e->target_code);
    }

    // Add if not duplicate
    for (auto e : new_ephemera) {
        if (centers.count(e->target_code) == 0) {
            unsorted_ephemera.push_back(e);
            centers.insert(e->target_code);
        } else {
            LOG_S(WARNING) << "Ignoring duplicate body (" << e->target_code
                           << ")";
        }
    }

    return unsorted_ephemera;
}

// Reorder the Ephemerides such that bodies serving as centers come before the
// target bodies.
// This is a multi-pass algorithm. We repeatedly sweep over the original list
// adding bodies to the sorted list as long as we have computed their center
EphemerisVec sort_ephemerides(const EphemerisVec& un_srt)
{
    EphemerisVec srt;

    std::unordered_set<int> centers = { 0 };

    while (srt.size() < un_srt.size()) {
        size_t centers_resolved_this_time = 0;
        for (size_t i = 0; i < un_srt.size(); i++) {
            if (centers.count(un_srt[i]->target_code))
                continue;
            if (centers.count(un_srt[i]->center_code)) {
                srt.push_back(un_srt[i]);
                centers.insert(un_srt[i]->target_code);
                centers_resolved_this_time++;
            }
        }
        if (centers_resolved_this_time == 0) {
            LOG_S(ERROR) << "Orrery has " << un_srt.size() - srt.size()
                         << " bodies with center(s) that do(es) not exist";
            break;
        }
    }

    return srt;
}

// Returns a vector v such that v[i] points to the ephemerides in srt that
// serves as the center for i. Undefined for i whose center is 0
std::vector<size_t> create_center_indexes(const EphemerisVec& srt)
{
    std::unordered_map<int, size_t> code2index;

    std::vector<size_t> ci(srt.size());

    for (size_t i = 0; i < srt.size(); i++) {
        code2index[srt[i]->target_code] = i;
    }

    for (size_t i = 0; i < srt.size(); i++) {
        if (srt[i]->center_code != 0) {
            ci[i] = code2index[srt[i]->center_code];
        }
    }

    return ci;
}

// For every body in the SPK file create a mirror OrreryBody to store the
// computed position information and some planetary constants. It is important
// to note that this list contains barycenters which are dynamical (virtual)
// points and not for display or gravitational computation.
OrreryBodyVec create_bodies(const EphemerisVec& ephemera)
{
    OrreryBodyVec bodies;
    for (auto e : ephemera) {
        OrreryBody ob;
        if (body_library.count(e->target_code)) {
            ob.property = body_library[e->target_code];
        }
        bodies.push_back(ob);
    }
    return bodies;
}

SpkOrrery::SpkOrrery(std::set<std::string> fnames, double begin_s, double end_s)
    : begin_s(begin_s)
    , end_s(end_s)
    , Orrery()
{
    for (auto& orrery_name : fnames) {
        size_t body_count = ephemera.size();
        load_orrery_model(orrery_name, begin_s, end_s);
        LOG_S(INFO) << ephemera.size() - body_count << " bodies from "
                    << orrery_name;
    }
    LOG_S(INFO) << ephemera.size() << " bodies in Orrery";

    ephemera   = sort_ephemerides(ephemera);
    center_idx = create_center_indexes(ephemera);
    bodies     = create_bodies(ephemera);
}

bool SpkOrrery::load_orrery_model(
    std::string fname, double begin_s, double end_s)
{
    std::ifstream nasa_spk_file(fname, std::ios::binary);

    if (!nasa_spk_file) {
        LOG_S(ERROR) << "Could not open " << fname;
        ok = false;
        return false;
    }

    ephemera = combine_ephemerides(
        ephemera, load_spk(nasa_spk_file, begin_s, end_s));

    ok = true;
    return ok;
}

void set_pos(double s, const Ephemeris& eph, sim::Vector& pos)
{
    const auto& e = eph.evec[std::floor((s - eph.begin_s) / eph.interval_s)];

    pos.x = cheby_eval(e.t_mid, e.t_half, e.X, s);
    pos.y = cheby_eval(e.t_mid, e.t_half, e.Y, s);
    pos.z = cheby_eval(e.t_mid, e.t_half, e.Z, s);
}

// Fill out the (x, y, z) of each Orrery body
void SpkOrrery::set_orrery_to(double s)
{
    for (size_t i = 0; i < ephemera.size(); i++) {
        set_pos(s, *ephemera[i], bodies[i].state.pos);
        bodies[i].state.t = s;
    }

    for (size_t i = 0; i < ephemera.size(); i++) {
        if (ephemera[i]->center_code != 0) {
            bodies[i].state.pos += bodies[center_idx[i]].state.pos;
        }
    }
}

// Fill out the (x, y, z) of each Orrery body and return us an immutable
// vector containing this information.
const OrreryBodyVec& SpkOrrery::get_orrery_at(double s)
{
    set_orrery_to(s);
    return bodies;
}

// This is a little expensive because we have to copy over the first set of
// computations
void SpkOrrery::set_orrery_with_vel_to(double s, double delta_s)
{
    OrreryBodyVec bodies_plus_delta = get_orrery_at(s + delta_s);
    set_orrery_to(s);

    for (size_t i = 0; i < bodies.size(); i++) {
        bodies[i].state.vel
            = (bodies_plus_delta[i].state.pos - bodies[i].state.pos) / delta_s;
    }
}
}<commit_msg>Add warning for missing bodies<commit_after>/*
This file is part of Groho, a simulator for inter-planetary travel and warfare.
Copyright (c) 2017-2018 by Kaushik Ghose. Some rights reserved, see LICENSE

Subclasses Orrery and incorporates code to read JPL/NASA SPK/DAF files.
One or more SPK files can be loaded into memory and body position computed
at given times.
*/

#include <unordered_set>

#define LOGURU_WITH_STREAMS 1
#include "loguru.hpp"

#include "solar_system.hpp"
#include "spkorrery.hpp"

namespace orrery {

EphemerisVec combine_ephemerides(
    const EphemerisVec& old_ephemera, const EphemerisVec& new_ephemera)
{
    EphemerisVec unsorted_ephemera;

    std::unordered_set<int> centers;

    for (auto e : old_ephemera) {
        unsorted_ephemera.push_back(e);
        centers.insert(e->target_code);
    }

    // Add if not duplicate
    for (auto e : new_ephemera) {
        if (centers.count(e->target_code) == 0) {
            unsorted_ephemera.push_back(e);
            centers.insert(e->target_code);
        } else {
            LOG_S(WARNING) << "Ignoring duplicate body (" << e->target_code
                           << ")";
        }
    }

    return unsorted_ephemera;
}

// Reorder the Ephemerides such that bodies serving as centers come before the
// target bodies.
// This is a multi-pass algorithm. We repeatedly sweep over the original list
// adding bodies to the sorted list as long as we have computed their center
EphemerisVec sort_ephemerides(const EphemerisVec& un_srt)
{
    EphemerisVec srt;

    std::unordered_set<int> centers = { 0 };

    while (srt.size() < un_srt.size()) {
        size_t centers_resolved_this_time = 0;
        for (size_t i = 0; i < un_srt.size(); i++) {
            if (centers.count(un_srt[i]->target_code))
                continue;
            if (centers.count(un_srt[i]->center_code)) {
                srt.push_back(un_srt[i]);
                centers.insert(un_srt[i]->target_code);
                centers_resolved_this_time++;
            }
        }
        if (centers_resolved_this_time == 0) {
            LOG_S(ERROR) << "Orrery has " << un_srt.size() - srt.size()
                         << " bodies with center(s) that do(es) not exist";
            break;
        }
    }

    return srt;
}

// Returns a vector v such that v[i] points to the ephemerides in srt that
// serves as the center for i. Undefined for i whose center is 0
std::vector<size_t> create_center_indexes(const EphemerisVec& srt)
{
    std::unordered_map<int, size_t> code2index;

    std::vector<size_t> ci(srt.size());

    for (size_t i = 0; i < srt.size(); i++) {
        code2index[srt[i]->target_code] = i;
    }

    for (size_t i = 0; i < srt.size(); i++) {
        if (srt[i]->center_code != 0) {
            ci[i] = code2index[srt[i]->center_code];
        }
    }

    return ci;
}

// For every body in the SPK file create a mirror OrreryBody to store the
// computed position information and some planetary constants. It is important
// to note that this list contains barycenters which are dynamical (virtual)
// points and not for display or gravitational computation.
OrreryBodyVec create_bodies(const EphemerisVec& ephemera)
{
    OrreryBodyVec bodies;
    for (auto e : ephemera) {
        OrreryBody ob;
        if (body_library.count(e->target_code)) {
            ob.property = body_library[e->target_code];
        } else {
            LOG_S(WARNING) << e->target_code
                           << " not found in solar system library";
        }
        bodies.push_back(ob);
    }
    return bodies;
}

SpkOrrery::SpkOrrery(std::set<std::string> fnames, double begin_s, double end_s)
    : begin_s(begin_s)
    , end_s(end_s)
    , Orrery()
{
    for (auto& orrery_name : fnames) {
        size_t body_count = ephemera.size();
        load_orrery_model(orrery_name, begin_s, end_s);
        LOG_S(INFO) << ephemera.size() - body_count << " bodies from "
                    << orrery_name;
    }
    LOG_S(INFO) << ephemera.size() << " bodies in Orrery";

    ephemera   = sort_ephemerides(ephemera);
    center_idx = create_center_indexes(ephemera);
    bodies     = create_bodies(ephemera);
}

bool SpkOrrery::load_orrery_model(
    std::string fname, double begin_s, double end_s)
{
    std::ifstream nasa_spk_file(fname, std::ios::binary);

    if (!nasa_spk_file) {
        LOG_S(ERROR) << "Could not open " << fname;
        ok = false;
        return false;
    }

    ephemera = combine_ephemerides(
        ephemera, load_spk(nasa_spk_file, begin_s, end_s));

    ok = true;
    return ok;
}

void set_pos(double s, const Ephemeris& eph, sim::Vector& pos)
{
    const auto& e = eph.evec[std::floor((s - eph.begin_s) / eph.interval_s)];

    pos.x = cheby_eval(e.t_mid, e.t_half, e.X, s);
    pos.y = cheby_eval(e.t_mid, e.t_half, e.Y, s);
    pos.z = cheby_eval(e.t_mid, e.t_half, e.Z, s);
}

// Fill out the (x, y, z) of each Orrery body
void SpkOrrery::set_orrery_to(double s)
{
    for (size_t i = 0; i < ephemera.size(); i++) {
        set_pos(s, *ephemera[i], bodies[i].state.pos);
        bodies[i].state.t = s;
    }

    for (size_t i = 0; i < ephemera.size(); i++) {
        if (ephemera[i]->center_code != 0) {
            bodies[i].state.pos += bodies[center_idx[i]].state.pos;
        }
    }
}

// Fill out the (x, y, z) of each Orrery body and return us an immutable
// vector containing this information.
const OrreryBodyVec& SpkOrrery::get_orrery_at(double s)
{
    set_orrery_to(s);
    return bodies;
}

// This is a little expensive because we have to copy over the first set of
// computations
void SpkOrrery::set_orrery_with_vel_to(double s, double delta_s)
{
    OrreryBodyVec bodies_plus_delta = get_orrery_at(s + delta_s);
    set_orrery_to(s);

    for (size_t i = 0; i < bodies.size(); i++) {
        bodies[i].state.vel
            = (bodies_plus_delta[i].state.pos - bodies[i].state.pos) / delta_s;
    }
}
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andrew Schultz
 *          Nathan Binkert
 */

/**
 * @file
 * Generic interface for platforms
 */

#ifndef __DEV_PLATFORM_HH__
#define __DEV_PLATFORM_HH__

#include <bitset>
#include <set>

#include "params/Platform.hh"
#include "sim/sim_object.hh"

class PciConfigAll;
class IntrControl;
class Terminal;
class Uart;
class System;

class Platform : public SimObject
{
  public:
    /** Pointer to the interrupt controller */
    IntrControl *intrctrl;

    /** Pointer to the system for info about the memory system. */
    System *system;

  public:
    typedef PlatformParams Params;
    Platform(const Params *p);
    virtual ~Platform();
    virtual void postConsoleInt() = 0;
    virtual void clearConsoleInt() = 0;
    virtual void postPciInt(int line);
    virtual void clearPciInt(int line);
    virtual Addr pciToDma(Addr pciAddr) const;
    virtual Addr calcPciConfigAddr(int bus, int dev, int func) = 0;
    virtual Addr calcPciIOAddr(Addr addr) = 0;
    virtual Addr calcPciMemAddr(Addr addr) = 0;
    virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
            uint8_t intr);

  private:
    std::bitset<256> intLines;
    std::set<uint32_t> pciDevices;

};

#endif // __DEV_PLATFORM_HH__
<commit_msg>dev: Remove unused system pointer in the Platform base class<commit_after>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andrew Schultz
 *          Nathan Binkert
 */

/**
 * @file
 * Generic interface for platforms
 */

#ifndef __DEV_PLATFORM_HH__
#define __DEV_PLATFORM_HH__

#include <bitset>
#include <set>

#include "params/Platform.hh"
#include "sim/sim_object.hh"

class PciConfigAll;
class IntrControl;
class Terminal;
class Uart;
class System;

class Platform : public SimObject
{
  public:
    /** Pointer to the interrupt controller */
    IntrControl *intrctrl;

  public:
    typedef PlatformParams Params;
    Platform(const Params *p);
    virtual ~Platform();
    virtual void postConsoleInt() = 0;
    virtual void clearConsoleInt() = 0;
    virtual void postPciInt(int line);
    virtual void clearPciInt(int line);
    virtual Addr pciToDma(Addr pciAddr) const;
    virtual Addr calcPciConfigAddr(int bus, int dev, int func) = 0;
    virtual Addr calcPciIOAddr(Addr addr) = 0;
    virtual Addr calcPciMemAddr(Addr addr) = 0;
    virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
            uint8_t intr);

  private:
    std::bitset<256> intLines;
    std::set<uint32_t> pciDevices;

};

#endif // __DEV_PLATFORM_HH__
<|endoftext|>