<commit_before>
/**
 * Copyright (C) 2016, Canonical Ltd.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

// #define BUILD_FOR_BUNDLE

#include <QCommandLineParser>
#include <QDirIterator>
#include <QFile>
#include <QFontDatabase>
#include <QGuiApplication>
#include <QProcess>
#include <QQuickView>
#include <QStandardPaths>
#include <QTimer>
#include <QUrl>

#include "attachedproperties.h"
#include "reactitem.h"
#include "rootview.h"
#include "utilities.h"

#include "exceptionglobalhandler.h"

#ifdef BUILD_FOR_BUNDLE
#include <QMutexLocker>

QStringList consoleOutputStrings;
bool ubuntuServerStarted = false;
QMutex consoleOutputMutex;
QProcess *g_ubuntuServerProcess = nullptr;
#endif

const int MAIN_WINDOW_WIDTH = 1024;
const int MAIN_WINDOW_HEIGHT = 768;
const QString CRASH_REPORT_EXECUTABLE = QStringLiteral("reportApp");
const QString CRASH_REPORT_EXECUTABLE_RELATIVE_PATH =
    QStringLiteral("/../reportApp");

// TODO: some way to change while running
class ReactNativeProperties : public QObject {
  Q_OBJECT
  Q_PROPERTY(bool liveReload READ liveReload WRITE setLiveReload NOTIFY
                 liveReloadChanged)
  Q_PROPERTY(QUrl codeLocation READ codeLocation WRITE setCodeLocation NOTIFY
                 codeLocationChanged)
  Q_PROPERTY(QString pluginsPath READ pluginsPath WRITE setPluginsPath NOTIFY
                 pluginsPathChanged)
  Q_PROPERTY(
      QString executor READ executor WRITE setExecutor NOTIFY executorChanged)
public:
  ReactNativeProperties(QObject *parent = 0) : QObject(parent) {
    m_codeLocation = m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort);
  }
  bool liveReload() const { return m_liveReload; }
  void setLiveReload(bool liveReload) {
    if (m_liveReload == liveReload)
      return;
    m_liveReload = liveReload;
    Q_EMIT liveReloadChanged();
  }
  QUrl codeLocation() const { return m_codeLocation; }
  void setCodeLocation(const QUrl &codeLocation) {
    if (m_codeLocation == codeLocation)
      return;
    m_codeLocation = codeLocation;
    Q_EMIT codeLocationChanged();
  }
  QString pluginsPath() const { return m_pluginsPath; }
  void setPluginsPath(const QString &pluginsPath) {
    if (m_pluginsPath == pluginsPath)
      return;
    m_pluginsPath = pluginsPath;
    Q_EMIT pluginsPathChanged();
  }
  QString executor() const { return m_executor; }
  void setExecutor(const QString &executor) {
    if (m_executor == executor)
      return;
    m_executor = executor;
    Q_EMIT executorChanged();
  }
  QString packagerHost() const { return m_packagerHost; }
  void setPackagerHost(const QString &packagerHost) {
    if (m_packagerHost == packagerHost)
      return;
    m_packagerHost = packagerHost;
    setCodeLocation(m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort));
  }
  QString packagerPort() const { return m_packagerPort; }
  void setPackagerPort(const QString &packagerPort) {
    if (m_packagerPort == packagerPort)
      return;
    m_packagerPort = packagerPort;
    setCodeLocation(m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort));
  }
  void setLocalSource(const QString &source) {
    if (m_localSource == source)
      return;

    // overrides packager*
    if (source.startsWith("file:")) {
      setCodeLocation(source);
    } else {
      QFileInfo fi(source);
      if (!fi.exists()) {
        qWarning() << "Attempt to set non-existent local source file";
        return;
      }
      setCodeLocation(QUrl::fromLocalFile(fi.absoluteFilePath()));
      setLiveReload(false);
    }
  }
Q_SIGNALS:
  void liveReloadChanged();
  void codeLocationChanged();
  void pluginsPathChanged();
  void executorChanged();

private:
  bool m_liveReload = false;
  QString m_packagerHost = "localhost";
  QString m_packagerPort = "8081";
  QString m_localSource;
  QString m_packagerTemplate =
      "http://%1:%2/index.desktop.bundle?platform=desktop&dev=true";
  QUrl m_codeLocation;
  QString m_pluginsPath;
#ifdef BUILD_FOR_BUNDLE
  QString m_executor = "RemoteServerConnection";
#else
  QString m_executor = "LocalServerConnection";
#endif
};

#ifdef BUILD_FOR_BUNDLE
void runUbuntuServer();
void saveMessage(QtMsgType type, const QMessageLogContext &context,
                 const QString &msg);

void writeLogsToFile();
#endif

void loadFontsFromResources() {

  QDirIterator it(":", QDirIterator::Subdirectories);
  while (it.hasNext()) {
    QString resourceFile = it.next();
    if (resourceFile.endsWith(".otf", Qt::CaseInsensitive) ||
        resourceFile.endsWith(".ttf", Qt::CaseInsensitive)) {
      QFontDatabase::addApplicationFont(resourceFile);
    }
  }
}

void exceptionPostHandledCallback() {
#ifdef BUILD_FOR_BUNDLE
  if (g_ubuntuServerProcess) {
    g_ubuntuServerProcess->kill();
  }
#endif
}

QString getDataStoragePath() {
  QString dataStoragePath;
#ifdef BUILD_FOR_BUNDLE
  dataStoragePath =
      QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
  QDir dir(dataStoragePath);
  if (!dir.exists()) {
    dir.mkpath(".");
  }
#endif
  return dataStoragePath;
}

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

  QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
  QGuiApplication app(argc, argv);

  app.setApplicationName("Status");

  QString appPath = QCoreApplication::applicationDirPath();
#ifndef BUILD_FOR_BUNDLE
  appPath.append(CRASH_REPORT_EXECUTABLE_RELATIVE_PATH);
#endif

  ExceptionGlobalHandler exceptionHandler(
      appPath + QDir::separator() + CRASH_REPORT_EXECUTABLE,
      exceptionPostHandledCallback, getDataStoragePath());

  Q_INIT_RESOURCE(react_resources);

  loadFontsFromResources();

#ifdef BUILD_FOR_BUNDLE
  qInstallMessageHandler(saveMessage);
  runUbuntuServer();
#endif

  QQuickView view;
  ReactNativeProperties *rnp = new ReactNativeProperties(&view);
#ifdef BUILD_FOR_BUNDLE
  rnp->setCodeLocation("file:" + QGuiApplication::applicationDirPath() +
                       "/assets");
#endif

  utilities::registerReactTypes();

  QCommandLineParser p;
  p.setApplicationDescription("React Native host application");
  p.addHelpOption();
  p.addOptions({
      {{"R", "live-reload"}, "Enable live reload."},
      {{"H", "host"}, "Set packager host address.", rnp->packagerHost()},
      {{"P", "port"}, "Set packager port number.", rnp->packagerPort()},
      {{"L", "local"}, "Set path to the local packaged source", "not set"},
      {{"M", "plugins-path"}, "Set path to node modules", "./plugins"},
      {{"E", "executor"}, "Set Javascript executor", rnp->executor()},
  });
  p.process(app);
  rnp->setLiveReload(p.isSet("live-reload"));
  if (p.isSet("host"))
    rnp->setPackagerHost(p.value("host"));
  if (p.isSet("port"))
    rnp->setPackagerPort(p.value("port"));
  if (p.isSet("local"))
    rnp->setLocalSource(p.value("local"));
  if (p.isSet("plugins-path"))
    rnp->setPluginsPath(p.value("plugins-path"));
  if (p.isSet("executor"))
    rnp->setExecutor(p.value("executor"));

  view.rootContext()->setContextProperty("ReactNativeProperties", rnp);
  view.setSource(QUrl("qrc:///main.qml"));
  view.setResizeMode(QQuickView::SizeRootObjectToView);
  view.resize(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT);
  view.show();

#ifdef BUILD_FOR_BUNDLE
  QTimer t;
  t.setInterval(500);
  QObject::connect(&t, &QTimer::timeout, [=]() { writeLogsToFile(); });
  t.start();
#endif

  return app.exec();
}

#ifdef BUILD_FOR_BUNDLE

void writeLogsToFile() {
  QMutexLocker locker(&consoleOutputMutex);
  QFile logFile(getDataStoragePath() + "/Status.log");
  if (logFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
    for (QString message : consoleOutputStrings) {
      logFile.write(message.toStdString().c_str());
    }
    consoleOutputStrings.clear();

    logFile.flush();
    logFile.close();
  }
}

void runUbuntuServer() {
  g_ubuntuServerProcess = new QProcess();
  g_ubuntuServerProcess->setWorkingDirectory(getDataStoragePath());
  g_ubuntuServerProcess->setProgram(QGuiApplication::applicationDirPath() +
                                    "/ubuntu-server");
  QObject::connect(g_ubuntuServerProcess, &QProcess::errorOccurred,
                   [=](QProcess::ProcessError) {
                     qDebug() << "process name: "
                              << g_ubuntuServerProcess->program();
                     qDebug() << "process error: "
                              << g_ubuntuServerProcess->errorString();
                   });

  QObject::connect(
      g_ubuntuServerProcess, &QProcess::readyReadStandardOutput, [=] {
        qDebug() << "ubuntu-server std: "
                 << g_ubuntuServerProcess->readAllStandardOutput().trimmed();
      });
  QObject::connect(
      g_ubuntuServerProcess, &QProcess::readyReadStandardError, [=] {
        QString output =
            g_ubuntuServerProcess->readAllStandardError().trimmed();
        qDebug() << "ubuntu-server err: " << output;
        if (output.contains("Server starting")) {
          ubuntuServerStarted = true;
        }
      });

  QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit,
                   [=]() {
                     qDebug() << "Kill ubuntu server";
                     g_ubuntuServerProcess->kill();
                   });

  qDebug() << "starting ubuntu server...";
  g_ubuntuServerProcess->start();
  qDebug() << "wait for started...";

  while (!ubuntuServerStarted) {
    QGuiApplication::processEvents();
  }

  qDebug() << "waiting finished";
}

void appendConsoleString(const QString &msg) {
  QMutexLocker locker(&consoleOutputMutex);
  consoleOutputStrings << msg;
}

void saveMessage(QtMsgType type, const QMessageLogContext &context,
                 const QString &msg) {

  QByteArray localMsg = msg.toLocal8Bit();
  QString message = localMsg + "\n";
  QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
  QString typeStr;

  switch (type) {
  case QtDebugMsg:
    typeStr = "D";
    break;
  case QtInfoMsg:
    typeStr = "I";
    break;
  case QtWarningMsg:
    typeStr = "W";
    break;
  case QtCriticalMsg:
    typeStr = "C";
    break;
  case QtFatalMsg:
    typeStr = "F";
  }
  appendConsoleString(QString("%1 - %2 - %3").arg(timestamp, typeStr, message));
  if (type == QtFatalMsg) {
    writeLogsToFile();
    abort();
  }
}
#endif

#include "main.moc"
<commit_msg>Non-bundle build logging to file support; Custom log path with STATUS_LOG_PATH env var.<commit_after>
/**
 * Copyright (C) 2016, Canonical Ltd.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

// #define BUILD_FOR_BUNDLE

#include <QCommandLineParser>
#include <QDirIterator>
#include <QFile>
#include <QFontDatabase>
#include <QGuiApplication>
#include <QMutexLocker>
#include <QProcess>
#include <QQuickView>
#include <QStandardPaths>
#include <QTimer>
#include <QUrl>

#include "attachedproperties.h"
#include "reactitem.h"
#include "rootview.h"
#include "utilities.h"

#include "exceptionglobalhandler.h"

static QStringList consoleOutputStrings;
static QMutex consoleOutputMutex;

#ifdef BUILD_FOR_BUNDLE
bool ubuntuServerStarted = false;
QProcess *g_ubuntuServerProcess = nullptr;
#endif

const int MAIN_WINDOW_WIDTH = 1024;
const int MAIN_WINDOW_HEIGHT = 768;
const QString CRASH_REPORT_EXECUTABLE = QStringLiteral("reportApp");
const QString CRASH_REPORT_EXECUTABLE_RELATIVE_PATH =
    QStringLiteral("/../reportApp");

const char *ENABLE_LOG_FILE_ENV_VAR_NAME = "STATUS_LOG_FILE_ENABLED";
const char *LOG_FILE_PATH_ENV_VAR_NAME = "STATUS_LOG_PATH";

// TODO: some way to change while running
class ReactNativeProperties : public QObject {
  Q_OBJECT
  Q_PROPERTY(bool liveReload READ liveReload WRITE setLiveReload NOTIFY
                 liveReloadChanged)
  Q_PROPERTY(QUrl codeLocation READ codeLocation WRITE setCodeLocation NOTIFY
                 codeLocationChanged)
  Q_PROPERTY(QString pluginsPath READ pluginsPath WRITE setPluginsPath NOTIFY
                 pluginsPathChanged)
  Q_PROPERTY(
      QString executor READ executor WRITE setExecutor NOTIFY executorChanged)
public:
  ReactNativeProperties(QObject *parent = nullptr) : QObject(parent) {
    m_codeLocation = m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort);
  }
  bool liveReload() const { return m_liveReload; }
  void setLiveReload(bool liveReload) {
    if (m_liveReload == liveReload)
      return;
    m_liveReload = liveReload;
    Q_EMIT liveReloadChanged();
  }
  QUrl codeLocation() const { return m_codeLocation; }
  void setCodeLocation(const QUrl &codeLocation) {
    if (m_codeLocation == codeLocation)
      return;
    m_codeLocation = codeLocation;
    Q_EMIT codeLocationChanged();
  }
  QString pluginsPath() const { return m_pluginsPath; }
  void setPluginsPath(const QString &pluginsPath) {
    if (m_pluginsPath == pluginsPath)
      return;
    m_pluginsPath = pluginsPath;
    Q_EMIT pluginsPathChanged();
  }
  QString executor() const { return m_executor; }
  void setExecutor(const QString &executor) {
    if (m_executor == executor)
      return;
    m_executor = executor;
    Q_EMIT executorChanged();
  }
  QString packagerHost() const { return m_packagerHost; }
  void setPackagerHost(const QString &packagerHost) {
    if (m_packagerHost == packagerHost)
      return;
    m_packagerHost = packagerHost;
    setCodeLocation(m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort));
  }
  QString packagerPort() const { return m_packagerPort; }
  void setPackagerPort(const QString &packagerPort) {
    if (m_packagerPort == packagerPort)
      return;
    m_packagerPort = packagerPort;
    setCodeLocation(m_packagerTemplate.arg(m_packagerHost).arg(m_packagerPort));
  }
  void setLocalSource(const QString &source) {
    if (m_localSource == source)
      return;

    // overrides packager*
    if (source.startsWith("file:")) {
      setCodeLocation(source);
    } else {
      QFileInfo fi(source);
      if (!fi.exists()) {
        qWarning() << "Attempt to set non-existent local source file";
        return;
      }
      setCodeLocation(QUrl::fromLocalFile(fi.absoluteFilePath()));
      setLiveReload(false);
    }
  }
Q_SIGNALS:
  void liveReloadChanged();
  void codeLocationChanged();
  void pluginsPathChanged();
  void executorChanged();

private:
  bool m_liveReload = false;
  QString m_packagerHost = "localhost";
  QString m_packagerPort = "8081";
  QString m_localSource;
  QString m_packagerTemplate =
      "http://%1:%2/index.desktop.bundle?platform=desktop&dev=true";
  QUrl m_codeLocation;
  QString m_pluginsPath;
#ifdef BUILD_FOR_BUNDLE
  QString m_executor = "RemoteServerConnection";
#else
  QString m_executor = "LocalServerConnection";
#endif
};

void saveMessage(QtMsgType type, const QMessageLogContext &context,
                 const QString &msg);
void writeLogsToFile();

#ifdef BUILD_FOR_BUNDLE

void runUbuntuServer();

#endif

void loadFontsFromResources() {

  QDirIterator it(":", QDirIterator::Subdirectories);
  while (it.hasNext()) {
    QString resourceFile = it.next();
    if (resourceFile.endsWith(".otf", Qt::CaseInsensitive) ||
        resourceFile.endsWith(".ttf", Qt::CaseInsensitive)) {
      QFontDatabase::addApplicationFont(resourceFile);
    }
  }
}

void exceptionPostHandledCallback() {
#ifdef BUILD_FOR_BUNDLE
  if (g_ubuntuServerProcess) {
    g_ubuntuServerProcess->kill();
  }
#endif
}

bool redirectLogIntoFile() {
#ifdef BUILD_FOR_BUNDLE
  return true;
#else
  return qEnvironmentVariable(ENABLE_LOG_FILE_ENV_VAR_NAME, "") ==
         QStringLiteral("1");
#endif
}

QString getDataStoragePath() {
  QString dataStoragePath =
      QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
  QDir dir(dataStoragePath);
  if (!dir.exists()) {
    dir.mkpath(".");
  }
  return dataStoragePath;
}

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

  QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
  QGuiApplication app(argc, argv);

  QCoreApplication::setApplicationName("Status");

  QString appPath = QCoreApplication::applicationDirPath();
  QString dataStoragePath = getDataStoragePath();
#ifndef BUILD_FOR_BUNDLE
  appPath.append(CRASH_REPORT_EXECUTABLE_RELATIVE_PATH);
  dataStoragePath = "";
#endif

  ExceptionGlobalHandler exceptionHandler(
      appPath + QDir::separator() + CRASH_REPORT_EXECUTABLE,
      exceptionPostHandledCallback, dataStoragePath);

  Q_INIT_RESOURCE(react_resources);

  loadFontsFromResources();

  if (redirectLogIntoFile()) {
    qInstallMessageHandler(saveMessage);
  }

#ifdef BUILD_FOR_BUNDLE
  runUbuntuServer();
#endif

  QQuickView view;
  ReactNativeProperties *rnp = new ReactNativeProperties(&view);
#ifdef BUILD_FOR_BUNDLE
  rnp->setCodeLocation("file:" + QGuiApplication::applicationDirPath() +
                       "/assets");
#endif

  utilities::registerReactTypes();

  QCommandLineParser p;
  p.setApplicationDescription("React Native host application");
  p.addHelpOption();
  p.addOptions({
      {{"R", "live-reload"}, "Enable live reload."},
      {{"H", "host"}, "Set packager host address.", rnp->packagerHost()},
      {{"P", "port"}, "Set packager port number.", rnp->packagerPort()},
      {{"L", "local"}, "Set path to the local packaged source", "not set"},
      {{"M", "plugins-path"}, "Set path to node modules", "./plugins"},
      {{"E", "executor"}, "Set Javascript executor", rnp->executor()},
  });
  p.process(app);
  rnp->setLiveReload(p.isSet("live-reload"));
  if (p.isSet("host"))
    rnp->setPackagerHost(p.value("host"));
  if (p.isSet("port"))
    rnp->setPackagerPort(p.value("port"));
  if (p.isSet("local"))
    rnp->setLocalSource(p.value("local"));
  if (p.isSet("plugins-path"))
    rnp->setPluginsPath(p.value("plugins-path"));
  if (p.isSet("executor"))
    rnp->setExecutor(p.value("executor"));

  view.rootContext()->setContextProperty("ReactNativeProperties", rnp);
  view.setSource(QUrl("qrc:///main.qml"));
  view.setResizeMode(QQuickView::SizeRootObjectToView);
  view.resize(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT);
  view.show();

  QTimer flushLogsToFileTimer;
  if (redirectLogIntoFile()) {
    flushLogsToFileTimer.setInterval(500);
    QObject::connect(&flushLogsToFileTimer, &QTimer::timeout,
                     [=]() { writeLogsToFile(); });
    flushLogsToFileTimer.start();
  }

  return app.exec();
}

QString getLogFilePath() {
  QString logFilePath;
#ifdef BUILD_FOR_BUNDLE
  logFilePath = getDataStoragePath() + "/Status.log";
#else
  logFilePath = qEnvironmentVariable(LOG_FILE_PATH_ENV_VAR_NAME, "");
  if (logFilePath.isEmpty()) {
    logFilePath = getDataStoragePath() + "/StatusDev.log";
  }
#endif
  return logFilePath;
}

void writeLogsToFile() {
  QMutexLocker locker(&consoleOutputMutex);
  QFile logFile(getLogFilePath());
  if (logFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
    for (QString message : consoleOutputStrings) {
      logFile.write(message.toStdString().c_str());
    }
    consoleOutputStrings.clear();

    logFile.flush();
    logFile.close();
  }
}

#ifdef BUILD_FOR_BUNDLE
void runUbuntuServer() {
  g_ubuntuServerProcess = new QProcess();
  g_ubuntuServerProcess->setWorkingDirectory(getDataStoragePath());
  g_ubuntuServerProcess->setProgram(QGuiApplication::applicationDirPath() +
                                    "/ubuntu-server");
  QObject::connect(g_ubuntuServerProcess, &QProcess::errorOccurred,
                   [=](QProcess::ProcessError) {
                     qDebug() << "process name: "
                              << g_ubuntuServerProcess->program();
                     qDebug() << "process error: "
                              << g_ubuntuServerProcess->errorString();
                   });

  QObject::connect(
      g_ubuntuServerProcess, &QProcess::readyReadStandardOutput, [=] {
        qDebug() << "ubuntu-server std: "
                 << g_ubuntuServerProcess->readAllStandardOutput().trimmed();
      });
  QObject::connect(
      g_ubuntuServerProcess, &QProcess::readyReadStandardError, [=] {
        QString output =
            g_ubuntuServerProcess->readAllStandardError().trimmed();
        qDebug() << "ubuntu-server err: " << output;
        if (output.contains("Server starting")) {
          ubuntuServerStarted = true;
        }
      });

  QObject::connect(QGuiApplication::instance(), &QCoreApplication::aboutToQuit,
                   [=]() {
                     qDebug() << "Kill ubuntu server";
                     g_ubuntuServerProcess->kill();
                   });

  qDebug() << "starting ubuntu server...";
  g_ubuntuServerProcess->start();
  qDebug() << "wait for started...";

  while (!ubuntuServerStarted) {
    QGuiApplication::processEvents();
  }

  qDebug() << "waiting finished";
}
#endif

void appendConsoleString(const QString &msg) {
  QMutexLocker locker(&consoleOutputMutex);
  consoleOutputStrings << msg;
}

void saveMessage(QtMsgType type, const QMessageLogContext &context,
                 const QString &msg) {
  Q_UNUSED(context);
  QByteArray localMsg = msg.toLocal8Bit();
  QString message = localMsg + "\n";
  QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
  QString typeStr;

  switch (type) {
  case QtDebugMsg:
    typeStr = "D";
    break;
  case QtInfoMsg:
    typeStr = "I";
    break;
  case QtWarningMsg:
    typeStr = "W";
    break;
  case QtCriticalMsg:
    typeStr = "C";
    break;
  case QtFatalMsg:
    typeStr = "F";
  }
  appendConsoleString(QString("%1 - %2 - %3").arg(timestamp, typeStr, message));
  if (type == QtFatalMsg) {
    writeLogsToFile();
    abort();
  }
}

#include "main.moc"
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stdlib.h>
#include <unistd.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/io/mmappedfile.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-mdb/MDB.h"
#include "cm-common/CustomerNamespace.h"
#include "cm-logjoin/LogJoin.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "input",
      fnord::cli::FlagParser::T_STRING,
      true,
      "i",
      NULL,
      "input file",
      "<filename>");

  flags.defineFlag(
      "separator",
      fnord::cli::FlagParser::T_STRING,
      false,
      "s",
      "\n",
      "separator",
      "<char>");

  flags.defineFlag(
      "concurrency",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      "c",
      "10",
      "concurrency",
      "<num>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "CRITICAL",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* args */
  auto concurrency = flags.getInt("concurrency");
  auto inputfile = flags.getString("input");
  auto separator_str = flags.getString("separator");
  if (separator_str.length() != 1) {
    // print usage
    return 1;
  }

  char separator = separator_str[0];

  auto uris = flags.getArgv();
  if (uris.size() == 0) {
    // print usage...
    return 1;
  }

  /* start event loop */
  fnord::thread::EventLoop ev;

  auto evloop_thread = std::thread([&ev] {
    ev.run();
  });

  /* set up rpc client */
  HTTPRPCClient rpc_client(&ev);

  /* set up feedwriter */
  feeds::RemoteFeedWriter feed_writer(&rpc_client);

  for (const auto& uri_raw : uris) {
    URI uri(uri_raw);
    const auto& params = uri.queryParams();

    std::string feed;
    if (!URI::getParam(params, "feed", &feed)) {
      RAISEF(
          kIllegalArgumentError,
          "feed url missing ?feed query param: $0",
          uri_raw);
    }

    auto rpc_url = uri_raw.substr(0, uri_raw.find("?"));
    feed_writer.addTargetFeed(rpc_url, feed, concurrency);
  }

  /* mmap input file */
  io::MmappedFile mmap(File::openFile(inputfile, File::O_READ));
  auto begin = (char *) mmap.begin();
  auto cur = begin;
  auto end = (char *) mmap.end();
  auto last = cur;
  int total_entries = 0;
  int total_bytes = 0;
  auto start_time = WallClock::now().unixMicros();
  auto last_status_line = start_time;

  /* status line */
  auto status_line = [
      begin,
      end,
      &cur,
      &total_bytes,
      &total_entries,
      &start_time,
      &last_status_line,
      &feed_writer] {
    auto now = WallClock::now().unixMicros();
    if (now - last_status_line < 10000) {
      return;
    }

    last_status_line = now;
    auto runtime = (now - start_time) / 1000000;
    int percent = ((double) (cur - begin) / (double) (end - begin)) * 100;
    int bandwidth = total_bytes / (double) (runtime + 1);
    auto queuelen = feed_writer.queueLength();

    auto str = StringUtil::format(
        "\r[$0%] uploading: entries=$1 bytes=$2B time=$3s bw=$4B/s queue=$5" \
        "          ",
        percent,
        total_entries,
        total_bytes,
        runtime,
        bandwidth,
        queuelen);

    write(0, str.c_str(), str.length());
    fflush(0);
  };

  /* upload entries */
  for (; cur != end; ++cur) {
    status_line();

    if (*cur != separator) {
      continue;
    }

    if (cur > last + 1) {
      while (feed_writer.queueLength() >= feed_writer.maxQueueLength() - 1) {
        status_line();
        usleep(1000);
      }

      feed_writer.appendEntry(String(last, cur - last));
      total_bytes += cur - last;
      ++total_entries;
    }

    last = cur + 1;
  }

  while (feed_writer.queueLength() > 0) {
    status_line();
    usleep(1000);
  }

  status_line();
  write(0, "\n", 1);
  fflush(0);

  ev.shutdown();
  evloop_thread.join();

  return 0;
}

