<commit_before>#include "LogsPopup.hpp"

#include "IrcMessage"
#include "common/Channel.hpp"
#include "common/NetworkRequest.hpp"
#include "providers/twitch/TwitchChannel.hpp"
#include "providers/twitch/TwitchMessageBuilder.hpp"
#include "widgets/helper/ChannelView.hpp"

#include <QDateTime>
#include <QJsonArray>
#include <QMessageBox>
#include <QVBoxLayout>

namespace chatterino {

LogsPopup::LogsPopup()
    : channel_(Channel::getEmpty())
{
    this->initLayout();
    this->resize(400, 600);
}

void LogsPopup::initLayout()
{
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);

    this->channelView_ = new ChannelView(this);
    layout->addWidget(this->channelView_);

    this->setLayout(layout);
}

void LogsPopup::setInfo(ChannelPtr channel, QString userName)
{
    this->channel_ = channel;
    this->userName_ = userName;
    this->getRoomID();
    this->setWindowTitle(this->userName_ + "'s logs in #" +
                         this->channel_->getName());
}

void LogsPopup::setMessages(std::vector<MessagePtr> &messages)
{
    ChannelPtr logsChannel(new Channel("logs", Channel::Type::Misc));

    logsChannel->addMessagesAtStart(messages);
    this->channelView_->setChannel(logsChannel);
}

void LogsPopup::getRoomID()
{
    TwitchChannel *twitchChannel =
        dynamic_cast<TwitchChannel *>(this->channel_.get());
    if (twitchChannel == nullptr)
    {
        return;
    }

    QString channelName = twitchChannel->getName();

    QString url = QString("https://cbenni.com/api/channel/%1").arg(channelName);

    NetworkRequest req(url);
    req.setCaller(QThread::currentThread());

    req.onError([this](int errorCode) {
        this->getOverrustleLogs();
        return true;
    });

    req.onSuccess([this, channelName](auto result) -> Outcome {
        auto data = result.parseJson();
        this->roomID_ = data.value("channel").toObject()["id"].toInt();
        this->getLogviewerLogs();
        return Success;
    });

    req.execute();
}

void LogsPopup::getLogviewerLogs()
{
    TwitchChannel *twitchChannel =
        dynamic_cast<TwitchChannel *>(this->channel_.get());
    if (twitchChannel == nullptr)
    {
        return;
    }

    QString channelName = twitchChannel->getName();

    auto url = QString("https://cbenni.com/api/logs/%1/?nick=%2&before=500")
                   .arg(channelName, this->userName_);

    NetworkRequest req(url);
    req.setCaller(QThread::currentThread());

    req.onError([this](int errorCode) {
        this->getOverrustleLogs();
        return true;
    });

    req.onSuccess([this, channelName](auto result) -> Outcome {
        auto data = result.parseJson();
        std::vector<MessagePtr> messages;

        QJsonValue before = data.value("before");

        for (auto i : before.toArray())
        {
            auto messageObject = i.toObject();
            QString message = messageObject.value("text").toString();

            // Hacky way to fix the timestamp
            message.insert(1, "historical=1;");
            message.insert(1, QString("tmi-sent-ts=%10000;")
                                  .arg(messageObject["time"].toInt()));
            message.insert(1, QString("room-id=%1;").arg(this->roomID_));

            MessageParseArgs args;
            auto ircMessage =
                Communi::IrcMessage::fromData(message.toUtf8(), nullptr);
            auto privMsg =
                static_cast<Communi::IrcPrivateMessage *>(ircMessage);
            TwitchMessageBuilder builder(this->channel_.get(), privMsg, args);
            messages.push_back(builder.build());
        };
        this->setMessages(messages);

        return Success;
    });

    req.execute();
}

void LogsPopup::getOverrustleLogs()
{
    TwitchChannel *twitchChannel =
        dynamic_cast<TwitchChannel *>(this->channel_.get());
    if (twitchChannel == nullptr)
    {
        return;
    }

    QString channelName = twitchChannel->getName();

    QString url =
        QString("https://overrustlelogs.net/api/v1/stalk/%1/%2.json?limit=500")
            .arg(channelName, this->userName_);

    NetworkRequest req(url);
    req.setCaller(QThread::currentThread());
    req.onError([channelName](int errorCode) {
        //        this->close();
        auto box = new QMessageBox(
            QMessageBox::Information, "Error getting logs",
            "No logs could be found for channel " + channelName);
        box->setAttribute(Qt::WA_DeleteOnClose);
        box->show();
        box->raise();

        return true;
    });

    req.onSuccess([this, channelName](auto result) -> Outcome {
        auto data = result.parseJson();
        std::vector<MessagePtr> messages;
        if (data.contains("lines"))
        {
            QJsonArray dataMessages = data.value("lines").toArray();
            for (auto i : dataMessages)
            {
                QJsonObject singleMessage = i.toObject();
                QTime timeStamp = QDateTime::fromSecsSinceEpoch(
                                      singleMessage.value("timestamp").toInt())
                                      .time();

                MessageBuilder builder;
                builder.emplace<TimestampElement>(timeStamp);
                builder.emplace<TextElement>(this->userName_,
                                             MessageElementFlag::Username,
                                             MessageColor::System);
                builder.emplace<TextElement>(
                    singleMessage.value("text").toString(),
                    MessageElementFlag::Text, MessageColor::Text);
                messages.push_back(builder.release());
            }
        }
        this->setMessages(messages);

        return Success;
    });

    req.execute();
}
}  // namespace chatterino
<commit_msg>Added closing LogsPopup with QMessageBox.<commit_after>#include "LogsPopup.hpp"

#include "IrcMessage"
#include "common/Channel.hpp"
#include "common/NetworkRequest.hpp"
#include "providers/twitch/TwitchChannel.hpp"
#include "providers/twitch/TwitchMessageBuilder.hpp"
#include "widgets/helper/ChannelView.hpp"

#include <QDateTime>
#include <QJsonArray>
#include <QMessageBox>
#include <QVBoxLayout>

namespace chatterino {

LogsPopup::LogsPopup()
    : channel_(Channel::getEmpty())
{
    this->initLayout();
    this->resize(400, 600);
}

void LogsPopup::initLayout()
{
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);

    this->channelView_ = new ChannelView(this);
    layout->addWidget(this->channelView_);

    this->setLayout(layout);
}

void LogsPopup::setInfo(ChannelPtr channel, QString userName)
{
    this->channel_ = channel;
    this->userName_ = userName;
    this->getRoomID();
    this->setWindowTitle(this->userName_ + "'s logs in #" +
                         this->channel_->getName());
}

void LogsPopup::setMessages(std::vector<MessagePtr> &messages)
{
    ChannelPtr logsChannel(new Channel("logs", Channel::Type::Misc));

    logsChannel->addMessagesAtStart(messages);
    this->channelView_->setChannel(logsChannel);
}

void LogsPopup::getRoomID()
{
    TwitchChannel *twitchChannel =
        dynamic_cast<TwitchChannel *>(this->channel_.get());
    if (twitchChannel == nullptr)
    {
        return;
    }

    QString channelName = twitchChannel->getName();

    QString url = QString("https://cbenni.com/api/channel/%1").arg(channelName);

    NetworkRequest req(url);
    req.setCaller(QThread::currentThread());

    req.onError([this](int errorCode) {
        this->getOverrustleLogs();
        return true;
    });

    req.onSuccess([this, channelName](auto result) -> Outcome {
        auto data = result.parseJson();
        this->roomID_ = data.value("channel").toObject()["id"].toInt();
        this->getLogviewerLogs();
        return Success;
    });

    req.execute();
}

void LogsPopup::getLogviewerLogs()
{
    TwitchChannel *twitchChannel =
        dynamic_cast<TwitchChannel *>(this->channel_.get());
    if (twitchChannel == nullptr)
    {
        return;
    }

    QString channelName = twitchChannel->getName();

    auto url = QString("https://cbenni.com/api/logs/%1/?nick=%2&before=500")
                   .arg(channelName, this->userName_);

    NetworkRequest req(url);
    req.setCaller(QThread::currentThread());

    req.onError([this](int errorCode) {
        this->getOverrustleLogs();
        return true;
    });

    req.onSuccess([this, channelName](auto result) -> Outcome {
        auto data = result.parseJson();
        std::vector<MessagePtr> messages;

        QJsonValue before = data.value("before");

        for (auto i : before.toArray())
        {
            auto messageObject = i.toObject();
            QString message = messageObject.value("text").toString();

            // Hacky way to fix the timestamp
            message.insert(1, "historical=1;");
            message.insert(1, QString("tmi-sent-ts=%10000;")
                                  .arg(messageObject["time"].toInt()));
            message.insert(1, QString("room-id=%1;").arg(this->roomID_));

            MessageParseArgs args;
            auto ircMessage =
                Communi::IrcMessage::fromData(message.toUtf8(), nullptr);
            auto privMsg =
                static_cast<Communi::IrcPrivateMessage *>(ircMessage);
            TwitchMessageBuilder builder(this->channel_.get(), privMsg, args);
            messages.push_back(builder.build());
        };
        this->setMessages(messages);

        return Success;
    });

    req.execute();
}