<commit_msg>fix int overflows<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stdlib.h>
#include <unistd.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/io/mmappedfile.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-mdb/MDB.h"
#include "cm-common/CustomerNamespace.h"
#include "cm-logjoin/LogJoin.h"

using namespace fnord;

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "input",
      fnord::cli::FlagParser::T_STRING,
      true,
      "i",
      NULL,
      "input file",
      "<filename>");

  flags.defineFlag(
      "separator",
      fnord::cli::FlagParser::T_STRING,
      false,
      "s",
      "\n",
      "separator",
      "<char>");

  flags.defineFlag(
      "concurrency",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      "c",
      "10",
      "concurrency",
      "<num>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "CRITICAL",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  /* args */
  auto concurrency = flags.getInt("concurrency");
  auto inputfile = flags.getString("input");
  auto separator_str = flags.getString("separator");
  if (separator_str.length() != 1) {
    // print usage
    return 1;
  }

  char separator = separator_str[0];

  auto uris = flags.getArgv();
  if (uris.size() == 0) {
    // print usage...
    return 1;
  }

  /* start event loop */
  fnord::thread::EventLoop ev;

  auto evloop_thread = std::thread([&ev] {
    ev.run();
  });

  /* set up rpc client */
  HTTPRPCClient rpc_client(&ev);

  /* set up feedwriter */
  feeds::RemoteFeedWriter feed_writer(&rpc_client);

  for (const auto& uri_raw : uris) {
    URI uri(uri_raw);
    const auto& params = uri.queryParams();

    std::string feed;
    if (!URI::getParam(params, "feed", &feed)) {
      RAISEF(
          kIllegalArgumentError,
          "feed url missing ?feed query param: $0",
          uri_raw);
    }

    auto rpc_url = uri_raw.substr(0, uri_raw.find("?"));
    feed_writer.addTargetFeed(rpc_url, feed, concurrency);
  }

  /* mmap input file */
  io::MmappedFile mmap(File::openFile(inputfile, File::O_READ));
  auto begin = (char *) mmap.begin();
  auto cur = begin;
  auto end = (char *) mmap.end();
  auto last = cur;
  uint64_t total_entries = 0;
  uint64_t total_bytes = 0;
  auto start_time = WallClock::now().unixMicros();
  auto last_status_line = start_time;

  /* status line */
  auto status_line = [
      begin,
      end,
      &cur,
      &total_bytes,
      &total_entries,
      &start_time,
      &last_status_line,
      &feed_writer] {
    auto now = WallClock::now().unixMicros();
    if (now - last_status_line < 10000) {
      return;
    }

    last_status_line = now;
    auto runtime = (now - start_time) / 1000000;
    int percent = ((double) (cur - begin) / (double) (end - begin)) * 100;
    uint64_t bandwidth = total_bytes / (runtime + 1);
    auto queuelen = feed_writer.queueLength();

    auto str = StringUtil::format(
        "\r[$0%] uploading: entries=$1 bytes=$2B time=$3s bw=$4B/s queue=$5" \
        "          ",
        percent,
        total_entries,
        total_bytes,
        runtime,
        bandwidth,
        queuelen);

    write(0, str.c_str(), str.length());
    fflush(0);
  };

  /* upload entries */
  for (; cur != end; ++cur) {
    status_line();

    if (*cur != separator) {
      continue;
    }

    if (cur > last + 1) {
      while (feed_writer.queueLength() >= feed_writer.maxQueueLength() - 1) {
        status_line();
        usleep(1000);
      }

      feed_writer.appendEntry(String(last, cur - last));
      total_bytes += cur - last;
      ++total_entries;
    }

    last = cur + 1;
  }

  while (feed_writer.queueLength() > 0) {
    status_line();
    usleep(1000);
  }

  status_line();
  write(0, "\n", 1);
  fflush(0);

  ev.shutdown();
  evloop_thread.join();

  return 0;
}