void LogsPopup::getOverrustleLogs()
{
    TwitchChannel *twitchChannel =
        dynamic_cast<TwitchChannel *>(this->channel_.get());
    if (twitchChannel == nullptr)
    {
        return;
    }

    QString channelName = twitchChannel->getName();

    QString url =
        QString("https://overrustlelogs.net/api/v1/stalk/%1/%2.json?limit=500")
            .arg(channelName, this->userName_);

    NetworkRequest req(url);
    req.setCaller(QThread::currentThread());
    req.onError([this, channelName](int errorCode) {
        auto box = new QMessageBox(
            QMessageBox::Information, "Error getting logs",
            "No logs could be found for channel " + channelName);
        box->setAttribute(Qt::WA_DeleteOnClose);
        box->show();
        box->raise();

        static QSet<int> closeButtons {
            QMessageBox::Ok,
            QMessageBox::Close,
        };
        if (closeButtons.contains(box->exec()))
        {
            this->close();
        }

        return true;
    });

    req.onSuccess([this, channelName](auto result) -> Outcome {
        auto data = result.parseJson();
        std::vector<MessagePtr> messages;
        if (data.contains("lines"))
        {
            QJsonArray dataMessages = data.value("lines").toArray();
            for (auto i : dataMessages)
            {
                QJsonObject singleMessage = i.toObject();
                QTime timeStamp = QDateTime::fromSecsSinceEpoch(
                                      singleMessage.value("timestamp").toInt())
                                      .time();

                MessageBuilder builder;
                builder.emplace<TimestampElement>(timeStamp);
                builder.emplace<TextElement>(this->userName_,
                                             MessageElementFlag::Username,
                                             MessageColor::System);
                builder.emplace<TextElement>(
                    singleMessage.value("text").toString(),
                    MessageElementFlag::Text, MessageColor::Text);
                messages.push_back(builder.release());
            }
        }
        this->setMessages(messages);

        return Success;
    });

    req.execute();
}
}  // namespace chatterino
<|endoftext|>


<commit_before>/*
    Copyright (C) 2011  Martin Klapetek <mklapetek@kde.org>
    Copyright (C) 2013  David Edmundson <davidedmundsonk@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "persondetailsview.h"

#include <QFormLayout>
#include <QLabel>
#include <QDebug>
#include <QList>

#include <KLocalizedString>

#include "abstractfieldwidgetfactory.h"
#include "plugins/emaildetailswidget.h"

namespace KPeople {

class PersonDetailsViewPrivate{
public:
    PersonData  *m_person;
    QFormLayout *m_mainLayout;
    QList<AbstractFieldWidgetFactory*> m_plugins;
};
}

using namespace KPeople;

class CoreFieldsPlugin : public AbstractFieldWidgetFactory
{
public:
    CoreFieldsPlugin(KABC::Field *field);
    virtual ~CoreFieldsPlugin();
    virtual QString label() const;
    virtual int sortWeight() const;
    virtual QWidget* createDetailsWidget(const KABC::Addressee &person, QWidget *parent) const;
private:
    KABC::Field* m_field;
};

CoreFieldsPlugin::CoreFieldsPlugin(KABC::Field* field):
    m_field(field)
{
}

CoreFieldsPlugin::~CoreFieldsPlugin()
{

}

QString CoreFieldsPlugin::label() const
{
    return m_field->label();
}

int CoreFieldsPlugin::sortWeight() const
{
    return m_field->category()*10;
}

QWidget* CoreFieldsPlugin::createDetailsWidget(const KABC::Addressee &person, QWidget *parent) const
{
    //don't handle emails here - KABC::Field just lists one which is rubbish. Instead use a custom plugin that lists everything
    if (m_field->category() == KABC::Field::Email) {
        return 0;
    }

    const QString &text = m_field->value(person);
    if (text.isEmpty()) {
        return 0;
    }
    return new QLabel(text, parent);
}

PersonDetailsView::PersonDetailsView(QWidget *parent)
    : QWidget(parent),
      d_ptr(new PersonDetailsViewPrivate())
{
    Q_D(PersonDetailsView);
    d->m_mainLayout = new QFormLayout(this);
    d->m_person = 0;

    //create plugins
    Q_FOREACH(KABC::Field *field, KABC::Field::allFields()) {
        d->m_plugins << new CoreFieldsPlugin(field);
    }

    d->m_plugins << new EmailFieldsPlugin();

    //TODO Sort plugins
}

PersonDetailsView::~PersonDetailsView()
{
    Q_D(PersonDetailsView);
//     qDeleteAll<AbstractFieldWidgetFactory>(d->m_plugins);
    delete d_ptr;
}

void PersonDetailsView::setPerson(PersonData *person)
{
    Q_D(PersonDetailsView);
    if (!d->m_person) {
        disconnect(d->m_person, SIGNAL(dataChanged()), this, SLOT(reload()));
    }

    d->m_person = person;
    connect(d->m_person, SIGNAL(dataChanged()), this, SLOT(reload()));
    reload();
}

// void PersonDetailsView::setPersonsModel(PersonsModel *model)
// {
//     Q_D(PersonDetailsView);
//     Q_FOREACH (AbstractPersonDetailsWidget *detailsWidget, d->m_detailWidgets) {
//         detailsWidget->setPersonsModel(model);
//     }
// }

void PersonDetailsView::reload()
{
    Q_D(PersonDetailsView);

    //delete everything currently in the layout
    QLayoutItem *child;
    while ((child = layout()->takeAt(0)) != 0) {
        delete child->widget();
        delete child;
    }

    Q_FOREACH(AbstractFieldWidgetFactory *widgetFactory, d->m_plugins) {
        const QString label = widgetFactory->label() + ':';
        QWidget *widget = widgetFactory->createDetailsWidget(d->m_person->person(), this);

        if (widget) {
            QFont font = widget->font();
            font.setBold(true);
            widget->setFont(font);
            d->m_mainLayout->addRow(label, widget);
        }
    }
}
<commit_msg>Create our own label in PersonDetailsView<commit_after>/*
    Copyright (C) 2011  Martin Klapetek <mklapetek@kde.org>
    Copyright (C) 2013  David Edmundson <davidedmundsonk@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "persondetailsview.h"

#include <QFormLayout>
#include <QLabel>
#include <QDebug>
#include <QList>

#include <KLocalizedString>

#include "abstractfieldwidgetfactory.h"
#include "plugins/emaildetailswidget.h"

namespace KPeople {

class PersonDetailsViewPrivate{
public:
    PersonData  *m_person;
    QFormLayout *m_mainLayout;
    QList<AbstractFieldWidgetFactory*> m_plugins;
};
}

using namespace KPeople;

class CoreFieldsPlugin : public AbstractFieldWidgetFactory
{
public:
    CoreFieldsPlugin(KABC::Field *field);
    virtual ~CoreFieldsPlugin();
    virtual QString label() const;
    virtual int sortWeight() const;
    virtual QWidget* createDetailsWidget(const KABC::Addressee &person, QWidget *parent) const;
private:
    KABC::Field* m_field;
};

CoreFieldsPlugin::CoreFieldsPlugin(KABC::Field* field):
    m_field(field)
{
}

CoreFieldsPlugin::~CoreFieldsPlugin()
{

}

QString CoreFieldsPlugin::label() const
{
    return m_field->label();
}

int CoreFieldsPlugin::sortWeight() const
{
    return m_field->category()*10;
}

QWidget* CoreFieldsPlugin::createDetailsWidget(const KABC::Addressee &person, QWidget *parent) const
{
    //don't handle emails here - KABC::Field just lists one which is rubbish. Instead use a custom plugin that lists everything
    if (m_field->category() == KABC::Field::Email) {
        return 0;
    }

    const QString &text = m_field->value(person);
    if (text.isEmpty()) {
        return 0;
    }
    return new QLabel(text, parent);
}

PersonDetailsView::PersonDetailsView(QWidget *parent)
    : QWidget(parent),
      d_ptr(new PersonDetailsViewPrivate())
{
    Q_D(PersonDetailsView);
    d->m_mainLayout = new QFormLayout(this);
    d->m_person = 0;

    //create plugins
    Q_FOREACH(KABC::Field *field, KABC::Field::allFields()) {
        d->m_plugins << new CoreFieldsPlugin(field);
    }

    d->m_plugins << new EmailFieldsPlugin();

    //TODO Sort plugins
}

PersonDetailsView::~PersonDetailsView()
{
    Q_D(PersonDetailsView);
//     qDeleteAll<AbstractFieldWidgetFactory>(d->m_plugins);
    delete d_ptr;
}

void PersonDetailsView::setPerson(PersonData *person)
{
    Q_D(PersonDetailsView);
    if (!d->m_person) {
        disconnect(d->m_person, SIGNAL(dataChanged()), this, SLOT(reload()));
    }

    d->m_person = person;
    connect(d->m_person, SIGNAL(dataChanged()), this, SLOT(reload()));
    reload();
}

// void PersonDetailsView::setPersonsModel(PersonsModel *model)
// {
//     Q_D(PersonDetailsView);
//     Q_FOREACH (AbstractPersonDetailsWidget *detailsWidget, d->m_detailWidgets) {
//         detailsWidget->setPersonsModel(model);
//     }
// }

void PersonDetailsView::reload()
{
    Q_D(PersonDetailsView);

    //delete everything currently in the layout
    QLayoutItem *child;
    while ((child = layout()->takeAt(0)) != 0) {
        delete child->widget();
        delete child;
    }

    Q_FOREACH(AbstractFieldWidgetFactory *widgetFactory, d->m_plugins) {
        const QString label = widgetFactory->label() + ':';
        QWidget *widget = widgetFactory->createDetailsWidget(d->m_person->person(), this);

        if (widget) {
            QFont font = widget->font();
            font.setBold(true);
            widget->setFont(font);
            QLabel *widgetLabel = new QLabel(label, this);
            d->m_mainLayout->addRow(widgetLabel, widget);
        }
    }
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2017 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/debugging.h"

#include <cstdarg>
#include <signal.h>

#include "xenia/base/string_buffer.h"

namespace xe {
namespace debugging {

bool IsDebuggerAttached() { return false; }
void Break() { raise(SIGTRAP); }

void DebugPrint(const char* fmt, ...) {
  StringBuffer buff;

  va_list va;
  va_start(va, fmt);
  buff.AppendVarargs(fmt, va);
  va_end(va);

  // OutputDebugStringA(buff.GetString());
}

}  // namespace debugging
}  // namespace xe
<commit_msg>Fix Travis :|<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2017 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/debugging.h"

#include <signal.h>
#include <cstdarg>

#include "xenia/base/string_buffer.h"

namespace xe {
namespace debugging {

bool IsDebuggerAttached() { return false; }
void Break() { raise(SIGTRAP); }

void DebugPrint(const char* fmt, ...) {
  StringBuffer buff;

  va_list va;
  va_start(va, fmt);
  buff.AppendVarargs(fmt, va);
  va_end(va);

  // OutputDebugStringA(buff.GetString());
}

}  // namespace debugging
}  // namespace xe
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_TO_COMPLEX_HPP
#define STAN_MATH_PRIM_FUN_TO_COMPLEX_HPP

#include <stan/math/prim/meta.hpp>
#include <complex>

namespace stan {
namespace math {

/**
 * Return the real part of the complex argument.
 *
 * @return a complex type with real and imaginary set to 0
 */