<|endoftext|>


<commit_before>#include "rosplan_interface_mapping/RPSimpleMapServer.h"

/* implementation of rosplan_interface_mapping::RPSimpleMapServer.h */
namespace KCL_rosplan {

	/* constructor */
	RPSimpleMapServer::RPSimpleMapServer(ros::NodeHandle &nh, std::string frame)
	 : message_store(nh), fixed_frame(frame) {

		// config
		std::string dataPath("common/");
		nh.param("data_path", data_path, dataPath);

		// knowledge interface
		update_knowledge_client = nh.serviceClient<rosplan_knowledge_msgs::KnowledgeUpdateService>("/kcl_rosplan/update_knowledge_base");

		// visualisation
		waypoints_pub = nh.advertise<visualization_msgs::MarkerArray>("/kcl_rosplan/viz/waypoints", 10, true);
	}

	/*-----------*/
	/* build PRM */
	/*-----------*/

	/**
	 * Generates waypoints and stores them in the knowledge base and scene database
	 */
	bool RPSimpleMapServer::generateRoadmap(rosplan_knowledge_msgs::CreatePRM::Request &req, rosplan_knowledge_msgs::CreatePRM::Response &res) {

		ros::NodeHandle nh("~");

		// clear previous roadmap from knowledge base
		ROS_INFO("KCL: (RPSimpleMapServer) Cleaning old roadmap");
		rosplan_knowledge_msgs::KnowledgeUpdateService updateSrv;
		updateSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::REMOVE_KNOWLEDGE;
		updateSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::INSTANCE;
		updateSrv.request.knowledge.instance_type = "waypoint";
		update_knowledge_client.call(updateSrv);

		// clear previous roadmap from scene database
		for (std::map<std::string,Waypoint*>::iterator wit=waypoints.begin(); wit!=waypoints.end(); ++wit) {
			message_store.deleteID(db_name_map[wit->first]);
		}
		db_name_map.clear();

		// clear from visualization
		clearMarkerArrays(nh);

		// generate waypoints
		ROS_INFO("KCL: (RPSimpleMapServer) Generating roadmap");

		for (std::map<std::string, Waypoint*>::const_iterator ci = waypoints.begin(); ci != waypoints.end(); ++ci)
			delete (*ci).second;
		waypoints.clear();

		std::srand(std::time(0));
		for(int i=0; i<req.nr_waypoints; i++) {
			int x = (rand()%15);
			int y = (rand()%15);
			std::stringstream ss;
			ss << "wp" << i;
			Waypoint* wp = new Waypoint(ss.str(), x, y);
			waypoints[wp->wpID] = wp;
		}

		// publish visualization
		publishWaypointMarkerArray(nh);

		// add roadmap to knowledge base and scene database
		ROS_INFO("KCL: (RPSimpleMapServer) Adding knowledge");
		for (std::map<std::string,Waypoint*>::iterator wit=waypoints.begin(); wit!=waypoints.end(); ++wit) {

			// instance
			rosplan_knowledge_msgs::KnowledgeUpdateService updateSrv;
			updateSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
			updateSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::INSTANCE;
			updateSrv.request.knowledge.instance_type = "waypoint";
			updateSrv.request.knowledge.instance_name = wit->first;
			update_knowledge_client.call(updateSrv);

			res.waypoints.push_back(wit->first);

			// predicates
			for (std::vector<std::string>::iterator nit=wit->second->neighbours.begin(); nit!=wit->second->neighbours.end(); ++nit) {
				rosplan_knowledge_msgs::KnowledgeUpdateService updatePredSrv;
				updatePredSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
				updatePredSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::FACT;
				updatePredSrv.request.knowledge.attribute_name = "connected";
				diagnostic_msgs::KeyValue pairFrom;
				pairFrom.key = "from";
				pairFrom.value = wit->first;
				updatePredSrv.request.knowledge.values.push_back(pairFrom);
				diagnostic_msgs::KeyValue pairTo;
				pairTo.key = "to";
				pairTo.value = *nit;
				updatePredSrv.request.knowledge.values.push_back(pairTo);
				update_knowledge_client.call(updatePredSrv);
			}

			// functions
			for (std::vector<std::string>::iterator nit=wit->second->neighbours.begin(); nit!=wit->second->neighbours.end(); ++nit) {
				rosplan_knowledge_msgs::KnowledgeUpdateService updateFuncSrv;
				updateFuncSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
				updateFuncSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::FUNCTION;
				updateFuncSrv.request.knowledge.attribute_name = "distance";
				diagnostic_msgs::KeyValue pairFrom;
				pairFrom.key = "wp1";
				pairFrom.value = wit->first;
				updateFuncSrv.request.knowledge.values.push_back(pairFrom);
				diagnostic_msgs::KeyValue pairTo;
				pairTo.key = "wp2";
				pairTo.value = *nit;
				updateFuncSrv.request.knowledge.values.push_back(pairTo);
				double dist = sqrt(
						(wit->second->real_x - waypoints[*nit]->real_x)*(wit->second->real_x - waypoints[*nit]->real_x)
						+ (wit->second->real_y - waypoints[*nit]->real_y)*(wit->second->real_y - waypoints[*nit]->real_y));
				updateFuncSrv.request.knowledge.function_value = dist;
				update_knowledge_client.call(updateFuncSrv);
			}

			//data
			geometry_msgs::PoseStamped pose;
			pose.header.frame_id = fixed_frame;
			pose.pose.position.x = wit->second->real_x;
			pose.pose.position.y = wit->second->real_y;
			pose.pose.position.z = 0.0;
			pose.pose.orientation.x = 0.0;;
			pose.pose.orientation.y = 0.0;;
			pose.pose.orientation.z = 1.0;
			pose.pose.orientation.w = 1.0;
			std::string id(message_store.insertNamed(wit->first, pose));
			db_name_map[wit->first] = id;
		}

		ROS_INFO("KCL: (RPSimpleMapServer) Done");
		return true;
	}

	/**
	 * parses a pose with yaw from strings: "[f, f, f]"
	 */
	 void RPSimpleMapServer::parsePose(geometry_msgs::PoseStamped &pose, std::string line) {

		int curr,next;
		curr=line.find("[")+1;
		next=line.find(",",curr);

		pose.pose.position.x = (double)atof(line.substr(curr,next-curr).c_str());
		curr=next+1; next=line.find(",",curr);

		pose.pose.position.y = (double)atof(line.substr(curr,next-curr).c_str());
		curr=next+1; next=line.find(",",curr);

		pose.pose.orientation.x = 0.0;
		pose.pose.orientation.y = 0.0;
		pose.pose.orientation.w = (double)atof(line.substr(curr,next-curr).c_str());
		pose.pose.orientation.z = sqrt(1 - pose.pose.orientation.w * pose.pose.orientation.w);
	}

	bool RPSimpleMapServer::setupRoadmap(std::string filename) {

		ros::NodeHandle nh("~");

		// clear previous roadmap from knowledge base
		ROS_INFO("KCL: (RPSimpleMapServer) Loading roadmap from file");

		// load configuration file
		std::ifstream infile(filename.c_str());
		std::string line;
		int curr,next;
		while(std::getline(infile, line)) {
			// read waypoint
			curr=line.find("[");
			std::string name = line.substr(0,curr);

			// instance
			rosplan_knowledge_msgs::KnowledgeUpdateService updateSrv;
			updateSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
			updateSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::INSTANCE;
			updateSrv.request.knowledge.instance_type = "waypoint";
			updateSrv.request.knowledge.instance_name = name;
			update_knowledge_client.call(updateSrv);

			// data
			geometry_msgs::PoseStamped pose;
			pose.header.frame_id = fixed_frame;
			parsePose(pose, line);
			std::string id(message_store.insertNamed(name, pose));
			db_name_map[name] = id;

			// save here for viz
			Waypoint* wp = new Waypoint(name, pose.pose.position.x, pose.pose.position.y);
			waypoints[wp->wpID] = wp;
		}
		infile.close();

		// publish visualization
		publishWaypointMarkerArray(nh);
	}

} // close namespace

	/*-------------*/
	/* Main method */
	/*-------------*/

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

		// setup ros
		ros::init(argc, argv, "rosplan_simple_map_server");
		ros::NodeHandle nh("~");

		// params
		std::string filename("waypoints.txt");
		std::string fixed_frame("world");
		nh.param("/waypoint_file", filename, filename);
		nh.param("fixed_frame", fixed_frame, fixed_frame);

		// init
		KCL_rosplan::RPSimpleMapServer sms(nh, fixed_frame);
		ros::ServiceServer createPRMService = nh.advertiseService("/kcl_rosplan/roadmap_server/create_prm", &KCL_rosplan::RPSimpleMapServer::generateRoadmap, &sms);
		sms.setupRoadmap(filename);

		ROS_INFO("KCL: (RPSimpleMapServer) Ready to receive.");
		ros::spin();
		return 0;
	}