std::complex<double> to_complex(){
    return std::complex<double>(0, 0);
}

/**
 * Return the real part of the complex argument.
 *
 * @tparam T value type of argument
 * @param[in] re real value argument
 * @param[in] im imaginary value argument
 * @return complex type with real value set to re and imaginary
 *         set im or 0 if no second argument is supplied
 */
template <typename T>
std::complex<T> to_complex(const T& re, const T& im = 0){
    return std::complex<T>(re, im);
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>Added inline keyword<commit_after>#ifndef STAN_MATH_PRIM_FUN_TO_COMPLEX_HPP
#define STAN_MATH_PRIM_FUN_TO_COMPLEX_HPP

#include <stan/math/prim/meta.hpp>
#include <complex>

namespace stan {
namespace math {

/**
 * Return the real part of the complex argument.
 *
 * @return a complex type with real and imaginary set to 0
 */
inline std::complex<double> to_complex(){
    return std::complex<double>(0, 0);
}

/**
 * Return the real part of the complex argument.
 *
 * @tparam T value type of argument
 * @param[in] re real value argument
 * @param[in] im imaginary value argument
 * @return complex type with real value set to re and imaginary
 *         set im or 0 if no second argument is supplied
 */
template <typename T>
inline std::complex<T> to_complex(const T& re, const T& im = 0){
    return std::complex<T>(re, im);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUNCTOR_ODE_BDF_HPP
#define STAN_MATH_REV_FUNCTOR_ODE_BDF_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/functor/cvodes_integrator.hpp>
#include <ostream>
#include <vector>

namespace stan {
namespace math {

/**
 * Solve the ODE initial value problem y' = f(t, y), y(t0) = y0 at a set of
 * times, { t1, t2, t3, ... } using the stiff backward differentiation formula
 * BDF solver from CVODES.
 *
 * \p f must define an operator() with the signature as:
 *   template<typename T_t, typename T_y, typename... T_Args>
 *   Eigen::Matrix<stan::return_type_t<T_t, T_y, T_Args...>, Eigen::Dynamic, 1>
 *     operator()(const T_t& t, const Eigen::Matrix<T_y, Eigen::Dynamic, 1>& y,
 *     std::ostream* msgs, const T_Args&... args);
 *
 * t is the time, y is the state, msgs is a stream for error messages, and args
 * are optional arguments passed to the ODE solve function (which are passed
 * through to \p f without modification).
 *
 * @tparam F Type of ODE right hand side
 * @tparam T_0 Type of initial time
 * @tparam T_ts Type of output times
 * @tparam T_Args Types of pass-through parameters
 *
 * @param f Right hand side of the ODE
 * @param y0 Initial state
 * @param t0 Initial time
 * @param ts Times at which to solve the ODE at. All values must be sorted and
 *   not less than t0.
 * @param relative_tolerance Relative tolerance passed to CVODES
 * @param absolute_tolerance Absolute tolerance passed to CVODES
 * @param max_num_steps Upper limit on the number of integration steps to
 *   take between each output (error if exceeded)
 * @param[in, out] msgs the print stream for warning messages
 * @param args Extra arguments passed unmodified through to ODE right hand side
 * @return Solution to ODE at times \p ts
 */
template <typename F, typename T_initial, typename T_t0, typename T_ts,
          typename... T_Args>
std::vector<Eigen::Matrix<stan::return_type_t<T_initial, T_t0, T_ts, T_Args...>,
                          Eigen::Dynamic, 1>>
ode_bdf_tol(const F& f, const Eigen::Matrix<T_initial, Eigen::Dynamic, 1>& y0,
            const T_t0& t0, const std::vector<T_ts>& ts,
            double relative_tolerance, double absolute_tolerance,
            long int max_num_steps, std::ostream* msgs, const T_Args&... args) {
  cvodes_integrator<CV_BDF, F, T_initial, T_t0, T_ts,
		    T_Args...> integrator(f, y0, t0, ts,
					  relative_tolerance, absolute_tolerance,
					  max_num_steps,
					  msgs, args...);

  return integrator();
}

/**
 * Solve the ODE initial value problem y' = f(t, y), y(t0) = y0 at a set of
 * times, { t1, t2, t3, ... } using the stiff backward differentiation formula
 * (BDF) solver in CVODES with a relative tolerance of 1e-10, an absolute
 * tolerance of 1e-10, and taking a maximum of 1e8 steps.
 *
 * \p f must define an operator() with the signature as:
 *   template<typename T_t, typename T_y, typename... T_Args>
 *   Eigen::Matrix<stan::return_type_t<T_t, T_y, T_Args...>, Eigen::Dynamic, 1>
 *     operator()(const T_t& t, const Eigen::Matrix<T_y, Eigen::Dynamic, 1>& y,
 *     std::ostream* msgs, const T_Args&... args);
 *
 * t is the time, y is the state, msgs is a stream for error messages, and args
 * are optional arguments passed to the ODE solve function (which are passed
 * through to \p f without modification).
 *
 * @tparam F Type of ODE right hand side
 * @tparam T_0 Type of initial time
 * @tparam T_ts Type of output times
 * @tparam T_Args Types of pass-through parameters
 *
 * @param f Right hand side of the ODE
 * @param y0 Initial state
 * @param t0 Initial time
 * @param ts Times at which to solve the ODE at. All values must be sorted and
 *   not less than t0.
 * @param relative_tolerance Relative tolerance passed to CVODES
 * @param absolute_tolerance Absolute tolerance passed to CVODES
 * @param max_num_steps Upper limit on the number of integration steps to
 *   take between each output (error if exceeded)
 * @param[in, out] msgs the print stream for warning messages
 * @param args Extra arguments passed unmodified through to ODE right hand side
 * @return Solution to ODE at times \p ts
 */
template <typename F, typename T_initial, typename T_t0, typename T_ts,
          typename... T_Args>
std::vector<Eigen::Matrix<stan::return_type_t<T_initial, T_t0, T_ts, T_Args...>,
                          Eigen::Dynamic, 1>>
ode_bdf(const F& f, const Eigen::Matrix<T_initial, Eigen::Dynamic, 1>& y0,
        const T_t0& t0, const std::vector<T_ts>& ts, std::ostream* msgs,
        const T_Args&... args) {
  double relative_tolerance = 1e-10;
  double absolute_tolerance = 1e-10;
  long int max_num_steps = 1e8;

  return ode_bdf_tol(f, y0, t0, ts, relative_tolerance, absolute_tolerance,
                     max_num_steps, msgs, args...);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)<commit_after>#ifndef STAN_MATH_REV_FUNCTOR_ODE_BDF_HPP
#define STAN_MATH_REV_FUNCTOR_ODE_BDF_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/functor/cvodes_integrator.hpp>
#include <ostream>
#include <vector>

namespace stan {
namespace math {

/**
 * Solve the ODE initial value problem y' = f(t, y), y(t0) = y0 at a set of
 * times, { t1, t2, t3, ... } using the stiff backward differentiation formula
 * BDF solver from CVODES.
 *
 * \p f must define an operator() with the signature as:
 *   template<typename T_t, typename T_y, typename... T_Args>
 *   Eigen::Matrix<stan::return_type_t<T_t, T_y, T_Args...>, Eigen::Dynamic, 1>
 *     operator()(const T_t& t, const Eigen::Matrix<T_y, Eigen::Dynamic, 1>& y,
 *     std::ostream* msgs, const T_Args&... args);
 *
 * t is the time, y is the state, msgs is a stream for error messages, and args
 * are optional arguments passed to the ODE solve function (which are passed
 * through to \p f without modification).
 *
 * @tparam F Type of ODE right hand side
 * @tparam T_0 Type of initial time
 * @tparam T_ts Type of output times
 * @tparam T_Args Types of pass-through parameters
 *
 * @param f Right hand side of the ODE
 * @param y0 Initial state
 * @param t0 Initial time
 * @param ts Times at which to solve the ODE at. All values must be sorted and
 *   not less than t0.
 * @param relative_tolerance Relative tolerance passed to CVODES
 * @param absolute_tolerance Absolute tolerance passed to CVODES
 * @param max_num_steps Upper limit on the number of integration steps to
 *   take between each output (error if exceeded)
 * @param[in, out] msgs the print stream for warning messages
 * @param args Extra arguments passed unmodified through to ODE right hand side
 * @return Solution to ODE at times \p ts
 */
template <typename F, typename T_initial, typename T_t0, typename T_ts,
          typename... T_Args>
std::vector<Eigen::Matrix<stan::return_type_t<T_initial, T_t0, T_ts, T_Args...>,
                          Eigen::Dynamic, 1>>
ode_bdf_tol(const F& f, const Eigen::Matrix<T_initial, Eigen::Dynamic, 1>& y0,
            const T_t0& t0, const std::vector<T_ts>& ts,
            double relative_tolerance, double absolute_tolerance,
            long int max_num_steps, std::ostream* msgs, const T_Args&... args) {
  cvodes_integrator<CV_BDF, F, T_initial, T_t0, T_ts, T_Args...> integrator(
      f, y0, t0, ts, relative_tolerance, absolute_tolerance, max_num_steps,
      msgs, args...);

  return integrator();
}

/**
 * Solve the ODE initial value problem y' = f(t, y), y(t0) = y0 at a set of
 * times, { t1, t2, t3, ... } using the stiff backward differentiation formula
 * (BDF) solver in CVODES with a relative tolerance of 1e-10, an absolute
 * tolerance of 1e-10, and taking a maximum of 1e8 steps.
 *
 * \p f must define an operator() with the signature as:
 *   template<typename T_t, typename T_y, typename... T_Args>
 *   Eigen::Matrix<stan::return_type_t<T_t, T_y, T_Args...>, Eigen::Dynamic, 1>
 *     operator()(const T_t& t, const Eigen::Matrix<T_y, Eigen::Dynamic, 1>& y,
 *     std::ostream* msgs, const T_Args&... args);
 *
 * t is the time, y is the state, msgs is a stream for error messages, and args
 * are optional arguments passed to the ODE solve function (which are passed
 * through to \p f without modification).
 *
 * @tparam F Type of ODE right hand side
 * @tparam T_0 Type of initial time
 * @tparam T_ts Type of output times
 * @tparam T_Args Types of pass-through parameters
 *
 * @param f Right hand side of the ODE
 * @param y0 Initial state
 * @param t0 Initial time
 * @param ts Times at which to solve the ODE at. All values must be sorted and
 *   not less than t0.
 * @param relative_tolerance Relative tolerance passed to CVODES
 * @param absolute_tolerance Absolute tolerance passed to CVODES
 * @param max_num_steps Upper limit on the number of integration steps to
 *   take between each output (error if exceeded)
 * @param[in, out] msgs the print stream for warning messages
 * @param args Extra arguments passed unmodified through to ODE right hand side
 * @return Solution to ODE at times \p ts
 */
template <typename F, typename T_initial, typename T_t0, typename T_ts,
          typename... T_Args>
std::vector<Eigen::Matrix<stan::return_type_t<T_initial, T_t0, T_ts, T_Args...>,
                          Eigen::Dynamic, 1>>
ode_bdf(const F& f, const Eigen::Matrix<T_initial, Eigen::Dynamic, 1>& y0,
        const T_t0& t0, const std::vector<T_ts>& ts, std::ostream* msgs,
        const T_Args&... args) {
  double relative_tolerance = 1e-10;
  double absolute_tolerance = 1e-10;
  long int max_num_steps = 1e8;

  return ode_bdf_tol(f, y0, t0, ts, relative_tolerance, absolute_tolerance,
                     max_num_steps, msgs, args...);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2004  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <iomanip>
#include <fstream>

// Local includes
#include "mesh.h"
#include "libmesh_config.h"
#include "medit_io.h"

// ------------------------------------------------------------
// MEDITIO  members
void MEDITIO::write (const std::string& fname)
{
  if (libMesh::processor_id() == 0)
    if (!this->binary())
      this->write_ascii  (fname);
}

void MEDITIO::write_nodal_data (const std::string& fname,
			      const std::vector<Number>& soln,
			      const std::vector<std::string>& names)
{
  if (libMesh::processor_id() == 0)
    if (!this->binary())
      this->write_ascii  (fname, &soln, &names);
}

void MEDITIO::write_ascii (const std::string& fname,
			   const std::vector<Number>* vec,
			   const std::vector<std::string>* solution_names)
{
  // Current lacks in implementation:
  //  (i)   only 3D meshes.
  //  (ii)  only QUAD4, TRI3, TET4 elements, others are omitted !
  //  (iii) no distinction between materials.
  //  (iv)  no vector output, just first scalar as output

  // assert three dimensions (should be extended later)
  assert (this->cmesh().mesh_dimension() == 3);

  // Open the output file stream
  std::ofstream out (fname.c_str());

  assert (out.good());

  // Get a reference to the mesh
  const MeshBase& mesh = this->cmesh();

  // Begin interfacing with the MEdit data file
  {
    // header:
    out << "MeshVersionFormatted  1\n";
    out << "Dimension  3\n";
    out << "# Mesh generated by libmesh\n\n";

    // write the nodes:
    out << "# Set of mesh vertices\n";
    out << "Vertices\n";
    out << mesh.n_nodes() << "\n";

    for (unsigned int v=0; v<mesh.n_nodes(); v++)
      out << mesh.point(v)(0) << " " << mesh.point(v)(1) << " " << mesh.point(v)(2) << " 0\n";
  }

  {
    // write the connectivity:
    out << "\n# Set of Polys\n\n";

    // count occurrences of output elements:
    int n_tri3  = 0;
    int n_quad4 = 0;
    int n_tet4  = 0;

    const_active_elem_iterator       it (mesh.elements_begin());
    const const_active_elem_iterator end(mesh.elements_end());

    for ( ; it != end; ++it) {
      if ((*it)->type() == TRI3)  n_tri3++;
      if ((*it)->type() == QUAD4) n_quad4++;
      if ((*it)->type() == QUAD9) n_quad4+=4; // (QUAD9 is written as 4 QUAD4.)
      if ((*it)->type() == TET4)  n_tet4++;
    } // for

    // First: write out TRI3 elements:
    out << "Triangles\n";
    out << n_tri3 << "\n";

    for (it=mesh.elements_begin() ; it != end; ++it)
      if ((*it)->type() == TRI3) {
	out << (*it)->node(0)+1  << " " << (*it)->node(1)+1  << " " << (*it)->node(2)+1  << " 0\n";
      } // if

    // Second: write out QUAD4 elements:
    out << "Quadrilaterals\n";
    out << n_quad4 << "\n";

    for (it=mesh.elements_begin() ; it != end; ++it)
      if ((*it)->type() == QUAD4) {
	out << (*it)->node(0)+1  << " "
	    << (*it)->node(1)+1  << " "
	    << (*it)->node(2)+1  << " "
	    << (*it)->node(3)+1  <<" 0\n";
      } // if
      else if ((*it)->type() == QUAD9) {
	out << (*it)->node(0)+1  << " "
	    << (*it)->node(4)+1  << " "
	    << (*it)->node(8)+1  << " "
	    << (*it)->node(7)+1  <<" 0\n";
	out << (*it)->node(7)+1  << " "
	    << (*it)->node(8)+1  << " "
	    << (*it)->node(6)+1  << " "
	    << (*it)->node(3)+1  <<" 0\n";
	out << (*it)->node(4)+1  << " "
	    << (*it)->node(1)+1  << " "
	    << (*it)->node(5)+1  << " "
	    << (*it)->node(8)+1  <<" 0\n";
	out << (*it)->node(8)+1  << " "
	    << (*it)->node(5)+1  << " "
	    << (*it)->node(2)+1  << " "
	    << (*it)->node(6)+1  <<" 0\n";
      } // if

    // Third: write out TET4 elements:
    out << "Tetrahedra\n";
    out << n_tet4 << "\n";

    for (it=mesh.elements_begin() ; it != end; ++it)
      if ((*it)->type() == TET4) {
	out << (*it)->node(0)+1  << " "
	    << (*it)->node(1)+1  << " "
	    << (*it)->node(2)+1  << " "
	    << (*it)->node(3)+1  <<" 0\n";
      } // if
  }
  // end of the out file
  out << std::endl << "# end of file" << std::endl;

  // optionally write the data
  if ((solution_names != NULL) &&
      (vec != NULL))
    {
      // Open the ".bb" file stream
      int idx = fname.find_last_of(".");
      std::string bbname = fname.substr(0,idx) + ".bb";

      std::ofstream bbout (bbname.c_str());
      assert (bbout.good());

      // Header: 3: 3D mesh, 1: scalar output, 2: node-indexed
      const unsigned int n_vars = solution_names->size();
      bbout << "3 1 " << mesh.n_nodes() << " 2\n";
      for (unsigned int n=0; n<mesh.n_nodes(); n++)
	bbout << std::setprecision(10) << (*vec)[n*n_vars + scalar_idx] << " ";
      bbout << "\n";
    } // endif
}

<commit_msg>Fixed op= bug which should never have compiled.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2004  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <iomanip>
#include <fstream>

// Local includes
#include "mesh.h"
#include "libmesh_config.h"
#include "medit_io.h"

// ------------------------------------------------------------
// MEDITIO  members
void MEDITIO::write (const std::string& fname)
{
  if (libMesh::processor_id() == 0)
    if (!this->binary())
      this->write_ascii  (fname);
}

void MEDITIO::write_nodal_data (const std::string& fname,
			      const std::vector<Number>& soln,
			      const std::vector<std::string>& names)
{
  if (libMesh::processor_id() == 0)
    if (!this->binary())
      this->write_ascii  (fname, &soln, &names);
}

void MEDITIO::write_ascii (const std::string& fname,
			   const std::vector<Number>* vec,
			   const std::vector<std::string>* solution_names)
{
  // Current lacks in implementation:
  //  (i)   only 3D meshes.
  //  (ii)  only QUAD4, TRI3, TET4 elements, others are omitted !
  //  (iii) no distinction between materials.
  //  (iv)  no vector output, just first scalar as output

  // assert three dimensions (should be extended later)
  assert (this->cmesh().mesh_dimension() == 3);

  // Open the output file stream
  std::ofstream out (fname.c_str());

  assert (out.good());

  // Get a reference to the mesh
  const MeshBase& mesh = this->cmesh();

  // Begin interfacing with the MEdit data file
  {
    // header:
    out << "MeshVersionFormatted  1\n";
    out << "Dimension  3\n";
    out << "# Mesh generated by libmesh\n\n";

    // write the nodes:
    out << "# Set of mesh vertices\n";
    out << "Vertices\n";
    out << mesh.n_nodes() << "\n";

    for (unsigned int v=0; v<mesh.n_nodes(); v++)
      out << mesh.point(v)(0) << " " << mesh.point(v)(1) << " " << mesh.point(v)(2) << " 0\n";
  }

  {
    // write the connectivity:
    out << "\n# Set of Polys\n\n";

    // count occurrences of output elements:
    int n_tri3  = 0;
    int n_quad4 = 0;
    int n_tet4  = 0;

    {
      const_active_elem_iterator       it (mesh.elements_begin());
      const const_active_elem_iterator end(mesh.elements_end());

      for ( ; it != end; ++it)
	{
	  if ((*it)->type() == TRI3)  n_tri3++;
	  if ((*it)->type() == QUAD4) n_quad4++;
	  if ((*it)->type() == QUAD9) n_quad4+=4; // (QUAD9 is written as 4 QUAD4.)
	  if ((*it)->type() == TET4)  n_tet4++;
	} // for
    }

    // First: write out TRI3 elements:
    out << "Triangles\n";
    out << n_tri3 << "\n";

    {
      const_active_elem_iterator       it (mesh.elements_begin());
      const const_active_elem_iterator end(mesh.elements_end());

      for ( ; it != end; ++it)
	if ((*it)->type() == TRI3)
	  out << (*it)->node(0)+1  << " " << (*it)->node(1)+1  << " " << (*it)->node(2)+1  << " 0\n";
    }

    // Second: write out QUAD4 elements:
    out << "Quadrilaterals\n";
    out << n_quad4 << "\n";

    {
      const_active_elem_iterator       it (mesh.elements_begin());
      const const_active_elem_iterator end(mesh.elements_end());

      for ( ; it != end; ++it)
	if ((*it)->type() == QUAD4)
	  {
	    out << (*it)->node(0)+1  << " "
		<< (*it)->node(1)+1  << " "
		<< (*it)->node(2)+1  << " "
		<< (*it)->node(3)+1  <<" 0\n";
	  } // if
	else if ((*it)->type() == QUAD9)
	  {
	    out << (*it)->node(0)+1  << " "
		<< (*it)->node(4)+1  << " "
		<< (*it)->node(8)+1  << " "
		<< (*it)->node(7)+1  <<" 0\n";
	    out << (*it)->node(7)+1  << " "
		<< (*it)->node(8)+1  << " "
		<< (*it)->node(6)+1  << " "
		<< (*it)->node(3)+1  <<" 0\n";
	    out << (*it)->node(4)+1  << " "
		<< (*it)->node(1)+1  << " "
		<< (*it)->node(5)+1  << " "
		<< (*it)->node(8)+1  <<" 0\n";
	    out << (*it)->node(8)+1  << " "
		<< (*it)->node(5)+1  << " "
		<< (*it)->node(2)+1  << " "
		<< (*it)->node(6)+1  <<" 0\n";
	  } // if
    }

    // Third: write out TET4 elements:
    out << "Tetrahedra\n";
    out << n_tet4 << "\n";

    {
      const_active_elem_iterator       it (mesh.elements_begin());
      const const_active_elem_iterator end(mesh.elements_end());

      for ( ; it != end; ++it)
	if ((*it)->type() == TET4)
	  {
	    out << (*it)->node(0)+1  << " "
		<< (*it)->node(1)+1  << " "
		<< (*it)->node(2)+1  << " "
		<< (*it)->node(3)+1  <<" 0\n";
	  } // if
    }

  }
  // end of the out file
  out << std::endl << "# end of file" << std::endl;

  // optionally write the data
  if ((solution_names != NULL) &&
      (vec != NULL))
    {
      // Open the ".bb" file stream
      int idx = fname.find_last_of(".");
      std::string bbname = fname.substr(0,idx) + ".bb";

      std::ofstream bbout (bbname.c_str());
      assert (bbout.good());

      // Header: 3: 3D mesh, 1: scalar output, 2: node-indexed
      const unsigned int n_vars = solution_names->size();
      bbout << "3 1 " << mesh.n_nodes() << " 2\n";
      for (unsigned int n=0; n<mesh.n_nodes(); n++)
	bbout << std::setprecision(10) << (*vec)[n*n_vars + scalar_idx] << " ";
      bbout << "\n";
    } // endif
}

<|endoftext|>


<commit_before>//*****************************************************************************
// Copyright 2017-2019 Intel Corporation
//
// 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.
//*****************************************************************************

#pragma once

#include <chrono>
#include <cmath>
#include <cstdlib> // llvm 8.1 gets confused about `malloc` otherwise
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <vector>

#include "ngraph/axis_vector.hpp"
#include "ngraph/graph_util.hpp"
#include "ngraph/node.hpp"
#include "ngraph/shape.hpp"

namespace ngraph
{
    class Node;
    class Function;
    class stopwatch;

    namespace runtime
    {
        class Backend;
        class Value;
    }

    std::string to_cplusplus_sourcecode_literal(bool val);

    template <typename T>
    std::string join(const T& v, const std::string& sep = ", ")
    {
        std::ostringstream ss;
        size_t count = 0;
        for (const auto& x : v)
        {
            if (count++ > 0)
            {
                ss << sep;
            }
            ss << x;
        }
        return ss.str();
    }

    template <typename T>
    std::string vector_to_string(const T& v)
    {
        std::ostringstream os;
        os << "[ " << ngraph::join(v) << " ]";
        return os.str();
    }

    size_t hash_combine(const std::vector<size_t>& list);
    void dump(std::ostream& out, const void*, size_t);

    std::string to_lower(const std::string& s);
    std::string to_upper(const std::string& s);
    std::string trim(const std::string& s);
    std::vector<std::string> split(const std::string& s, char delimiter, bool trim = false);
    template <typename T>
    std::string locale_string(T x)
    {
        std::stringstream ss;
        ss.imbue(std::locale(""));
        ss << x;
        return ss.str();
    }

    class stopwatch
    {
    public:
        void start()
        {
            if (m_active == false)
            {
                m_total_count++;
                m_active = true;
                m_start_time = m_clock.now();
            }
        }

        void stop()
        {
            if (m_active == true)
            {
                auto end_time = m_clock.now();
                m_last_time = end_time - m_start_time;
                m_total_time += m_last_time;
                m_active = false;
            }
        }

        size_t get_call_count() const;
        size_t get_seconds() const;
        size_t get_milliseconds() const;
        size_t get_microseconds() const;
        std::chrono::nanoseconds get_timer_value() const;
        size_t get_nanoseconds() const;

        size_t get_total_seconds() const;
        size_t get_total_milliseconds() const;
        size_t get_total_microseconds() const;
        size_t get_total_nanoseconds() const;

    private:
        std::chrono::high_resolution_clock m_clock;
        std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
        bool m_active = false;
        std::chrono::nanoseconds m_total_time =
            std::chrono::high_resolution_clock::duration::zero();
        std::chrono::nanoseconds m_last_time = std::chrono::high_resolution_clock::duration::zero();
        size_t m_total_count = 0;
    };

    /// Parses a string containing a literal of the underlying type.
    template <typename T>
    T parse_string(const std::string& s)
    {
        T result;
        std::stringstream ss;

        ss << s;
        ss >> result;

        // Check that (1) parsing succeeded and (2) the entire string was used.
        if (ss.fail() || ss.rdbuf()->in_avail() != 0)
        {
            throw std::runtime_error("Could not parse literal '" + s + "'");
        }

        return result;
    }

    /// template specializations for float and double to handle INFINITY, -INFINITY
    /// and NaN values.
    template <>
    float parse_string<float>(const std::string& s);
    template <>
    double parse_string<double>(const std::string& s);

    /// Parses a list of strings containing literals of the underlying type.
    template <typename T>
    std::vector<T> parse_string(const std::vector<std::string>& ss)
    {
        std::vector<T> result;

        for (auto s : ss)
        {
            result.push_back(parse_string<T>(s));
        }

        return result;
    }

    template <typename T>
    T ceil_div(const T& x, const T& y)
    {
        return (x == 0 ? 0 : (1 + (x - 1) / y));
    }

    template <typename T>
    T subtract_or_zero(T x, T y)
    {
        return y > x ? 0 : x - y;
    }

    void check_fp_values_isinf(const char* name, const float* array, size_t n);
    void check_fp_values_isinf(const char* name, const double* array, size_t n);
    void check_fp_values_isnan(const char* name, const float* array, size_t n);
    void check_fp_values_isnan(const char* name, const double* array, size_t n);

    void* ngraph_malloc(size_t size);
    void ngraph_free(void*);

    size_t round_up(size_t size, size_t alignment);
    bool is_valid_permutation(ngraph::AxisVector permutation, ngraph::Rank rank = Rank::dynamic());
    template <typename T>
    T apply_permutation(T input, ngraph::AxisVector order);

    AxisVector get_default_order(size_t rank);
    AxisVector get_default_order(const Shape& shape);

    AxisVector get_permutation_to_default_order(const AxisVector& axis_order);

    //
    // Return type struct for cache_fprop, with the modified fprop and bprop
    // functions
    // and a list of the nodes that have been appended to fprop output/bprop
    // input
    //
    struct FpropCache
    {
        std::shared_ptr<Function> fprop;
        std::shared_ptr<Function> bprop;
        std::vector<Node*> fprop_output_nodes;
        NodeMap node_param_map;
    };

    //
    // This utility takes forward-propogation and back-propagation functions
    // and turns them into clone functions where the intermediate values of
    // the forward prop are added to the output of fprop and the input of the bprop
    // to avoid repeat calculations.
    // The last argument is the adjoints coming into the bprop function, the output
    // bprop function will have these nodes as the first N input parameters
    //
    FpropCache cache_fprop(std::shared_ptr<Function> fprop, std::shared_ptr<Function> bprop);

    // NodeExecutors are used in compiler optimization passes like ConstantFolding to execute a node
    // using the supplied input and output memory locations.
    // A BuildNodeExecutor returns a backend-specific NodeExecutor for a given Node type
    using NodeExecutorTy =
        std::function<void(const std::vector<void*>& inputs, std::vector<void*>& outputs)>;
    using BuildNodeExecutor = std::function<NodeExecutorTy(const ngraph::Node*)>;

    using BuildNodeExecutorMap = std::unordered_map<std::type_index, BuildNodeExecutor>;

    enum class TensorRole
    {
        INPUT,
        CONSTANT,
        OUTPUT,
        INTERMEDIATE,
        UNKNOWN
    };

    //
    // EnumMask is intended to work with a scoped enum type. It's used to store
    // a combination of enum values and provides easy access and manipulation
    // of these enum values as a mask.
    //
    // EnumMask does not provide a set_all() or invert() operator because they
    // could do things unexpected by the user, i.e. for enum with 4 bit values,
    // invert(001000...) != 110100..., due to the extra bits.
    //
    template <typename T>
    class EnumMask
    {
    public:
        /// Make sure the template type is an enum.
        static_assert(std::is_enum<T>::value, "EnumMask template type must be an enum");
        /// Extract the underlying type of the enum.
        typedef typename std::underlying_type<T>::type value_type;
        /// Some bit operations are not safe for signed values, we require enum
        /// type to use unsigned underlying type.
        static_assert(std::is_unsigned<value_type>::value, "EnumMask enum must use unsigned type.");

        constexpr EnumMask()
            : m_value{0}
        {
        }
        constexpr EnumMask(const T& enum_value)
            : m_value{static_cast<value_type>(enum_value)}
        {
        }
        EnumMask(const EnumMask& other)
            : m_value{other.m_value}
        {
        }
        EnumMask(std::initializer_list<T> enum_values)
            : m_value{0}
        {
            for (auto& v : enum_values)
            {
                m_value |= static_cast<value_type>(v);
            }
        }
        value_type value() const { return m_value; }
        /// Check if any of the input parameter enum bit mask match
        bool is_any_set(const EnumMask& p) const { return m_value & p.m_value; }
        /// Check if all of the input parameter enum bit mask match
        bool is_set(const EnumMask& p) const { return (m_value & p.m_value) == p.m_value; }
        /// Check if any of the input parameter enum bit mask does not match
        bool is_any_clear(const EnumMask& p) const { return !is_set(p); }
        /// Check if all of the input parameter enum bit mask do not match
        bool is_clear(const EnumMask& p) const { return !is_any_set(p); }
        void set(const EnumMask& p) { m_value |= p.m_value; }
        void clear(const EnumMask& p) { m_value &= ~p.m_value; }
        void clear_all() { m_value = 0; }
        bool operator[](const EnumMask& p) const { return is_set(p); }
        bool operator==(const EnumMask& other) const { return m_value == other.m_value; }
        bool operator!=(const EnumMask& other) const { return m_value != other.m_value; }
        EnumMask& operator=(const EnumMask& other)
        {
            m_value = other.m_value;
            return *this;
        }
        EnumMask& operator&=(const EnumMask& other)
        {
            m_value &= other.m_value;
            return *this;
        }

        EnumMask& operator|=(const EnumMask& other)
        {
            m_value |= other.m_value;
            return *this;
        }

        EnumMask operator&(const EnumMask& other) const
        {
            return EnumMask(m_value & other.m_value);
        }

        EnumMask operator|(const EnumMask& other) const
        {
            return EnumMask(m_value | other.m_value);
        }

        friend std::ostream& operator<<(std::ostream& os, const EnumMask& m)
        {
            os << m.m_value;
            return os;
        }

    private:
        /// Only used internally
        explicit EnumMask(const value_type& value)
            : m_value{value}
        {
        }

        value_type m_value;
    };

    /// \brief Function to query parsed version information of the version of ngraph which
    /// contains this function. Version information strictly follows Semantic Versioning
    /// http://semver.org
    /// \param version The major part of the version
    /// \param major Returns the major part of the version
    /// \param minor Returns the minor part of the version
    /// \param patch Returns the patch part of the version
    /// \param extra Returns the extra part of the version. This includes everything following
    /// the patch version number.
    ///
    /// \note Throws a runtime_error if there is an error during parsing
    void parse_version_string(
        std::string version, size_t& major, size_t& minor, size_t& patch, std::string& extra);
} // end namespace ngraph

std::ostream& operator<<(std::ostream& os, const ngraph::NodeVector& nv);
<commit_msg>no_fork: Performance issue vector of string to T (#3542)<commit_after>//*****************************************************************************
// Copyright 2017-2019 Intel Corporation
//
// 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.
//*****************************************************************************

#pragma once

#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdlib> // llvm 8.1 gets confused about `malloc` otherwise
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <vector>
#include "ngraph/axis_vector.hpp"
#include "ngraph/graph_util.hpp"
#include "ngraph/node.hpp"
#include "ngraph/shape.hpp"

namespace ngraph
{
    class Node;
    class Function;
    class stopwatch;

    namespace runtime
    {
        class Backend;
        class Value;
    }

    std::string to_cplusplus_sourcecode_literal(bool val);

    template <typename T>
    std::string join(const T& v, const std::string& sep = ", ")
    {
        std::ostringstream ss;
        size_t count = 0;
        for (const auto& x : v)
        {
            if (count++ > 0)
            {
                ss << sep;
            }
            ss << x;
        }
        return ss.str();
    }

    template <typename T>
    std::string vector_to_string(const T& v)
    {
        std::ostringstream os;
        os << "[ " << ngraph::join(v) << " ]";
        return os.str();
    }

    size_t hash_combine(const std::vector<size_t>& list);
    void dump(std::ostream& out, const void*, size_t);

    std::string to_lower(const std::string& s);
    std::string to_upper(const std::string& s);
    std::string trim(const std::string& s);
    std::vector<std::string> split(const std::string& s, char delimiter, bool trim = false);
    template <typename T>
    std::string locale_string(T x)
    {
        std::stringstream ss;
        ss.imbue(std::locale(""));
        ss << x;
        return ss.str();
    }

    class stopwatch
    {
    public:
        void start()
        {
            if (m_active == false)
            {
                m_total_count++;
                m_active = true;
                m_start_time = m_clock.now();
            }
        }

        void stop()
        {
            if (m_active == true)
            {
                auto end_time = m_clock.now();
                m_last_time = end_time - m_start_time;
                m_total_time += m_last_time;
                m_active = false;
            }
        }

        size_t get_call_count() const;
        size_t get_seconds() const;
        size_t get_milliseconds() const;
        size_t get_microseconds() const;
        std::chrono::nanoseconds get_timer_value() const;
        size_t get_nanoseconds() const;

        size_t get_total_seconds() const;
        size_t get_total_milliseconds() const;
        size_t get_total_microseconds() const;
        size_t get_total_nanoseconds() const;

    private:
        std::chrono::high_resolution_clock m_clock;
        std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
        bool m_active = false;
        std::chrono::nanoseconds m_total_time =
            std::chrono::high_resolution_clock::duration::zero();
        std::chrono::nanoseconds m_last_time = std::chrono::high_resolution_clock::duration::zero();
        size_t m_total_count = 0;
    };

    /// Parses a string containing a literal of the underlying type.
    template <typename T>
    T parse_string(const std::string& s)
    {
        T result;
        std::stringstream ss;

        ss << s;
        ss >> result;

        // Check that (1) parsing succeeded and (2) the entire string was used.
        if (ss.fail() || ss.rdbuf()->in_avail() != 0)
        {
            throw std::runtime_error("Could not parse literal '" + s + "'");
        }

        return result;
    }

    /// template specializations for float and double to handle INFINITY, -INFINITY
    /// and NaN values.
    template <>
    float parse_string<float>(const std::string& s);
    template <>
    double parse_string<double>(const std::string& s);

    /// Parses a list of strings containing literals of the underlying type.
    template <typename T>
    std::vector<T> parse_string(const std::vector<std::string>& ss)
    {
        std::vector<T> result(ss.size());
        std::transform(ss.begin(), ss.end(), result.begin(), [](const std::string& s) {
            return parse_string<T>(s);
        });
        return result;
    }

    template <typename T>
    T ceil_div(const T& x, const T& y)
    {
        return (x == 0 ? 0 : (1 + (x - 1) / y));
    }

    template <typename T>
    T subtract_or_zero(T x, T y)
    {
        return y > x ? 0 : x - y;
    }

    void check_fp_values_isinf(const char* name, const float* array, size_t n);
    void check_fp_values_isinf(const char* name, const double* array, size_t n);
    void check_fp_values_isnan(const char* name, const float* array, size_t n);
    void check_fp_values_isnan(const char* name, const double* array, size_t n);

    void* ngraph_malloc(size_t size);
    void ngraph_free(void*);

    size_t round_up(size_t size, size_t alignment);
    bool is_valid_permutation(ngraph::AxisVector permutation, ngraph::Rank rank = Rank::dynamic());
    template <typename T>
    T apply_permutation(T input, ngraph::AxisVector order);

    AxisVector get_default_order(size_t rank);
    AxisVector get_default_order(const Shape& shape);

    AxisVector get_permutation_to_default_order(const AxisVector& axis_order);

    //
    // Return type struct for cache_fprop, with the modified fprop and bprop
    // functions
    // and a list of the nodes that have been appended to fprop output/bprop
    // input
    //
    struct FpropCache
    {
        std::shared_ptr<Function> fprop;
        std::shared_ptr<Function> bprop;
        std::vector<Node*> fprop_output_nodes;
        NodeMap node_param_map;
    };

    //
    // This utility takes forward-propogation and back-propagation functions
    // and turns them into clone functions where the intermediate values of
    // the forward prop are added to the output of fprop and the input of the bprop
    // to avoid repeat calculations.
    // The last argument is the adjoints coming into the bprop function, the output
    // bprop function will have these nodes as the first N input parameters
    //
    FpropCache cache_fprop(std::shared_ptr<Function> fprop, std::shared_ptr<Function> bprop);

    // NodeExecutors are used in compiler optimization passes like ConstantFolding to execute a node
    // using the supplied input and output memory locations.
    // A BuildNodeExecutor returns a backend-specific NodeExecutor for a given Node type
    using NodeExecutorTy =
        std::function<void(const std::vector<void*>& inputs, std::vector<void*>& outputs)>;
    using BuildNodeExecutor = std::function<NodeExecutorTy(const ngraph::Node*)>;

    using BuildNodeExecutorMap = std::unordered_map<std::type_index, BuildNodeExecutor>;

    enum class TensorRole
    {
        INPUT,
        CONSTANT,
        OUTPUT,
        INTERMEDIATE,
        UNKNOWN
    };

    //
    // EnumMask is intended to work with a scoped enum type. It's used to store
    // a combination of enum values and provides easy access and manipulation
    // of these enum values as a mask.
    //
    // EnumMask does not provide a set_all() or invert() operator because they
    // could do things unexpected by the user, i.e. for enum with 4 bit values,
    // invert(001000...) != 110100..., due to the extra bits.
    //
    template <typename T>
    class EnumMask
    {
    public:
        /// Make sure the template type is an enum.
        static_assert(std::is_enum<T>::value, "EnumMask template type must be an enum");
        /// Extract the underlying type of the enum.
        typedef typename std::underlying_type<T>::type value_type;
        /// Some bit operations are not safe for signed values, we require enum
        /// type to use unsigned underlying type.
        static_assert(std::is_unsigned<value_type>::value, "EnumMask enum must use unsigned type.");

        constexpr EnumMask()
            : m_value{0}
        {
        }
        constexpr EnumMask(const T& enum_value)
            : m_value{static_cast<value_type>(enum_value)}
        {
        }
        EnumMask(const EnumMask& other)
            : m_value{other.m_value}
        {
        }
        EnumMask(std::initializer_list<T> enum_values)
            : m_value{0}
        {
            for (auto& v : enum_values)
            {
                m_value |= static_cast<value_type>(v);
            }
        }
        value_type value() const { return m_value; }
        /// Check if any of the input parameter enum bit mask match
        bool is_any_set(const EnumMask& p) const { return m_value & p.m_value; }
        /// Check if all of the input parameter enum bit mask match
        bool is_set(const EnumMask& p) const { return (m_value & p.m_value) == p.m_value; }
        /// Check if any of the input parameter enum bit mask does not match
        bool is_any_clear(const EnumMask& p) const { return !is_set(p); }
        /// Check if all of the input parameter enum bit mask do not match
        bool is_clear(const EnumMask& p) const { return !is_any_set(p); }
        void set(const EnumMask& p) { m_value |= p.m_value; }
        void clear(const EnumMask& p) { m_value &= ~p.m_value; }
        void clear_all() { m_value = 0; }
        bool operator[](const EnumMask& p) const { return is_set(p); }
        bool operator==(const EnumMask& other) const { return m_value == other.m_value; }
        bool operator!=(const EnumMask& other) const { return m_value != other.m_value; }
        EnumMask& operator=(const EnumMask& other)
        {
            m_value = other.m_value;
            return *this;
        }
        EnumMask& operator&=(const EnumMask& other)
        {
            m_value &= other.m_value;
            return *this;
        }

        EnumMask& operator|=(const EnumMask& other)
        {
            m_value |= other.m_value;
            return *this;
        }

        EnumMask operator&(const EnumMask& other) const
        {
            return EnumMask(m_value & other.m_value);
        }

        EnumMask operator|(const EnumMask& other) const
        {
            return EnumMask(m_value | other.m_value);
        }

        friend std::ostream& operator<<(std::ostream& os, const EnumMask& m)
        {
            os << m.m_value;
            return os;
        }

    private:
        /// Only used internally
        explicit EnumMask(const value_type& value)
            : m_value{value}
        {
        }

        value_type m_value;
    };

    /// \brief Function to query parsed version information of the version of ngraph which
    /// contains this function. Version information strictly follows Semantic Versioning
    /// http://semver.org
    /// \param version The major part of the version
    /// \param major Returns the major part of the version
    /// \param minor Returns the minor part of the version
    /// \param patch Returns the patch part of the version
    /// \param extra Returns the extra part of the version. This includes everything following
    /// the patch version number.
    ///
    /// \note Throws a runtime_error if there is an error during parsing
    void parse_version_string(
        std::string version, size_t& major, size_t& minor, size_t& patch, std::string& extra);
} // end namespace ngraph

std::ostream& operator<<(std::ostream& os, const ngraph::NodeVector& nv);
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>

#include "parsers/parse_error.hh"
#include "parsers/tina.hh"

namespace pnmc { namespace parsers {

namespace {

/*------------------------------------------------------------------------------------------------*/

unsigned int
value(std::string::const_iterator cit, std::string::const_iterator cend)
{
  std::string s(cit, cend);
  try
  {
    std::size_t pos;
    auto value = std::stoi(s, &pos);
    std::advance(cit, pos);
    if (std::distance(cit, cend) == 1)
    {
      switch (*cit)
      {
        case 'K': value *= 1000; break;
        case 'M': value *= 1000000; break;
        default: throw parse_error("Invalid suffix, got '" + std::string(cit, cend) + "'");
      }
    }
    else if (std::distance(cit, cend) > 1)
    {
      throw parse_error("Invalid suffix, got " + std::string(cit, cend));
    }
    return value;
  }
  catch (const std::invalid_argument&)
  {
    throw parse_error("Expected a value, got " + s);
  }
}

/*------------------------------------------------------------------------------------------------*/

std::pair<std::string, pn::arc>
place_arc(const std::string& s)
{
  auto pos = s.find_first_of("*?!");
  auto arc_type = pn::arc::type::normal;

  if (pos == std::string::npos)
  {
    return std::make_pair(s, pn::arc{1, arc_type});
  }

  if (pos == s.length() - 1)
  {
    throw parse_error("Valuation expected, got '" + s + "'");
  }

  auto valuation_pos = pos;
  switch (s[pos])
  {
      case '*': break;

      case '?':
      {
        if (s[pos + 1] == '-')
        {
          ++valuation_pos;
          arc_type = pn::arc::type::inhibitor;
        }
        else
        {
          arc_type = pn::arc::type::read;
        }
        break;
      }

      case '!':
      {
        if (s[pos +1] == '-')
        {
          ++valuation_pos;
          arc_type = pn::arc::type::stopwatch_inhibitor;
        }
        else
        {
          arc_type = pn::arc::type::stopwatch;
        }
        break;
      }

      default :
      {
        std::stringstream ss;
        ss << "Expected '*', '?' or '!', got '" << s[pos] << "'";
        throw parse_error(ss.str());
      }
  }

  const auto valuation = value(s.cbegin() + valuation_pos + 1, s.cend());
  return std::make_pair(s.substr(0, pos), pn::arc{valuation, arc_type});
}

/*------------------------------------------------------------------------------------------------*/

unsigned int
marking(const std::string& s)
{
  if (*s.cbegin() == '(' and *std::prev(s.cend()) == ')')
  {
    return value(std::next(s.cbegin()), std::prev(s.cend()));
  }
  else
  {
    throw parse_error("Invalid marking format: " + s);
  }
}

} // namespace anonymous

/*------------------------------------------------------------------------------------------------*/

std::shared_ptr<pn::net>
tina(std::istream& in)
{
  // Known limitations:
  // - there's must be a transition or place per line
  // - labels are ignored
  // - time intervals are not completely validated (e.g. [0, 2a] is wrongly validated

  std::shared_ptr<pn::net> net_ptr = std::make_shared<pn::net>();
  auto& net = *net_ptr;

  std::string line, s0, s1, s2, ignore;
  line.reserve(1024);

  while (std::getline(in, line))
  {
    std::istringstream ss(line);

    // Empty line or comment.
    if (((ss >> std::ws).peek() == std::char_traits<char>::to_int_type('#')) or not (ss >> s0))
    {
      continue;
    }

    // Net
    if (s0 == "net")
    {
      ss >> s0;
      net_ptr->name = s0;
    }

    // Transitions
    else if (s0 == "tr")
    {
      std::string place_id;

      if (ss >> s0)
      {
        net.add_transition(s0);
      }
      else
      {
        throw parse_error("Invalid transition: " + line);
      }

      // Ignore label, if any.
      if ((ss >> std::ws).peek() == std::char_traits<char>::to_int_type(':'))
      {
        ss >> ignore >> ignore; // ':' <label>
      }

      // Time interval.
      const auto peek = (ss >> std::ws).peek();
      if (   peek == std::char_traits<char>::to_int_type('[')
          or peek == std::char_traits<char>::to_int_type(']'))
      {
        s1.clear();

        const bool open_lower_endpoint = ss.get() == ']';
        bool open_upper_endpoint = false;

        while (ss.good())
        {
          auto c = ss.get();
          if (c == '[')
          {
            open_upper_endpoint = true;
            break;
          }
          if (c == ']')
          {
            break;
          }
          s1.push_back(c);
        }

        if (not ss.good())
        {
          throw parse_error("Unexpected end of file. Missing '[' or ']'?");
        }

        std::istringstream ss1(s1);
        std::getline(ss1, s2, ','); // split on ','
        unsigned int first, last;
        try
        {
          first = std::stoi(s2);
        }
        catch (const std::invalid_argument&)
        {
          throw parse_error("Expected a value, got: '" + s2 + "'");
        }
        ss1 >> s2;
        try
        {
          last = std::stoi(s2);
          if ((last < first) or (open_upper_endpoint and first == last))
          {
            throw parse_error( "Invalid time interval '"
                             + (open_lower_endpoint ? std::string("]") : std::string("["))
                             + std::to_string(first) + "," + std::to_string(last)
                             + (open_upper_endpoint ? std::string("[") : std::string("]"))
                             + "'");
          }

          if (open_upper_endpoint)
          {
            last -= 1;
          }
        }
        catch (const std::invalid_argument& e)
        {
          if (s2 == "w")
          {
            last = std::numeric_limits<unsigned int>::max();
          }
          else
          {
            throw parse_error("Expected a value, got: '" + s2 + "'");
          }
        }

        net_ptr->add_time_interval(s0, first, last);
      }

      bool found_arrow = false;
      while (ss >> s1)
      {
        if (s1 == "->")
        {
          found_arrow = true;
          break;
        }
        const auto res = place_arc(s1);
        net.add_pre_place(s0, res.first, res.second);
      }

      if (not found_arrow)
      {
        throw parse_error("Invalid transition (missing '->'): " + line);
      }

      while (ss >> s1)
      {
        const auto res = place_arc(s1);
        net.add_post_place(s0, res.first, res.second);
      }
    }

    // Places
    else if (s0 == "pl")
    {
      if (ss >> s1)
      {
        // Ignore label, if any.
        if ((ss >> std::ws).peek() == std::char_traits<char>::to_int_type(':'))
        {
          ss >> ignore >> ignore; // ':' <label>
        }

        if (ss >> s2)
        {
          net.add_place(s1, marking(s2));
        }
        else
        {
          net.add_place(s1, 0);
        }
      }
      else
      {
        throw parse_error("Invalid place: " + line);
      }
    }

    // Error.
    else
    {
      throw parse_error("Invalid line: " + line);
    }
  }

  return net_ptr;
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::parsers
<commit_msg>Tina parse: check TPN lower endpoint.<commit_after>#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>

#include "parsers/parse_error.hh"
#include "parsers/tina.hh"

namespace pnmc { namespace parsers {

namespace {

/*------------------------------------------------------------------------------------------------*/

unsigned int
value(std::string::const_iterator cit, std::string::const_iterator cend)
{
  std::string s(cit, cend);
  try
  {
    std::size_t pos;
    auto value = std::stoi(s, &pos);
    std::advance(cit, pos);
    if (std::distance(cit, cend) == 1)
    {
      switch (*cit)
      {
        case 'K': value *= 1000; break;
        case 'M': value *= 1000000; break;
        default: throw parse_error("Invalid suffix, got '" + std::string(cit, cend) + "'");
      }
    }
    else if (std::distance(cit, cend) > 1)
    {
      throw parse_error("Invalid suffix, got " + std::string(cit, cend));
    }
    return value;
  }
  catch (const std::invalid_argument&)
  {
    throw parse_error("Expected a value, got " + s);
  }
}

/*------------------------------------------------------------------------------------------------*/

std::pair<std::string, pn::arc>
place_arc(const std::string& s)
{
  auto pos = s.find_first_of("*?!");
  auto arc_type = pn::arc::type::normal;

  if (pos == std::string::npos)
  {
    return std::make_pair(s, pn::arc{1, arc_type});
  }

  if (pos == s.length() - 1)
  {
    throw parse_error("Valuation expected, got '" + s + "'");
  }

  auto valuation_pos = pos;
  switch (s[pos])
  {
      case '*': break;

      case '?':
      {
        if (s[pos + 1] == '-')
        {
          ++valuation_pos;
          arc_type = pn::arc::type::inhibitor;
        }
        else
        {
          arc_type = pn::arc::type::read;
        }
        break;
      }

      case '!':
      {
        if (s[pos +1] == '-')
        {
          ++valuation_pos;
          arc_type = pn::arc::type::stopwatch_inhibitor;
        }
        else
        {
          arc_type = pn::arc::type::stopwatch;
        }
        break;
      }

      default :
      {
        std::stringstream ss;
        ss << "Expected '*', '?' or '!', got '" << s[pos] << "'";
        throw parse_error(ss.str());
      }
  }

  const auto valuation = value(s.cbegin() + valuation_pos + 1, s.cend());
  return std::make_pair(s.substr(0, pos), pn::arc{valuation, arc_type});
}

/*------------------------------------------------------------------------------------------------*/

unsigned int
marking(const std::string& s)
{
  if (*s.cbegin() == '(' and *std::prev(s.cend()) == ')')
  {
    return value(std::next(s.cbegin()), std::prev(s.cend()));
  }
  else
  {
    throw parse_error("Invalid marking format: " + s);
  }
}

} // namespace anonymous

/*------------------------------------------------------------------------------------------------*/

std::shared_ptr<pn::net>
tina(std::istream& in)
{
  // Known limitations:
  // - there's must be a transition or place per line
  // - labels are ignored
  // - time intervals are not completely validated (e.g. [0, 2a] is wrongly validated

  std::shared_ptr<pn::net> net_ptr = std::make_shared<pn::net>();
  auto& net = *net_ptr;

  std::string line, s0, s1, s2, ignore;
  line.reserve(1024);

  while (std::getline(in, line))
  {
    std::istringstream ss(line);

    // Empty line or comment.
    if (((ss >> std::ws).peek() == std::char_traits<char>::to_int_type('#')) or not (ss >> s0))
    {
      continue;
    }

    // Net
    if (s0 == "net")
    {
      ss >> s0;
      net_ptr->name = s0;
    }

    // Transitions
    else if (s0 == "tr")
    {
      std::string place_id;

      if (ss >> s0)
      {
        net.add_transition(s0);
      }
      else
      {
        throw parse_error("Invalid transition: " + line);
      }

      // Ignore label, if any.
      if ((ss >> std::ws).peek() == std::char_traits<char>::to_int_type(':'))
      {
        ss >> ignore >> ignore; // ':' <label>
      }

      // Time interval.
      const auto peek = (ss >> std::ws).peek();
      if (   peek == std::char_traits<char>::to_int_type('[')
          or peek == std::char_traits<char>::to_int_type(']'))
      {
        s1.clear();

        const bool open_lower_endpoint = ss.get() == ']';
        bool open_upper_endpoint = false;

        while (ss.good())
        {
          auto c = ss.get();
          if (c == '[')
          {
            open_upper_endpoint = true;
            break;
          }
          if (c == ']')
          {
            break;
          }
          s1.push_back(c);
        }

        if (not ss.good())
        {
          throw parse_error("Unexpected end of file. Missing '[' or ']'?");
        }

        std::istringstream ss1(s1);
        std::getline(ss1, s2, ','); // split on ','
        unsigned int first, last;
        try
        {
          first = std::stoi(s2);
        }
        catch (const std::invalid_argument&)
        {
          throw parse_error("Expected a value, got: '" + s2 + "'");
        }
        ss1 >> s2;
        try
        {
          last = std::stoi(s2);
          if ((last < first) or ((open_upper_endpoint or open_lower_endpoint) and first == last))
          {
            throw parse_error( "Invalid time interval '"
                             + (open_lower_endpoint ? std::string("]") : std::string("["))
                             + std::to_string(first) + "," + std::to_string(last)
                             + (open_upper_endpoint ? std::string("[") : std::string("]"))
                             + "'");
          }

          if (open_lower_endpoint)
          {
            first += 1;
          }

          if (open_upper_endpoint)
          {
            last -= 1;
          }
        }
        catch (const std::invalid_argument& e)
        {
          if (s2 == "w")
          {
            last = std::numeric_limits<unsigned int>::max();
          }
          else
          {
            throw parse_error("Expected a value, got: '" + s2 + "'");
          }
        }

        net_ptr->add_time_interval(s0, first, last);
      }

      bool found_arrow = false;
      while (ss >> s1)
      {
        if (s1 == "->")
        {
          found_arrow = true;
          break;
        }
        const auto res = place_arc(s1);
        net.add_pre_place(s0, res.first, res.second);
      }

      if (not found_arrow)
      {
        throw parse_error("Invalid transition (missing '->'): " + line);
      }

      while (ss >> s1)
      {
        const auto res = place_arc(s1);
        net.add_post_place(s0, res.first, res.second);
      }
    }

    // Places
    else if (s0 == "pl")
    {
      if (ss >> s1)
      {
        // Ignore label, if any.
        if ((ss >> std::ws).peek() == std::char_traits<char>::to_int_type(':'))
        {
          ss >> ignore >> ignore; // ':' <label>
        }

        if (ss >> s2)
        {
          net.add_place(s1, marking(s2));
        }
        else
        {
          net.add_place(s1, 0);
        }
      }
      else
      {
        throw parse_error("Invalid place: " + line);
      }
    }

    // Error.
    else
    {
      throw parse_error("Invalid line: " + line);
    }
  }

  return net_ptr;
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace pnmc::parsers
<|endoftext|>