<commit_msg>Fix setting the quaternion.<commit_after>#include "rosplan_interface_mapping/RPSimpleMapServer.h"

#include <tf/transform_listener.h>

/* implementation of rosplan_interface_mapping::RPSimpleMapServer.h */
namespace KCL_rosplan {

	/* constructor */
	RPSimpleMapServer::RPSimpleMapServer(ros::NodeHandle &nh, std::string frame)
	 : message_store(nh), fixed_frame(frame) {

		// config
		std::string dataPath("common/");
		nh.param("data_path", data_path, dataPath);

		// knowledge interface
		update_knowledge_client = nh.serviceClient<rosplan_knowledge_msgs::KnowledgeUpdateService>("/kcl_rosplan/update_knowledge_base");

		// visualisation
		waypoints_pub = nh.advertise<visualization_msgs::MarkerArray>("/kcl_rosplan/viz/waypoints", 10, true);
	}

	/*-----------*/
	/* build PRM */
	/*-----------*/

	/**
	 * Generates waypoints and stores them in the knowledge base and scene database
	 */
	bool RPSimpleMapServer::generateRoadmap(rosplan_knowledge_msgs::CreatePRM::Request &req, rosplan_knowledge_msgs::CreatePRM::Response &res) {

		ros::NodeHandle nh("~");

		// clear previous roadmap from knowledge base
		ROS_INFO("KCL: (RPSimpleMapServer) Cleaning old roadmap");
		rosplan_knowledge_msgs::KnowledgeUpdateService updateSrv;
		updateSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::REMOVE_KNOWLEDGE;
		updateSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::INSTANCE;
		updateSrv.request.knowledge.instance_type = "waypoint";
		update_knowledge_client.call(updateSrv);

		// clear previous roadmap from scene database
		for (std::map<std::string,Waypoint*>::iterator wit=waypoints.begin(); wit!=waypoints.end(); ++wit) {
			message_store.deleteID(db_name_map[wit->first]);
		}
		db_name_map.clear();

		// clear from visualization
		clearMarkerArrays(nh);

		// generate waypoints
		ROS_INFO("KCL: (RPSimpleMapServer) Generating roadmap");

		for (std::map<std::string, Waypoint*>::const_iterator ci = waypoints.begin(); ci != waypoints.end(); ++ci)
			delete (*ci).second;
		waypoints.clear();

		std::srand(std::time(0));
		for(int i=0; i<req.nr_waypoints; i++) {
			int x = (rand()%15);
			int y = (rand()%15);
			std::stringstream ss;
			ss << "wp" << i;
			Waypoint* wp = new Waypoint(ss.str(), x, y);
			waypoints[wp->wpID] = wp;
		}

		// publish visualization
		publishWaypointMarkerArray(nh);

		// add roadmap to knowledge base and scene database
		ROS_INFO("KCL: (RPSimpleMapServer) Adding knowledge");
		for (std::map<std::string,Waypoint*>::iterator wit=waypoints.begin(); wit!=waypoints.end(); ++wit) {

			// instance
			rosplan_knowledge_msgs::KnowledgeUpdateService updateSrv;
			updateSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
			updateSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::INSTANCE;
			updateSrv.request.knowledge.instance_type = "waypoint";
			updateSrv.request.knowledge.instance_name = wit->first;
			update_knowledge_client.call(updateSrv);

			res.waypoints.push_back(wit->first);

			// predicates
			for (std::vector<std::string>::iterator nit=wit->second->neighbours.begin(); nit!=wit->second->neighbours.end(); ++nit) {
				rosplan_knowledge_msgs::KnowledgeUpdateService updatePredSrv;
				updatePredSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
				updatePredSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::FACT;
				updatePredSrv.request.knowledge.attribute_name = "connected";
				diagnostic_msgs::KeyValue pairFrom;
				pairFrom.key = "from";
				pairFrom.value = wit->first;
				updatePredSrv.request.knowledge.values.push_back(pairFrom);
				diagnostic_msgs::KeyValue pairTo;
				pairTo.key = "to";
				pairTo.value = *nit;
				updatePredSrv.request.knowledge.values.push_back(pairTo);
				update_knowledge_client.call(updatePredSrv);
			}

			// functions
			for (std::vector<std::string>::iterator nit=wit->second->neighbours.begin(); nit!=wit->second->neighbours.end(); ++nit) {
				rosplan_knowledge_msgs::KnowledgeUpdateService updateFuncSrv;
				updateFuncSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
				updateFuncSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::FUNCTION;
				updateFuncSrv.request.knowledge.attribute_name = "distance";
				diagnostic_msgs::KeyValue pairFrom;
				pairFrom.key = "wp1";
				pairFrom.value = wit->first;
				updateFuncSrv.request.knowledge.values.push_back(pairFrom);
				diagnostic_msgs::KeyValue pairTo;
				pairTo.key = "wp2";
				pairTo.value = *nit;
				updateFuncSrv.request.knowledge.values.push_back(pairTo);
				double dist = sqrt(
						(wit->second->real_x - waypoints[*nit]->real_x)*(wit->second->real_x - waypoints[*nit]->real_x)
						+ (wit->second->real_y - waypoints[*nit]->real_y)*(wit->second->real_y - waypoints[*nit]->real_y));
				updateFuncSrv.request.knowledge.function_value = dist;
				update_knowledge_client.call(updateFuncSrv);
			}

			//data
			geometry_msgs::PoseStamped pose;
			pose.header.frame_id = fixed_frame;
			pose.pose.position.x = wit->second->real_x;
			pose.pose.position.y = wit->second->real_y;
			pose.pose.position.z = 0.0;
			pose.pose.orientation.x = 0.0;;
			pose.pose.orientation.y = 0.0;;
			pose.pose.orientation.z = 1.0;
			pose.pose.orientation.w = 1.0;
			std::string id(message_store.insertNamed(wit->first, pose));
			db_name_map[wit->first] = id;
		}

		ROS_INFO("KCL: (RPSimpleMapServer) Done");
		return true;
	}

	/**
	 * parses a pose with yaw from strings: "[f, f, f]"
	 */
	 void RPSimpleMapServer::parsePose(geometry_msgs::PoseStamped &pose, std::string line) {

		int curr,next;
		curr=line.find("[")+1;
		next=line.find(",",curr);

		pose.pose.position.x = (double)atof(line.substr(curr,next-curr).c_str());
		curr=next+1; next=line.find(",",curr);

		pose.pose.position.y = (double)atof(line.substr(curr,next-curr).c_str());
		curr=next+1; next=line.find("]",curr);

		float theta = atof(line.substr(curr,next-curr).c_str());
		tf::Quaternion q;
		q.setEuler(theta, 0 ,0);

		pose.pose.orientation.x = q.x();
		pose.pose.orientation.y = q.z();
		pose.pose.orientation.w = q.w();
		pose.pose.orientation.z = q.y();
	}

	bool RPSimpleMapServer::setupRoadmap(std::string filename) {

		ros::NodeHandle nh("~");

		// clear previous roadmap from knowledge base
		ROS_INFO("KCL: (RPSimpleMapServer) Loading roadmap from file");

		// load configuration file
		std::ifstream infile(filename.c_str());
		std::string line;
		int curr,next;
		while(std::getline(infile, line)) {
			// read waypoint
			curr=line.find("[");
			std::string name = line.substr(0,curr);

			// instance
			rosplan_knowledge_msgs::KnowledgeUpdateService updateSrv;
			updateSrv.request.update_type = rosplan_knowledge_msgs::KnowledgeUpdateService::Request::ADD_KNOWLEDGE;
			updateSrv.request.knowledge.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::INSTANCE;
			updateSrv.request.knowledge.instance_type = "waypoint";
			updateSrv.request.knowledge.instance_name = name;
			update_knowledge_client.call(updateSrv);

			// data
			geometry_msgs::PoseStamped pose;
			pose.header.frame_id = fixed_frame;
			parsePose(pose, line);
			std::string id(message_store.insertNamed(name, pose));
			db_name_map[name] = id;

			// save here for viz
			Waypoint* wp = new Waypoint(name, pose.pose.position.x, pose.pose.position.y);
			waypoints[wp->wpID] = wp;
		}
		infile.close();

		// publish visualization
		publishWaypointMarkerArray(nh);
	}

} // close namespace

	/*-------------*/
	/* Main method */
	/*-------------*/

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

		// setup ros
		ros::init(argc, argv, "rosplan_simple_map_server");
		ros::NodeHandle nh("~");

		// params
		std::string filename("waypoints.txt");
		std::string fixed_frame("map");
		nh.param("/waypoint_file", filename, filename);
		nh.param("fixed_frame", fixed_frame, fixed_frame);

		// init
		KCL_rosplan::RPSimpleMapServer sms(nh, fixed_frame);
		ros::ServiceServer createPRMService = nh.advertiseService("/kcl_rosplan/roadmap_server/create_prm", &KCL_rosplan::RPSimpleMapServer::generateRoadmap, &sms);
		sms.setupRoadmap(filename);

		ROS_INFO("KCL: (RPSimpleMapServer) Ready to receive.");
		ros::spin();
		return 0;
	}
<|endoftext|>


<commit_before><commit_msg>got rid of doGlRotate and camera init<commit_after><|endoftext|>


<commit_before><commit_msg>Cleaned up GUI section.<commit_after><|endoftext|>


<commit_before><commit_msg>Revert "[clang-tidy] fix PR36489 - respect deduced pointer types from auto as well"<commit_after><|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 ***********************************************************************
 *
 * Last port: operation/overlay/OverlayResultValidator.java rev. 0
 *
 **********************************************************************/

#include <geos/operation/overlay/OverlayResultValidator.h>
#include <geos/operation/overlay/FuzzyPointLocator.h>
#include <geos/operation/overlay/OffsetPointGenerator.h>

#include <cassert>
#include <functional>
#include <vector>
#include <memory> // for auto_ptr
#include <algorithm>

#ifndef GEOS_DEBUG
#define GEOS_DEBUG 0
#endif

#define COMPUTE_Z 1
#define USE_ELEVATION_MATRIX 1
#define USE_INPUT_AVGZ 0

using namespace std;
using namespace geos::geom;
using namespace geos::geomgraph;
using namespace geos::algorithm;

namespace geos {
namespace operation { // geos.operation
namespace overlay { // geos.operation.overlay

double OverlayResultValidator::_TOLERANCE = 0.000001;

/* static public */
bool
OverlayResultValidator::isValid(const Geometry& geom0, const Geometry& geom1,
		OverlayOp::OpCode opCode,
		const Geometry& result)
{
	OverlayResultValidator validator(geom0, geom1, result);
	return validator.isValid(opCode);
}

/*public*/
OverlayResultValidator::OverlayResultValidator(
		const Geometry& geom0,
		const Geometry& geom1,
		const Geometry& result)
	:
	g0(geom0),
	g1(geom1),
	gres(result),
	fpl0(g0, _TOLERANCE),
	fpl1(g1, _TOLERANCE),
	fplres(gres, _TOLERANCE),
	invalidLocation()
{
}

/*public*/
bool
OverlayResultValidator::isValid(OverlayOp::OpCode overlayOp)
{
	addTestPts(g0);
	addTestPts(g1);
	if (! testValid(overlayOp) )
		return false;
	return true;
}

/*private*/
void
OverlayResultValidator::addTestPts(const Geometry& g)
{
	OffsetPointGenerator ptGen(g, 5 * _TOLERANCE);
	auto_ptr< vector<geom::Coordinate> > pts = ptGen.getPoints();
	testCoords.insert(testCoords.end(), pts->begin(), pts->end());
}

/*private*/
bool
OverlayResultValidator::testValid(OverlayOp::OpCode overlayOp)
{
	for (size_t i=0, n=testCoords.size(); i<n; ++i)
	{
		Coordinate& pt = testCoords[i];
		if (! testValid(overlayOp, pt)) {
			invalidLocation = pt;
			return false;
		}
	}
	return true;
}

/*private*/
bool
OverlayResultValidator::testValid(OverlayOp::OpCode overlayOp,
		const Coordinate& pt)
{
	std::vector<geom::Location::Value> location(3);

	location[0] = fpl0.getLocation(pt);
	location[1] = fpl1.getLocation(pt);
	location[2] = fplres.getLocation(pt);

	/*
	 * If any location is on the Boundary, can't deduce anything,
	 * so just return true
	 */
	if ( find(location.begin(), location.end(), Location::BOUNDARY) != location.end() )
	{
		return true;
	}

	return isValidResult(overlayOp, location);
}

/* private */
bool
OverlayResultValidator::isValidResult(OverlayOp::OpCode overlayOp,
	std::vector<geom::Location::Value>& location)
{
	bool expectedInterior = OverlayOp::isResultOfOp(location[0],
			location[1], overlayOp);

	bool resultInInterior = (location[2] == Location::INTERIOR);

	bool isValid = ! (expectedInterior ^ resultInInterior);

	return isValid;
}

} // namespace geos.operation.overlay
} // namespace geos.operation
} // namespace geos

/**********************************************************************
 * $Log$
 **********************************************************************/

<commit_msg>blindly return positive result if any input or output is not an area<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 ***********************************************************************
 *
 * Last port: operation/overlay/OverlayResultValidator.java rev. 0
 *
 **********************************************************************/

#include <geos/operation/overlay/OverlayResultValidator.h>
#include <geos/operation/overlay/FuzzyPointLocator.h>
#include <geos/operation/overlay/OffsetPointGenerator.h>

#include <cassert>
#include <functional>
#include <vector>
#include <memory> // for auto_ptr
#include <algorithm>

#ifndef GEOS_DEBUG
#define GEOS_DEBUG 0
#endif

#define COMPUTE_Z 1
#define USE_ELEVATION_MATRIX 1
#define USE_INPUT_AVGZ 0

using namespace std;
using namespace geos::geom;
using namespace geos::geomgraph;
using namespace geos::algorithm;

namespace geos {
namespace operation { // geos.operation
namespace overlay { // geos.operation.overlay

double OverlayResultValidator::_TOLERANCE = 0.000001;

namespace { // anonymous namespace

bool isArea(const Geometry& g)
{
        GeometryTypeId type = g.getGeometryTypeId();
        if ( type == GEOS_POLYGON ) return true;
        if ( type == GEOS_MULTIPOLYGON ) return true;
        return false;
}

} // anonymous namespace

/* static public */
bool
OverlayResultValidator::isValid(const Geometry& geom0, const Geometry& geom1,
		OverlayOp::OpCode opCode,
		const Geometry& result)
{
	OverlayResultValidator validator(geom0, geom1, result);
	return validator.isValid(opCode);
}

/*public*/
OverlayResultValidator::OverlayResultValidator(
		const Geometry& geom0,
		const Geometry& geom1,
		const Geometry& result)
	:
	g0(geom0),
	g1(geom1),
	gres(result),
	fpl0(g0, _TOLERANCE),
	fpl1(g1, _TOLERANCE),
	fplres(gres, _TOLERANCE),
	invalidLocation()
{
}

/*public*/
bool
OverlayResultValidator::isValid(OverlayOp::OpCode overlayOp)
{
	// The check only works for areal geoms
	if ( ! isArea(g0) ) return true;
	if ( ! isArea(g1) ) return true;
	if ( ! isArea(gres) ) return true;

	addTestPts(g0);
	addTestPts(g1);
	if (! testValid(overlayOp) )
		return false;
	return true;
}

/*private*/
void
OverlayResultValidator::addTestPts(const Geometry& g)
{
	OffsetPointGenerator ptGen(g, 5 * _TOLERANCE);
	auto_ptr< vector<geom::Coordinate> > pts = ptGen.getPoints();
	testCoords.insert(testCoords.end(), pts->begin(), pts->end());
}

/*private*/
bool
OverlayResultValidator::testValid(OverlayOp::OpCode overlayOp)
{
	for (size_t i=0, n=testCoords.size(); i<n; ++i)
	{
		Coordinate& pt = testCoords[i];
		if (! testValid(overlayOp, pt)) {
			invalidLocation = pt;
			return false;
		}
	}
	return true;
}

/*private*/
bool
OverlayResultValidator::testValid(OverlayOp::OpCode overlayOp,
		const Coordinate& pt)
{
	std::vector<geom::Location::Value> location(3);

	location[0] = fpl0.getLocation(pt);
	location[1] = fpl1.getLocation(pt);
	location[2] = fplres.getLocation(pt);

	/*
	 * If any location is on the Boundary, can't deduce anything,
	 * so just return true
	 */
	if ( find(location.begin(), location.end(), Location::BOUNDARY) != location.end() )
	{
		return true;
	}

	return isValidResult(overlayOp, location);
}

/* private */
bool
OverlayResultValidator::isValidResult(OverlayOp::OpCode overlayOp,
	std::vector<geom::Location::Value>& location)
{
	bool expectedInterior = OverlayOp::isResultOfOp(location[0],
			location[1], overlayOp);

	bool resultInInterior = (location[2] == Location::INTERIOR);

	bool isValid = ! (expectedInterior ^ resultInInterior);

	return isValid;
}

} // namespace geos.operation.overlay
} // namespace geos.operation
} // namespace geos

/**********************************************************************
 * $Log$
 **********************************************************************/

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009  Cyril Soldani
 *
 * This file is part of QuickCheck++.
 *
 * QuickCheck++ is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * QuickCheck++ is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * QuickCheck++. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * \file generate.hh
 *
 * Defines the data generator interface. This file also contains some functions
 * and templates defining generators for basic types and containers.
 *
 * \todo more generators (\eg strings and other containers than vectors)
 * \todo implement more generator helper functions
 */

#ifndef QUICKCHECK_GENERATE_H
#define QUICKCHECK_GENERATE_H

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <limits>
#include <vector>

namespace quickcheck {

/**
 * Generates a value in a range.
 *
 * \tparam A the value type (must be numeric)
 *
 * \param low  the lower bound (inclusive)
 * \param high the higher bound (inclusive)
 *
 * \return a value between \c low and \c high (both inclusive).
 */
template<class A>
A generateInRange(A low, A high)
{
   assert(low <= high);
   A offset = static_cast<A>(double(rand()) / RAND_MAX
                             * (double(high) - double(low) + 1));
   return static_cast<A>(low + offset);
}

/**
 * Chooses randomly an element out of a sequence.
 *
 * \param first an iterator pointing to first element
 * \param last  an iterator pointing to after-last element
 *
 * \return the chosen element
 */
template<class A, class Iter>
A oneOf(Iter first, Iter last)
{
   assert(std::distance(first, last) > 0);
   size_t len = size_t(std::distance(first, last));
   assert(len > 0);
   size_t index = generateInRange(size_t(0), len - 1);
   Iter i;
   for (i = first; index != 0; ++i)
      --index;
   return *i;
}

/**
 * Generates randomly an integer value. The value is taken in interval \c [0,
 * n] for unsigned values and in interval \c [-n, n] for signed values. These
 * intervals are of course clipped to the minimum and maximum values admissible
 * for the returned type.
 *
 * \tparam A the return type
 *
 * \param n the size hint
 *
 * \return a random integer in the intersection of \c [-n, n] and the A's range
 */
template<class A>
A generateInteger(size_t n)
{
   // not appropriate for floats as it chooses only integers
   assert(std::numeric_limits<A>::is_integer);
   // clips [-n, n] interval if necessary
   A max = std::numeric_limits<A>::max();
   A min = std::numeric_limits<A>::min();
   A high = (n > size_t(max)) ? max : A(n);
   A low = (n > size_t(-min)) ? min : A(-n);
   // generates integer in clipped interval
   return generateInRange(low, high);
}

/**
 * Generates a boolean value randomly. The size hint is ignored.
 *
 * \param out the reference to be set to \c true or \c false at random
 */
static inline void generate(size_t, bool& out)
{
   static const bool booleans[] = { true, false };
   out = oneOf<bool>(&booleans[0], &booleans[2]);
}

/**
 * Generates a character at random. For low values of \c n, the character is
 * alphanumeric. For intermediate values, it is ASCII and printable. For high
 * values of \c n, the generated character can have any value in its range,
 * even if it means it is not ASCII and/or not printable.
 *
 * \warning the zero character may be generated by this generator (\c n > 94)
 * \warning the zero character is not generated very often by this generator
 * (and only for \c n > 94)
 *
 * \param n the size hint, influences the \e basicness of generated character
 * \param out the reference to be set to the generated character
 */
static inline void generate(size_t n, char& out)
{
   static const char *basicChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
      "abcdefghijklmnopqrstuvwxyz";
   if (n < sizeof (basicChars) - 1)
      out = oneOf<char>(&basicChars[0], &basicChars[n]);
   else if (n < 95)
      out = generateInRange(' ', '~'); // any printable ASCII
   else
      out = generateInRange(char(0x00), char(0xff));
}

/**
 * \copydoc generate(size_t, char&)
 */
static inline void generate(size_t n, unsigned char& out)
{
   char c;
   generate(n, c);
   out = static_cast<unsigned char>(c);
}

/**
 * Generates a short integer in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, short& out)
{
   out = generateInteger<short>(n);
}

/**
 * Generates an unsigned short integer in range \c [0, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, unsigned short& out)
{
   out = generateInteger<unsigned short>(n);
}

/**
 * Generates an integer in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, int& out)
{
   out = generateInteger<int>(n);
}

/**
 * Generates an unsigned integer in range \c [0, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, unsigned int& out)
{
   out = generateInteger<unsigned int>(n);
}

/**
 * Generates a long integer in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, long& out)
{
   out = generateInteger<long>(n);
}

/**
 * Generates an unsigned long integer in range \c [0, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, unsigned long& out)
{
   out = generateInteger<unsigned long>(n);
}

/**
 * Generates a single-precision floating point value in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, float& out)
{
   out = float(rand()) / float(RAND_MAX) * 2 * float(n) - float(n);
}

/**
 * Generates a double-precision floating point value in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, double& out)
{
   out = double(rand()) / RAND_MAX * 2 * double(n) - double(n);
}

/**
 * Generates a <tt>long double</tt> floating point value in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, long double& out)
{
   out = static_cast<long double>(rand()) / RAND_MAX * 2 * n - n;
}

/**
 * Generates a vector of 0 to \c n randomly-generated values of type \c A.
 *
 * \tparam A the element type
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
template<class A>
void generate(size_t n, std::vector<A>& out)
{
   unsigned len;
   generate(n, len);
   for (size_t i = 0; i < len; ++i) {
      A a;
      generate(n - 1, a);
      out.push_back(a);
   }
}

}

#endif // !QUICKCHECK_GENERATE_H
<commit_msg>Fix warnings in QuickCheck++.<commit_after>/*
 * Copyright (C) 2009  Cyril Soldani
 *
 * This file is part of QuickCheck++.
 *
 * QuickCheck++ is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * QuickCheck++ is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * QuickCheck++. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * \file generate.hh
 *
 * Defines the data generator interface. This file also contains some functions
 * and templates defining generators for basic types and containers.
 *
 * \todo more generators (\eg strings and other containers than vectors)
 * \todo implement more generator helper functions
 */

#ifndef QUICKCHECK_GENERATE_H
#define QUICKCHECK_GENERATE_H

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <limits>
#include <vector>

namespace quickcheck {

/**
 * Generates a value in a range.
 *
 * \tparam A the value type (must be numeric)
 *
 * \param low  the lower bound (inclusive)
 * \param high the higher bound (inclusive)
 *
 * \return a value between \c low and \c high (both inclusive).
 */
template<class A>
A generateInRange(A low, A high)
{
   assert(low <= high);
   A offset = static_cast<A>(double(rand()) / RAND_MAX
                             * (double(high) - double(low) + 1));
   return static_cast<A>(low + offset);
}

/**
 * Chooses randomly an element out of a sequence.
 *
 * \param first an iterator pointing to first element
 * \param last  an iterator pointing to after-last element
 *
 * \return the chosen element
 */
template<class A, class Iter>
A oneOf(Iter first, Iter last)
{
   assert(std::distance(first, last) > 0);
   size_t len = size_t(std::distance(first, last));
   assert(len > 0);
   size_t index = generateInRange(size_t(0), len - 1);
   Iter i;
   for (i = first; index != 0; ++i)
      --index;
   return *i;
}

/**
 * Generates randomly an integer value. The value is taken in interval \c [0,
 * n] for unsigned values and in interval \c [-n, n] for signed values. These
 * intervals are of course clipped to the minimum and maximum values admissible
 * for the returned type.
 *
 * \tparam A the return type
 *
 * \param n the size hint
 *
 * \return a random integer in the intersection of \c [-n, n] and the A's range
 */
template<class A>
A generateInteger(size_t n)
{
   // not appropriate for floats as it chooses only integers
   assert(std::numeric_limits<A>::is_integer);
   // clips [-n, n] interval if necessary
   A max = std::numeric_limits<A>::max();
   A min = std::numeric_limits<A>::min();
   A high = (ptrdiff_t(n) > ptrdiff_t(max)) ? max : A(n);
   A low = (ptrdiff_t(n) < -ptrdiff_t(min)) ? -min : -A(n);
   // generates integer in clipped interval
   return generateInRange(low, high);
}

template<class A>
A generateUnsignedInteger(size_t n)
{
   // not appropriate for floats as it chooses only integers
   assert(std::numeric_limits<A>::is_integer);
   // clips [0, n] interval if necessary
   A high = std::min<A>(A(n), std::numeric_limits<A>::max());
   // generates integer in clipped interval
   return generateInRange(A(0), high);
}

/**
 * Generates a boolean value randomly. The size hint is ignored.
 *
 * \param out the reference to be set to \c true or \c false at random
 */
static inline void generate(size_t, bool& out)
{
   static const bool booleans[] = { true, false };
   out = oneOf<bool>(&booleans[0], &booleans[2]);
}

/**
 * Generates a character at random. For low values of \c n, the character is
 * alphanumeric. For intermediate values, it is ASCII and printable. For high
 * values of \c n, the generated character can have any value in its range,
 * even if it means it is not ASCII and/or not printable.
 *
 * \warning the zero character may be generated by this generator (\c n > 94)
 * \warning the zero character is not generated very often by this generator
 * (and only for \c n > 94)
 *
 * \param n the size hint, influences the \e basicness of generated character
 * \param out the reference to be set to the generated character
 */
static inline void generate(size_t n, char& out)
{
   static const char *basicChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
      "abcdefghijklmnopqrstuvwxyz";
   if (n < sizeof (basicChars) - 1)
      out = oneOf<char>(&basicChars[0], &basicChars[n]);
   else if (n < 95)
      out = generateInRange(' ', '~'); // any printable ASCII
   else
      out = generateInRange(char(0x00), char(0xff));
}

/**
 * \copydoc generate(size_t, char&)
 */
static inline void generate(size_t n, unsigned char& out)
{
   char c;
   generate(n, c);
   out = static_cast<unsigned char>(c);
}

/**
 * Generates a short integer in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, short& out)
{
   out = generateInteger<short>(n);
}

/**
 * Generates an unsigned short integer in range \c [0, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, unsigned short& out)
{
   out = generateUnsignedInteger<unsigned short>(n);
}

/**
 * Generates an integer in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, int& out)
{
   out = generateInteger<int>(n);
}

/**
 * Generates an unsigned integer in range \c [0, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, unsigned int& out)
{
   out = generateUnsignedInteger<unsigned int>(n);
}

/**
 * Generates a long integer in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, long& out)
{
   out = generateInteger<long>(n);
}

/**
 * Generates an unsigned long integer in range \c [0, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, unsigned long& out)
{
   out = generateUnsignedInteger<unsigned long>(n);
}

/**
 * Generates a single-precision floating point value in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, float& out)
{
   out = float(rand()) / float(RAND_MAX) * 2 * float(n) - float(n);
}

/**
 * Generates a double-precision floating point value in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, double& out)
{
   out = double(rand()) / RAND_MAX * 2 * double(n) - double(n);
}

/**
 * Generates a <tt>long double</tt> floating point value in range \c [-n, n].
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
static inline void generate(size_t n, long double& out)
{
   out = static_cast<long double>(rand()) / RAND_MAX * 2 * n - n;
}

/**
 * Generates a vector of 0 to \c n randomly-generated values of type \c A.
 *
 * \tparam A the element type
 *
 * \param n   the size hint
 * \param out the reference to be set to the generated value
 */
template<class A>
void generate(size_t n, std::vector<A>& out)
{
   unsigned len;
   generate(n, len);
   for (size_t i = 0; i < len; ++i) {
      A a;
      generate(n - 1, a);
      out.push_back(a);
   }
}

}

#endif // !QUICKCHECK_GENERATE_H
<|endoftext|>


<commit_before>#pragma once

#include "blackhole/sink/files/rotation/watcher/config.hpp"

namespace blackhole {

namespace sink {

namespace rotation {

namespace watcher {

struct time_picker_t {
    inline std::tm now() const {
        std::time_t time = std::time(nullptr);
        std::tm timeinfo;
        ::localtime_r(&time, &timeinfo);
        return timeinfo;
    }
};

template<class TimePicker = time_picker_t>
struct datetime_t {
    typedef typename config_t<datetime_t<TimePicker>>::period_t period_t;

    TimePicker picker;
    period_t period;
    int previous;

    datetime_t(period_t period = period_t::daily) :
        period(period),
        previous(watch())
    {}

    datetime_t(const std::string& period) :
        period(make_period(period)),
        previous(watch())
    {}

    template<typename Backend>
    bool operator ()(Backend&, const std::string&) {
        int current = watch();
        if (current != previous) {
            previous = current;
            return true;
        }

        return false;
    }

private:
    int watch() const {
        const std::tm& timeinfo = picker.now();

        switch (period) {
        case period_t::hourly:
            return timeinfo.tm_hour;
        case period_t::daily:
            return timeinfo.tm_mday;
        case period_t::weekly:
            return timeinfo.tm_wday;
        case period_t::monthly:
            return timeinfo.tm_mon;
        default:
            break;
        }

        return timeinfo.tm_mday;
    }

    static period_t make_period(const std::string& period) {
        if (period == "H") {
            return period_t::hourly;
        } else if (period == "d") {
            return period_t::daily;
        } else if (period == "w") {
            return period_t::weekly;
        } else if (period == "M") {
            return period_t::monthly;
        }

        return period_t::daily;
    }
};

} // namespace watcher

} // namespace rotation

} // namespace sink

} // namespace blackhole
<commit_msg>More strict period value handling.<commit_after>#pragma once

#include "blackhole/sink/files/rotation/watcher/config.hpp"

namespace blackhole {

namespace sink {

namespace rotation {

namespace watcher {

struct time_picker_t {
    inline std::tm now() const {
        std::time_t time = std::time(nullptr);
        std::tm timeinfo;
        ::localtime_r(&time, &timeinfo);
        return timeinfo;
    }
};

template<class TimePicker = time_picker_t>
struct datetime_t {
    typedef typename config_t<datetime_t<TimePicker>>::period_t period_t;

    TimePicker picker;
    const period_t period;
    int previous;

    datetime_t(period_t period = period_t::daily) :
        period(period),
        previous(watch())
    {}

    datetime_t(const std::string& period) :
        period(make_period(period)),
        previous(watch())
    {}

    template<typename Backend>
    bool operator ()(Backend&, const std::string&) {
        int current = watch();
        if (current != previous) {
            previous = current;
            return true;
        }

        return false;
    }

private:
    int watch() const {
        const std::tm& timeinfo = picker.now();

        switch (period) {
        case period_t::hourly:
            return timeinfo.tm_hour;
        case period_t::daily:
            return timeinfo.tm_mday;
        case period_t::weekly:
            return timeinfo.tm_wday;
        case period_t::monthly:
            return timeinfo.tm_mon;
        default:
            break;
        }

        return timeinfo.tm_mday;
    }

    static period_t make_period(const std::string& period) {
        if (period == "H") {
            return period_t::hourly;
        } else if (period == "d") {
            return period_t::daily;
        } else if (period == "w") {
            return period_t::weekly;
        } else if (period == "M") {
            return period_t::monthly;
        }

        return period_t::daily;
    }
};

} // namespace watcher

} // namespace rotation

} // namespace sink

} // namespace blackhole
<|endoftext|>


<commit_before>#include "SparseSideInfo.h"
#include "linop.h"

#include <SmurffCpp/Utils/MatrixUtils.h>

#include <vector>

namespace smurff {

SparseSideInfo::SparseSideInfo(const std::shared_ptr<MatrixConfig> &mc) {
    F = matrix_utils::sparse_to_eigen(*mc);
    Ft = F.transpose();
}

SparseSideInfo::~SparseSideInfo() {}

int SparseSideInfo::cols() const
{
   return F.cols();
}

int SparseSideInfo::rows() const
{
   return F.rows();
}

std::ostream& SparseSideInfo::print(std::ostream &os) const
{
   double percent = 100.8 * (double)F.nonZeros() / (double)F.rows() / (double) F.cols();
   os << "SparseDouble " << F.nonZeros() << " [" << F.rows() << ", " << F.cols() << "] ("
      << percent << "%)" << std::endl;
   return os;
}

bool SparseSideInfo::is_dense() const
{
   return false;
}

void SparseSideInfo::compute_uhat(Matrix& uhat, Matrix& beta)
{
    COUNTER("compute_uhat");
    uhat = beta * (Ft);
}

void SparseSideInfo::At_mul_A(Matrix& out)
{
    COUNTER("At_mul_A");
    out = Ft * F;
}

Matrix SparseSideInfo::A_mul_B(Matrix& A)
{
    COUNTER("A_mul_B");
    return (A * F);
}

int SparseSideInfo::solve_blockcg(Matrix& X, double reg, Matrix& B, double tol, const int blocksize, const int excess, bool throw_on_cholesky_error)
{
    COUNTER("solve_blockcg");
    return linop::solve_blockcg(X, *this, reg, B, tol, blocksize, excess, throw_on_cholesky_error);
#if 0
    int iter1, iter2;
    Matrix X1 = X;
    {
        COUNTER("eigen_cg");
        linop::AtA A(F, reg);
        Eigen::ConjugateGradient<linop::AtA, Eigen::Lower | Eigen::Upper> cg;
        cg.setTolerance(tol);
        cg.compute(A);
        X1 = cg.solve(B.transpose()).transpose();
        iter1 = cg.iterations();
        SHOW(iter1);
        SHOW((X1 - B).norm());
    }

    Matrix X2 = X;
    {
        COUNTER("smurff_cg");
        iter2 = linop::solve_blockcg(X2, *this, reg, B, tol, blocksize, excess, throw_on_cholesky_error);
        SHOW(iter2);
        SHOW((X2 - B).norm());
    }

    SHOW((X2 - X1).norm());

    return iter1;
#endif
}

Vector SparseSideInfo::col_square_sum()
{
    COUNTER("col_square_sum");
    // component-wise square
    auto E = F.unaryExpr([](const double &d) { return d * d; });
    // col-wise sum
    return E.transpose() * Vector::Ones(E.rows());
}

// Y = X[:,col]' * B'
void SparseSideInfo::At_mul_Bt(Vector& Y, const int col, Matrix& B)
{
    COUNTER("At_mul_Bt");
    auto out = Ft.block(col, 0, col + 1, Ft.cols()) * B.transpose();
    Y = out.transpose();
}

// computes Z += A[:,col] * b', where a and b are vectors
void SparseSideInfo::add_Acol_mul_bt(Matrix& Z, const int col, Vector& b)
{
    COUNTER("add_Acol_mul_bt");
    Z += (F.col(col) * b.transpose()).transpose();
}
} // end namespace smurff
<commit_msg>FIX: double -> float_type<commit_after>#include "SparseSideInfo.h"
#include "linop.h"

#include <SmurffCpp/Utils/MatrixUtils.h>

#include <vector>

namespace smurff {

SparseSideInfo::SparseSideInfo(const std::shared_ptr<MatrixConfig> &mc) {
    F = matrix_utils::sparse_to_eigen(*mc);
    Ft = F.transpose();
}

SparseSideInfo::~SparseSideInfo() {}

int SparseSideInfo::cols() const
{
   return F.cols();
}

int SparseSideInfo::rows() const
{
   return F.rows();
}

std::ostream& SparseSideInfo::print(std::ostream &os) const
{
   double percent = 100.8 * (double)F.nonZeros() / (double)F.rows() / (double) F.cols();
   os << "SparseDouble " << F.nonZeros() << " [" << F.rows() << ", " << F.cols() << "] ("
      << percent << "%)" << std::endl;
   return os;
}

bool SparseSideInfo::is_dense() const
{
   return false;
}

void SparseSideInfo::compute_uhat(Matrix& uhat, Matrix& beta)
{
    COUNTER("compute_uhat");
    uhat = beta * (Ft);
}

void SparseSideInfo::At_mul_A(Matrix& out)
{
    COUNTER("At_mul_A");
    out = Ft * F;
}

Matrix SparseSideInfo::A_mul_B(Matrix& A)
{
    COUNTER("A_mul_B");
    return (A * F);
}

int SparseSideInfo::solve_blockcg(Matrix& X, double reg, Matrix& B, double tol, const int blocksize, const int excess, bool throw_on_cholesky_error)
{
    COUNTER("solve_blockcg");
    return linop::solve_blockcg(X, *this, reg, B, tol, blocksize, excess, throw_on_cholesky_error);
#if 0
    int iter1, iter2;
    Matrix X1 = X;
    {
        COUNTER("eigen_cg");
        linop::AtA A(F, reg);
        Eigen::ConjugateGradient<linop::AtA, Eigen::Lower | Eigen::Upper> cg;
        cg.setTolerance(tol);
        cg.compute(A);
        X1 = cg.solve(B.transpose()).transpose();
        iter1 = cg.iterations();
        SHOW(iter1);
        SHOW((X1 - B).norm());
    }

    Matrix X2 = X;
    {
        COUNTER("smurff_cg");
        iter2 = linop::solve_blockcg(X2, *this, reg, B, tol, blocksize, excess, throw_on_cholesky_error);
        SHOW(iter2);
        SHOW((X2 - B).norm());
    }

    SHOW((X2 - X1).norm());

    return iter1;
#endif
}

Vector SparseSideInfo::col_square_sum()
{
    COUNTER("col_square_sum");
    // component-wise square
    auto E = F.unaryExpr([](const float_type &d) { return d * d; });
    // col-wise sum
    return E.transpose() * Vector::Ones(E.rows());
}

// Y = X[:,col]' * B'
void SparseSideInfo::At_mul_Bt(Vector& Y, const int col, Matrix& B)
{
    COUNTER("At_mul_Bt");
    auto out = Ft.block(col, 0, col + 1, Ft.cols()) * B.transpose();
    Y = out.transpose();
}

// computes Z += A[:,col] * b', where a and b are vectors
void SparseSideInfo::add_Acol_mul_bt(Matrix& Z, const int col, Vector& b)
{
    COUNTER("add_Acol_mul_bt");
    Z += (F.col(col) * b.transpose()).transpose();
}
} // end namespace smurff
<|endoftext|>