text:
/**
   @author Shin'ichiro Nakaoka
*/

#include "ItemPropertyView.h"
#include "ItemTreeView.h"
#include "Item.h"
#include "ItemList.h"
#include "ItemManager.h"
#include "ViewManager.h"
#include "MenuManager.h"
#include "MessageView.h"
#include "PutPropertyFunction.h"
#include "SelectionListEditor.h"
#include "LazyCaller.h"
#include "AppConfig.h"
#include "Archive.h"
#include <cnoid/ConnectionSet>
#include <QTableWidget>
#include <QHeaderView>
#include <QBoxLayout>
#include <QDoubleSpinBox>
#include <QStyledItemDelegate>
#include <QItemEditorFactory>
#include <QStandardItemEditorCreator>
#include <QKeyEvent>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <cmath>
#include <iostream>
#include "gettext.h"

using namespace std;
using namespace cnoid;

namespace {

bool TRACE_FUNCTIONS = false;

struct Int {
    int value;
    int min, max;
    Int(int v){
        value = v;
    };
    Int(int v, int min, int max) {
        value = v;
        this->min = min;
        this->max = max;
    };
};

struct Double {
    double value;
    int decimals;
    double min, max;
    Double(double v, int d) {
        value = v;
        decimals = d;
    };
    Double(double v, int d, double min, double max) {
        value = v;
        decimals = d;
        this->min = min;
        this->max = max;
    };
};

typedef boost::variant<bool, Int, Double, string, Selection> ValueVariant;

typedef boost::variant<boost::function<bool(bool)>,
                       boost::function<bool(int)>,
                       boost::function<bool(double)>,
                       boost::function<bool(const string&)>
                       > FunctionVariant;

template<class ValueType> class ReturnTrue {
public:
    typedef bool result_type;
    boost::function<void(ValueType)> func;
    ReturnTrue(boost::function<void(ValueType)> func) : func(func) { }
    bool operator()(ValueType value) const { func(value); return true; }
};

enum TypeId { TYPE_BOOL, TYPE_INT, TYPE_DOUBLE, TYPE_STRING, TYPE_SELECTION };

struct Property {
    Property(const string& name, ValueVariant value)
        : name(name), value(value), hasValidFunction(false) { }
    Property(const string& name, ValueVariant value, FunctionVariant func)
        : name(name), value(value), func(func), hasValidFunction(true) { }
    string name;
    ValueVariant value;
    FunctionVariant func;
    bool hasValidFunction;
};
typedef boost::shared_ptr<Property> PropertyPtr;

class PropertyItem : public QTableWidgetItem
{
public:
    PropertyItem(ItemPropertyViewImpl* viewImpl, ValueVariant value);
    PropertyItem(ItemPropertyViewImpl* viewImpl, ValueVariant value, FunctionVariant func);

    virtual QVariant data(int role) const;
    virtual void setData(int role, const QVariant& qvalue);

    ItemPropertyViewImpl* itemPropertyViewImpl;
    ValueVariant value;
    FunctionVariant func;
    bool hasValidFunction;
};

class CustomizedTableWidget : public QTableWidget
{
public:
    CustomizedTableWidget(QWidget* parent) : QTableWidget(parent) { }

    PropertyItem* itemFromIndex(const QModelIndex& index) const {
        return dynamic_cast<PropertyItem*>(QTableWidget::itemFromIndex(index));
    }
};

class CustomizedItemDelegate : public QStyledItemDelegate
{
public:
    CustomizedTableWidget* tableWidget;
    int decimals;

    CustomizedItemDelegate(CustomizedTableWidget* tableWidget)
        : tableWidget(tableWidget) { decimals = 2; }

    virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {

        QWidget* editor = QStyledItemDelegate::createEditor(parent, option, index);
        PropertyItem* item = tableWidget->itemFromIndex(index);
        if(item){
            if(QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor)){
                ValueVariant& value = item->value;
                if(value.which() == TYPE_INT){
                    Int& v = boost::get<Int>(value);
                    spinBox->setRange(v.min, v.max);
                }
            } else if(QDoubleSpinBox* doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(editor)){
                ValueVariant& value = item->value;
                if(value.which() == TYPE_DOUBLE){
                    Double& v = boost::get<Double>(value);
                    if(v.decimals >= 0){
                        doubleSpinBox->setDecimals(v.decimals);
                        doubleSpinBox->setSingleStep(pow(10.0, -v.decimals));
                    }
                    doubleSpinBox->setRange(v.min, v.max);
                }
            }
        }
        return editor;
    }

    virtual QString	displayText(const QVariant& value, const QLocale& locale) const {
        if(value.type() == QVariant::Double){
            return QString::number(value.toDouble(), 'f', decimals);
        }
        return QStyledItemDelegate::displayText(value, locale);
    }

    void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {

        PropertyItem* item = tableWidget->itemFromIndex(index);
        if(item && item->value.which() == TYPE_DOUBLE){
            int& d = const_cast<int&>(decimals);
            d = boost::get<Double>(item->value).decimals;
        }
        QStyledItemDelegate::paint(painter, option, index);
    }

};
}

namespace cnoid {

class ItemPropertyViewImpl : public PutPropertyFunction
{
public:
    ItemPropertyViewImpl(ItemPropertyView* self);
    ~ItemPropertyViewImpl();

    ItemPropertyView* self;

    int decimals_;
    double dmin;
    double dmax;
    int imin;
    int imax;

    CustomizedTableWidget* tableWidget;
    int fontPointSizeDiff;

    ItemPtr currentItem;
    ConnectionSet itemConnections;
    int tmpListIndex;

    bool isEditingProperty;
    bool updateRequestedDuringPropertyEditing;

    std::vector<PropertyPtr> properties;

    bool isPressedPathValid;

    Connection selectionChangedConnection;

    // PutPropertyFunction's virtual functions
    PutPropertyFunction& decimals(int d) {
        decimals_ = d;
        return *this;
    }
    PutPropertyFunction& min(double min) {
        dmin = min;
        return *this;
    }
    PutPropertyFunction& max(double max) {
        dmax = max;
        return *this;
    }
    PutPropertyFunction& min(int min){
        imin = min;
        return *this;
    }
    PutPropertyFunction& max(int max){
        imax = max;
        return *this;
    }
    PutPropertyFunction& reset(){
        decimals_ = 2;
        dmin = -std::numeric_limits<double>::max();
        dmax = std::numeric_limits<double>::max();
        imin =std::numeric_limits<int>::min();
        imax= std::numeric_limits<int>::max();
        return *this;
    }

    virtual void operator()(const std::string& name, bool value){
        addProperty(name, new PropertyItem(this, value));
    }
    virtual void operator()(const std::string& name, bool value, const boost::function<bool(bool)>& func) {
        addProperty(name, new PropertyItem(this, value, func));
    }
    virtual void operator()(const std::string& name, bool value,
                            const boost::function<void(bool)>& func, bool forceUpdate) {
        addProperty(name, new PropertyItem
                    (this, value, boost::function<bool(bool)>(ReturnTrue<bool>(func))));
    }
    virtual void operator()(const std::string& name, int value){
        addProperty(name, new PropertyItem(this, Int(value)));
    }
    virtual void operator()(const std::string& name, int value, const boost::function<bool(int)>& func){
        addProperty(name, new PropertyItem(this, Int(value, imin, imax), func));
    }
    virtual void operator()(const std::string& name, int value,
                            const boost::function<void(int)>& func, bool forceUpdate){
        addProperty(name, new PropertyItem(this, Int(value, imin, imax),
                                           boost::function<bool(int)>(ReturnTrue<int>(func))));
    }
    virtual void operator()(const std::string& name, double value){
        addProperty(name, new PropertyItem(this, Double(value, decimals_)));
    }
    virtual void operator()(const std::string& name, double value,
                            const boost::function<bool(double)>& func){
        addProperty(name, new PropertyItem(this, Double(value, decimals_, dmin, dmax), func));
    }
    virtual void operator()(const std::string& name, double value,
                            const boost::function<void(double)>& func, bool forceUpdate){
        addProperty(name, new PropertyItem(this, Double(value, decimals_, dmin, dmax),
                                           boost::function<bool(double)>(ReturnTrue<double>(func))));
    }
    virtual void operator()(const std::string& name, const std::string& value){
        addProperty(name, new PropertyItem(this, value));
    }
    virtual void operator()(const std::string& name, const std::string& value,
                            const boost::function<bool(const std::string&)>& func){
        addProperty(name, new PropertyItem(this, value, func));
    }
    virtual void operator()(const std::string& name, const std::string& value,
                            const boost::function<void(const std::string&)>& func, bool forceUpdate){
        addProperty(name, new PropertyItem
                    (this, value, boost::function<bool(const std::string&)>(ReturnTrue<const std::string&>(func))));
    }
    void operator()(const std::string& name, const Selection& selection){
        addProperty(name, new PropertyItem(this, selection));
    }
    void operator()(const std::string& name, const Selection& selection,
                    const boost::function<bool(int which)>& func){
        addProperty(name, new PropertyItem(this, selection, func));
    }
    void operator()(const std::string& name, const Selection& selection,
                    const boost::function<void(int which)>& func, bool forceUpdate){
        addProperty(name, new PropertyItem
                    (this, selection,  boost::function<bool(int)>(ReturnTrue<int>(func))));
    }

    void clear();
    void updateProperties();
    void addProperty(const std::string& name, PropertyItem* propertyItem);
    void onItemSelectionChanged(const ItemList<>& items);
    void zoomFontSize(int pointSizeDiff);
};
}

PropertyItem::PropertyItem(ItemPropertyViewImpl* viewImpl, ValueVariant value)
    : itemPropertyViewImpl(viewImpl),
      value(value)
{
    setFlags(Qt::ItemIsEnabled);
    hasValidFunction = false;
}

PropertyItem::PropertyItem(ItemPropertyViewImpl* viewImpl, ValueVariant value, FunctionVariant func)
    : itemPropertyViewImpl(viewImpl),
      value(value),
      func(func)
{
    setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable);
    hasValidFunction = true;
}

QVariant PropertyItem::data(int role) const
{
    if(role == Qt::DisplayRole || role == Qt::EditRole){
        switch(value.which()){
        case TYPE_BOOL:      return boost::get<bool>(value);
        case TYPE_INT:       return boost::get<Int>(value).value;
        case TYPE_DOUBLE:    return boost::get<Double>(value).value;
        case TYPE_STRING:    return boost::get<string>(value).c_str();

        case TYPE_SELECTION:
        {
            const Selection& s = boost::get<Selection>(value);
            if(role == Qt::DisplayRole){
                return s.selectedLabel();
            } else if(role == Qt::EditRole){
                QStringList labels;
                labels << QString::number(s.selectedIndex());
                for(int i=0; i < s.size(); ++i){
                    labels << s.label(i);
                }
                return labels;
            }
        }
        }
    }
    return QTableWidgetItem::data(role);
}

void PropertyItem::setData(int role, const QVariant& qvalue)
{
    itemPropertyViewImpl->isEditingProperty = true;
    itemPropertyViewImpl->updateRequestedDuringPropertyEditing = false;

    bool accepted = false;

    if(role == Qt::EditRole){

        try {
            switch(qvalue.type()){

            case QVariant::Bool:
                accepted = boost::get< boost::function<bool(bool)> >(func)(qvalue.toBool());
                break;

            case QVariant::String:
                accepted = boost::get< boost::function<bool(const string&)> >(func)(qvalue.toString().toStdString());
                break;

            case QVariant::Int:
                accepted = boost::get< boost::function<bool(int)> >(func)(qvalue.toInt());
                break;

            case QVariant::Double:
                accepted = boost::get< boost::function<bool(double)> >(func)(qvalue.toDouble());
                break;

            case QVariant::StringList:
            {
                const QStringList& slist = qvalue.toStringList();
                if(!slist.empty()){
                    accepted = boost::get< boost::function<bool(int)> >(func)(slist[0].toInt());
                }
            }
            break;

            default:
                break;
            }

        } catch(const boost::bad_lexical_cast& ex) {

        }

        if(accepted){
            if(!itemPropertyViewImpl->updateRequestedDuringPropertyEditing){
                itemPropertyViewImpl->currentItem->notifyUpdate();
            }
        }
        if(itemPropertyViewImpl->updateRequestedDuringPropertyEditing){
            callLater(boost::bind(&ItemPropertyViewImpl::updateProperties, itemPropertyViewImpl));
        }
    }

    itemPropertyViewImpl->isEditingProperty = false;
}

void ItemPropertyView::initializeClass(ExtensionManager* ext)
{
    ext->viewManager().registerClass<ItemPropertyView>(
        "ItemPropertyView", N_("Property"), ViewManager::SINGLE_DEFAULT);
}

ItemPropertyView::ItemPropertyView()
{
    impl = new ItemPropertyViewImpl(this);
}

ItemPropertyViewImpl::ItemPropertyViewImpl(ItemPropertyView* self)
    : self(self)
{
    self->setDefaultLayoutArea(View::LEFT_BOTTOM);

    isPressedPathValid = false;
    isEditingProperty = false;

    tableWidget = new CustomizedTableWidget(self);
    tableWidget->setFrameShape(QFrame::NoFrame);
    tableWidget->setColumnCount(2);
    tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    tableWidget->setSelectionMode(QAbstractItemView::NoSelection);

    tableWidget->horizontalHeader()->hide();
    tableWidget->horizontalHeader()->setStretchLastSection(true);

    tableWidget->verticalHeader()->hide();
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
    tableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
#else
    tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
#endif

    QStyledItemDelegate* delegate = new CustomizedItemDelegate(tableWidget);
    QItemEditorFactory* factory = new QItemEditorFactory;

    QItemEditorCreatorBase* selectionListCreator =
        new QStandardItemEditorCreator<SelectionListEditor>();
    factory->registerEditor(QVariant::StringList, selectionListCreator);

    delegate->setItemEditorFactory(factory);

    tableWidget->setItemDelegate(delegate);

    QVBoxLayout* vbox = new QVBoxLayout();
    vbox->addWidget(tableWidget);
    self->setLayout(vbox);

    selectionChangedConnection =
        ItemTreeView::mainInstance()->sigSelectionChanged().connect(
            boost::bind(&ItemPropertyViewImpl::onItemSelectionChanged, this, _1));

    fontPointSizeDiff = 0;
    MappingPtr config = AppConfig::archive()->openMapping("ItemPropertyView");
    int storedFontPointSizeDiff;
    if(config->read("fontZoom", storedFontPointSizeDiff)){
        zoomFontSize(storedFontPointSizeDiff);
    }
}

ItemPropertyView::~ItemPropertyView()
{
    if(TRACE_FUNCTIONS){
        cout << "ItemPropertyView::~ItemPropertyView()" << endl;
    }

    delete impl;
}

ItemPropertyViewImpl::~ItemPropertyViewImpl()
{
    if(TRACE_FUNCTIONS){
        cout << "ItemPropertyViewImpl::~ItemPropertyView()Impl" << endl;
    }

    itemConnections.disconnect();
    selectionChangedConnection.disconnect();
}

void ItemPropertyViewImpl::clear()
{
    if(TRACE_FUNCTIONS){
        cout << "ItemPropertyView::clear()" << endl;
    }

    itemConnections.disconnect();
    currentItem = 0;
    updateProperties();
}

void ItemPropertyViewImpl::updateProperties()
{
    if(TRACE_FUNCTIONS){
        cout << "ItemPropertyView::updateProperties()" << endl;
    }

    if(isEditingProperty){
        updateRequestedDuringPropertyEditing = true;

    } else {
        tableWidget->setRowCount(0);
        tmpListIndex = 0;
        properties.clear();
        if(currentItem){
            reset();
            currentItem->putProperties(*this);
        }
    }
}

void ItemPropertyViewImpl::addProperty(const std::string& name, PropertyItem* propertyItem)
{
    int row = tableWidget->rowCount();
    tableWidget->setRowCount(row + 1);

    QTableWidgetItem* nameItem = new QTableWidgetItem(name.c_str());
    nameItem->setFlags(Qt::ItemIsEnabled);
    tableWidget->setItem(row, 0, nameItem);

    tableWidget->setItem(row, 1, propertyItem);
}

void ItemPropertyViewImpl::onItemSelectionChanged(const ItemList<>& items)
{
    if(TRACE_FUNCTIONS){
        cout << "ItemPropertyView::onItemSelectionChanged()" << endl;
    }

    Item* item = items.toSingle();

    if(item != currentItem){
        itemConnections.disconnect();
        currentItem = item;
        if(item){
            itemConnections.add(
                item->sigUpdated().connect(
                    boost::bind(&ItemPropertyViewImpl::updateProperties, this)));
            itemConnections.add(
                item->sigNameChanged().connect(
                    boost::bind(&ItemPropertyViewImpl::updateProperties, this)));
            itemConnections.add(
                item->sigDetachedFromRoot().connect(
                    boost::bind(&ItemPropertyViewImpl::clear, this)));
        }
        updateProperties();
    }
}

void ItemPropertyView::keyPressEvent(QKeyEvent* event)
{
    if(event->modifiers() & Qt::ControlModifier){
        switch(event->key()){
        case Qt::Key_Plus:
        case Qt::Key_Semicolon:
            impl->zoomFontSize(1);
            return;
        case Qt::Key_Minus:
            impl->zoomFontSize(-1);
            return;
        defaut:
            break;
        }
    }
    View::keyPressEvent(event);
}

void ItemPropertyViewImpl::zoomFontSize(int pointSizeDiff)
{
    QFont font = tableWidget->font();
    font.setPointSize(font.pointSize() + pointSizeDiff);
    tableWidget->setFont(font);
    fontPointSizeDiff += pointSizeDiff;
    AppConfig::archive()->openMapping("ItemPropertyView")->write("fontZoom", fontPointSizeDiff);
}

void ItemPropertyView::onAttachedMenuRequest(MenuManager& menuManager)
{
    menuManager.addItem(_("Update"))->sigTriggered().connect(
        boost::bind(&ItemPropertyViewImpl::updateProperties, impl));
}

max_stars_repo_name: snozawa/choreonoid

max_issues_repo_name: snozawa/choreonoid

max_forks_repo_name: snozawa/choreonoid


text:
#pragma once

#include "sensors.hpp"
#include "utils/telemetry_utils.hpp"
#include "utils/time_utils.hpp"

#include <app.hpp>
#include <boost/container/flat_map.hpp>
#include <registries/privilege_registry.hpp>

#include <tuple>
#include <variant>

namespace redfish
{

namespace telemetry
{

using ReadingParameters =
    std::vector<std::tuple<sdbusplus::message::object_path, std::string,
                           std::string, std::string>>;

inline void fillReportDefinition(
    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id,
    const std::vector<
        std::pair<std::string, std::variant<std::string, bool, uint64_t,
                                            ReadingParameters>>>& ret)
{
    asyncResp->res.jsonValue["@odata.type"] =
        "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
    asyncResp->res.jsonValue["@odata.id"] =
        telemetry::metricReportDefinitionUri + std::string("/") + id;
    asyncResp->res.jsonValue["Id"] = id;
    asyncResp->res.jsonValue["Name"] = id;
    asyncResp->res.jsonValue["MetricReport"]["@odata.id"] =
        telemetry::metricReportUri + std::string("/") + id;
    asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
    asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";

    const bool* emitsReadingsUpdate = nullptr;
    const bool* logToMetricReportsCollection = nullptr;
    const ReadingParameters* readingParams = nullptr;
    const std::string* reportingType = nullptr;
    const uint64_t* interval = nullptr;
    for (const auto& [key, var] : ret)
    {
        if (key == "EmitsReadingsUpdate")
        {
            emitsReadingsUpdate = std::get_if<bool>(&var);
        }
        else if (key == "LogToMetricReportsCollection")
        {
            logToMetricReportsCollection = std::get_if<bool>(&var);
        }
        else if (key == "ReadingParameters")
        {
            readingParams = std::get_if<ReadingParameters>(&var);
        }
        else if (key == "ReportingType")
        {
            reportingType = std::get_if<std::string>(&var);
        }
        else if (key == "Interval")
        {
            interval = std::get_if<uint64_t>(&var);
        }
    }
    if (!emitsReadingsUpdate || !logToMetricReportsCollection ||
        !readingParams || !reportingType || !interval)
    {
        BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
        messages::internalError(asyncResp->res);
        return;
    }

    std::vector<std::string> redfishReportActions;
    redfishReportActions.reserve(2);
    if (*emitsReadingsUpdate)
    {
        redfishReportActions.emplace_back("RedfishEvent");
    }
    if (*logToMetricReportsCollection)
    {
        redfishReportActions.emplace_back("LogToMetricReportsCollection");
    }

    nlohmann::json metrics = nlohmann::json::array();
    for (auto& [sensorPath, operationType, id, metadata] : *readingParams)
    {
        metrics.push_back({
            {"MetricId", id},
            {"MetricProperties", {metadata}},
        });
    }
    asyncResp->res.jsonValue["Metrics"] = metrics;
    asyncResp->res.jsonValue["MetricReportDefinitionType"] = *reportingType;
    asyncResp->res.jsonValue["ReportActions"] = redfishReportActions;
    asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
        time_utils::toDurationString(std::chrono::milliseconds(*interval));
}

struct AddReportArgs
{
    std::string name;
    std::string reportingType;
    bool emitsReadingsUpdate = false;
    bool logToMetricReportsCollection = false;
    uint64_t interval = 0;
    std::vector<std::pair<std::string, std::vector<std::string>>> metrics;
};

inline bool toDbusReportActions(crow::Response& res,
                                std::vector<std::string>& actions,
                                AddReportArgs& args)
{
    size_t index = 0;
    for (auto& action : actions)
    {
        if (action == "RedfishEvent")
        {
            args.emitsReadingsUpdate = true;
        }
        else if (action == "LogToMetricReportsCollection")
        {
            args.logToMetricReportsCollection = true;
        }
        else
        {
            messages::propertyValueNotInList(
                res, action, "ReportActions/" + std::to_string(index));
            return false;
        }
        index++;
    }
    return true;
}

inline bool getUserParameters(crow::Response& res, const crow::Request& req,
                              AddReportArgs& args)
{
    std::vector<nlohmann::json> metrics;
    std::vector<std::string> reportActions;
    std::optional<nlohmann::json> schedule;
    if (!json_util::readJson(req, res, "Id", args.name, "Metrics", metrics,
                             "MetricReportDefinitionType", args.reportingType,
                             "ReportActions", reportActions, "Schedule",
                             schedule))
    {
        return false;
    }

    constexpr const char* allowedCharactersInName =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
    if (args.name.empty() || args.name.find_first_not_of(
                                 allowedCharactersInName) != std::string::npos)
    {
        BMCWEB_LOG_ERROR << "Failed to match " << args.name
                         << " with allowed character "
                         << allowedCharactersInName;
        messages::propertyValueIncorrect(res, "Id", args.name);
        return false;
    }

    if (args.reportingType != "Periodic" && args.reportingType != "OnRequest")
    {
        messages::propertyValueNotInList(res, args.reportingType,
                                         "MetricReportDefinitionType");
        return false;
    }

    if (!toDbusReportActions(res, reportActions, args))
    {
        return false;
    }

    if (args.reportingType == "Periodic")
    {
        if (!schedule)
        {
            messages::createFailedMissingReqProperties(res, "Schedule");
            return false;
        }

        std::string durationStr;
        if (!json_util::readJson(*schedule, res, "RecurrenceInterval",
                                 durationStr))
        {
            return false;
        }

        std::optional<std::chrono::milliseconds> durationNum =
            time_utils::fromDurationString(durationStr);
        if (!durationNum)
        {
            messages::propertyValueIncorrect(res, "RecurrenceInterval",
                                             durationStr);
            return false;
        }
        args.interval = static_cast<uint64_t>(durationNum->count());
    }

    args.metrics.reserve(metrics.size());
    for (auto& m : metrics)
    {
        std::string id;
        std::vector<std::string> uris;
        if (!json_util::readJson(m, res, "MetricId", id, "MetricProperties",
                                 uris))
        {
            return false;
        }

        args.metrics.emplace_back(std::move(id), std::move(uris));
    }

    return true;
}

inline bool getChassisSensorNode(
    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
    const std::vector<std::pair<std::string, std::vector<std::string>>>&
        metrics,
    boost::container::flat_set<std::pair<std::string, std::string>>& matched)
{
    for (const auto& [id, uris] : metrics)
    {
        for (size_t i = 0; i < uris.size(); i++)
        {
            const std::string& uri = uris[i];
            std::string chassis;
            std::string node;

            if (!boost::starts_with(uri, "/redfish/v1/Chassis/") ||
                !dbus::utility::getNthStringFromPath(uri, 3, chassis) ||
                !dbus::utility::getNthStringFromPath(uri, 4, node))
            {
                BMCWEB_LOG_ERROR
                    << "Failed to get chassis and sensor Node from " << uri;
                messages::propertyValueIncorrect(asyncResp->res, uri,
                                                 "MetricProperties/" +
                                                     std::to_string(i));
                return false;
            }

            if (boost::ends_with(node, "#"))
            {
                node.pop_back();
            }

            matched.emplace(std::move(chassis), std::move(node));
        }
    }
    return true;
}

class AddReport
{
  public:
    AddReport(AddReportArgs argsIn,
              const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) :
        asyncResp(asyncResp),
        args{std::move(argsIn)}
    {}
    ~AddReport()
    {
        if (asyncResp->res.result() != boost::beast::http::status::ok)
        {
            return;
        }

        telemetry::ReadingParameters readingParams;
        readingParams.reserve(args.metrics.size());

        for (const auto& [id, uris] : args.metrics)
        {
            for (size_t i = 0; i < uris.size(); i++)
            {
                const std::string& uri = uris[i];
                auto el = uriToDbus.find(uri);
                if (el == uriToDbus.end())
                {
                    BMCWEB_LOG_ERROR
                        << "Failed to find DBus sensor corresponding to URI "
                        << uri;
                    messages::propertyValueNotInList(asyncResp->res, uri,
                                                     "MetricProperties/" +
                                                         std::to_string(i));
                    return;
                }

                const std::string& dbusPath = el->second;
                readingParams.emplace_back(dbusPath, "SINGLE", id, uri);
            }
        }
        const std::shared_ptr<bmcweb::AsyncResp> aResp = asyncResp;
        crow::connections::systemBus->async_method_call(
            [aResp, name = args.name, uriToDbus = std::move(uriToDbus)](
                const boost::system::error_code ec, const std::string&) {
                if (ec == boost::system::errc::file_exists)
                {
                    messages::resourceAlreadyExists(
                        aResp->res, "MetricReportDefinition", "Id", name);
                    return;
                }
                if (ec == boost::system::errc::too_many_files_open)
                {
                    messages::createLimitReachedForResource(aResp->res);
                    return;
                }
                if (ec == boost::system::errc::argument_list_too_long)
                {
                    nlohmann::json metricProperties = nlohmann::json::array();
                    for (const auto& [uri, _] : uriToDbus)
                    {
                        metricProperties.emplace_back(uri);
                    }
                    messages::propertyValueIncorrect(
                        aResp->res, metricProperties, "MetricProperties");
                    return;
                }
                if (ec)
                {
                    messages::internalError(aResp->res);
                    BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
                    return;
                }

                messages::created(aResp->res);
            },
            telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
            "xyz.openbmc_project.Telemetry.ReportManager", "AddReport",
            "TelemetryService/" + args.name, args.reportingType,
            args.emitsReadingsUpdate, args.logToMetricReportsCollection,
            args.interval, readingParams);
    }

    void insert(const boost::container::flat_map<std::string, std::string>& el)
    {
        uriToDbus.insert(el.begin(), el.end());
    }

  private:
    const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
    AddReportArgs args;
    boost::container::flat_map<std::string, std::string> uriToDbus{};
};
} // namespace telemetry

inline void requestRoutesMetricReportDefinitionCollection(App& app)
{
    BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
        .privileges(redfish::privileges::getMetricReportDefinitionCollection)
        .methods(boost::beast::http::verb::get)(
            [](const crow::Request&,
               const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
                asyncResp->res.jsonValue["@odata.type"] =
                    "#MetricReportDefinitionCollection."
                    "MetricReportDefinitionCollection";
                asyncResp->res.jsonValue["@odata.id"] =
                    "/redfish/v1/TelemetryService/MetricReportDefinitions";
                asyncResp->res.jsonValue["Name"] =
                    "Metric Definition Collection";
                const std::vector<const char*> interfaces{
                    telemetry::reportInterface};
                collection_util::getCollectionMembers(
                    asyncResp, telemetry::metricReportDefinitionUri, interfaces,
                    "/xyz/openbmc_project/Telemetry/Reports/TelemetryService");
            });

    BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
        .privileges(redfish::privileges::postMetricReportDefinitionCollection)
        .methods(
            boost::beast::http::verb::
                post)([](const crow::Request& req,
                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
            telemetry::AddReportArgs args;
            if (!telemetry::getUserParameters(asyncResp->res, req, args))
            {
                return;
            }

            boost::container::flat_set<std::pair<std::string, std::string>>
                chassisSensors;
            if (!telemetry::getChassisSensorNode(asyncResp, args.metrics,
                                                 chassisSensors))
            {
                return;
            }

            auto addReportReq = std::make_shared<telemetry::AddReport>(
                std::move(args), asyncResp);
            for (const auto& [chassis, sensorType] : chassisSensors)
            {
                retrieveUriToDbusMap(
                    chassis, sensorType,
                    [asyncResp,
                     addReportReq](const boost::beast::http::status status,
                                   const boost::container::flat_map<
                                       std::string, std::string>& uriToDbus) {
                        if (status != boost::beast::http::status::ok)
                        {
                            BMCWEB_LOG_ERROR
                                << "Failed to retrieve URI to dbus sensors map with err "
                                << static_cast<unsigned>(status);
                            return;
                        }
                        addReportReq->insert(uriToDbus);
                    });
            }
        });
}

inline void requestRoutesMetricReportDefinition(App& app)
{
    BMCWEB_ROUTE(app,
                 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
        .privileges(redfish::privileges::getMetricReportDefinition)
        .methods(boost::beast::http::verb::get)(
            [](const crow::Request&,
               const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
               const std::string& id) {
                crow::connections::systemBus->async_method_call(
                    [asyncResp, id](
                        const boost::system::error_code ec,
                        const std::vector<std::pair<
                            std::string,
                            std::variant<std::string, bool, uint64_t,
                                         telemetry::ReadingParameters>>>& ret) {
                        if (ec.value() == EBADR ||
                            ec == boost::system::errc::host_unreachable)
                        {
                            messages::resourceNotFound(
                                asyncResp->res, "MetricReportDefinition", id);
                            return;
                        }
                        if (ec)
                        {
                            BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
                            messages::internalError(asyncResp->res);
                            return;
                        }

                        telemetry::fillReportDefinition(asyncResp, id, ret);
                    },
                    telemetry::service, telemetry::getDbusReportPath(id),
                    "org.freedesktop.DBus.Properties", "GetAll",
                    telemetry::reportInterface);
            });
    BMCWEB_ROUTE(app,
                 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
        .privileges(redfish::privileges::deleteMetricReportDefinitionCollection)
        .methods(boost::beast::http::verb::delete_)(
            [](const crow::Request&,
               const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
               const std::string& id)

            {
                const std::string reportPath = telemetry::getDbusReportPath(id);

                crow::connections::systemBus->async_method_call(
                    [asyncResp, id](const boost::system::error_code ec) {
                        /*
                         * boost::system::errc and std::errc are missing value
                         * for EBADR error that is defined in Linux.
                         */
                        if (ec.value() == EBADR)
                        {
                            messages::resourceNotFound(
                                asyncResp->res, "MetricReportDefinition", id);
                            return;
                        }

                        if (ec)
                        {
                            BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
                            messages::internalError(asyncResp->res);
                            return;
                        }

                        asyncResp->res.result(
                            boost::beast::http::status::no_content);
                    },
                    telemetry::service, reportPath,
                    "xyz.openbmc_project.Object.Delete", "Delete");
            });
}
} // namespace redfish

ext: hpp

max_stars_repo_name: GiridhariKrishna/bmcweb

max_issues_repo_name: GiridhariKrishna/bmcweb

max_forks_repo_name: GiridhariKrishna/bmcweb


text:
#ifndef RUBY_BGL_GRAPH_HH
#define RUBY_BGL_GRAPH_HH

#include <ruby.h>
#include <boost/graph/adjacency_list.hpp>
#include <set>
#include <boost/tuple/tuple.hpp>

extern VALUE bglModule;
extern VALUE bglGraph;
extern VALUE bglReverseGraph;
extern VALUE bglUndirectedGraph;
extern VALUE bglVertex;

/**********************************************************************
 * Definition of base C++ types
 */

struct EdgeProperty
{
    VALUE info;
    boost::default_color_type color; // needed by some algorithms

    EdgeProperty(VALUE info)
	: info(info) { }
};

struct RubyGraph : public boost::adjacency_list< boost::setS, boost::setS
		      , boost::bidirectionalS, VALUE, EdgeProperty>
{
    std::string name;
};
typedef std::map<VALUE, RubyGraph::vertex_descriptor>	graph_map;

inline RubyGraph& graph_wrapped(VALUE self)
{
    RubyGraph* object = 0;
    Data_Get_Struct(self, RubyGraph, object);
    return *object;
}

extern graph_map* vertex_descriptor_map(VALUE self, bool create);

/* Return the vertex_descriptor of +self+ in +graph+. The boolean is true if
 * +self+ is in graph, and false otherwise.
 */
inline std::pair<RubyGraph::vertex_descriptor, bool>
rb_to_vertex(VALUE vertex, VALUE graph)
{
    graph_map* descriptors = vertex_descriptor_map(vertex, false);
    if (!descriptors)
        return std::make_pair(static_cast<void*>(0), false);
    graph_map::iterator it = descriptors->find(graph);
    if(it == descriptors->end())
	return std::make_pair(static_cast<void*>(0), false);
    else
	return std::make_pair(it->second, true);
}

/* Returns a range for all descriptors of +self+
 */
inline std::pair<graph_map::iterator, graph_map::iterator> vertex_descriptors(VALUE self)
{
    graph_map& descriptors = *vertex_descriptor_map(self, true);
    return make_pair(descriptors.begin(), descriptors.end());
}

namespace details
{
    template<typename Graph, bool direct> struct vertex_range;

    template<typename Graph>
    struct vertex_range<Graph, true>
    {
	typedef typename Graph::adjacency_iterator iterator;
	typedef std::pair<iterator, iterator> range;

	static range get(RubyGraph::vertex_descriptor v, Graph& graph)
	{ return adjacent_vertices(v, graph); }
	static range get(RubyGraph::vertex_descriptor v, Graph const& graph)
	{ return adjacent_vertices(v, graph); }
    };

    template<typename Graph>
    struct vertex_range<Graph, false>
    {
	typedef typename Graph::inv_adjacency_iterator iterator;
	typedef std::pair<iterator, iterator> range;

	static range get(RubyGraph::vertex_descriptor v, Graph& graph)
	{ return inv_adjacent_vertices(v, graph); }
	static range get(RubyGraph::vertex_descriptor v, Graph const& graph)
	{ return inv_adjacent_vertices(v, graph); }
    };
}

/** Iterates on all vertices in the range */
template <typename Range, typename F>
static bool for_each_value(Range range, RubyGraph& graph, F f)
{
    typedef typename Range::first_type Iterator;
    Iterator it, end;
    for (boost::tie(it, end) = range; it != end; )
    {
	VALUE value = graph[*it];
	++it;

	if (!f(value))
	    return false;
    }
    return true;
}

/** Iterates on each adjacent vertex of +v+ in +graph+ which are not yet in +already_seen+ */
template <typename Graph, bool direct>
static bool for_each_adjacent_uniq(RubyGraph::vertex_descriptor v, Graph const& graph, std::set<VALUE>& already_seen)
{
    typedef details::vertex_range<Graph, direct>	getter;
    typedef typename getter::iterator		        Iterator;

    Iterator it, end;
    for (boost::tie(it, end) = details::vertex_range<Graph, direct>::get(v, graph); it != end; )
    {
	VALUE related_object = graph[*it];
	bool inserted;
	boost::tie(boost::tuples::ignore, inserted) = already_seen.insert(related_object);
	++it;

	if (inserted)
	    rb_yield_values(1, related_object);
    }
    return true;
}

/* Iterates on all graphs +vertex+ is part of, calling f(RubyGraph&, vertex_descriptor). If the calling
 * function returns false, stop iteration here */
template<typename F>
static bool for_each_graph(VALUE vertex, F f)
{
    graph_map::iterator graph, graph_end;
    for (boost::tie(graph, graph_end) = vertex_descriptors(vertex); graph != graph_end;)
    {
	RubyGraph& g	    = graph_wrapped(graph->first);
	RubyGraph::vertex_descriptor v = graph->second;
	++graph;

	if (!f(v, g))
	    return false;
    }
    return true;
}

// Returns true if +v+ has either no child (if +direct+ is true) or no parents (if +direct+ is false)
template<typename Graph, bool direct>
bool vertex_has_adjacent_i(RubyGraph::vertex_descriptor v, Graph const& g)
{
    typedef typename details::vertex_range<Graph, direct> getter;
    typename getter::iterator begin, end;
    boost::tie(begin, end) = getter::get(v, g);
    return begin == end;
}

template<bool direct>
VALUE vertex_has_adjacent(int argc, VALUE* argv, VALUE self)
{
    VALUE graph = Qnil;
    rb_scan_args(argc, argv, "01", &graph);

    bool result;
    if (NIL_P(graph))
	result = for_each_graph(self, vertex_has_adjacent_i<RubyGraph, direct>);
    else
    {
	RubyGraph::vertex_descriptor v; bool exists;
	boost::tie(v, exists) = rb_to_vertex(self, graph);
	if (! exists)
	    return Qtrue;

	RubyGraph& g = graph_wrapped(graph);
	result = vertex_has_adjacent_i<RubyGraph, direct>(v, g);
    }
    return result ? Qtrue : Qfalse;
}

#endif

ext: hh

max_stars_repo_name: auv-avalon/tools-roby

max_issues_repo_name: auv-avalon/tools-roby

max_forks_repo_name: auv-avalon/tools-roby


text:
//    |  /           |
//    ' /   __| _` | __|  _ \   __|
//    . \  |   (   | |   (   |\__ \.
//   _|\_\_|  \__,_|\__|\___/ ____/
//                   Multi-Physics
//
//  License:		 BSD License
//					 Kratos default license: kratos/license.txt
//
//  Main authors:    Zhiming Guo
//                   Riccardo Rossi
//

// System includes

// External includes
#include <boost/python.hpp>

// Project includes
#include "includes/define.h"
#include "processes/process.h"
#include "custom_python/add_custom_processes_to_python.h"
#include "custom_processes/create_mls_particles_gauss_process.h"
#include "custom_processes/recompute_neighbours_process.h"
#include "custom_processes/compute_mls_shape_functions_process.h"
#include "custom_processes/compute_lme_shape_functions_process.h"
#include "custom_processes/node_and_element_erase_process.h"
#include "custom_processes/gauss_coordiantes_update_process.h"

#include "includes/node.h"

namespace Kratos
{

namespace Python
{
void  AddCustomProcessesToPython()
{
    using namespace boost::python;

    class_<CreateMLSParticleGauss, bases<Process> >("CreateMLSParticleGauss",init<ModelPart&, const std::string, const std::string, unsigned int>());

	class_<RecomputeNeighboursProcess, bases<Process> >("RecomputeNeighboursProcess",init<ModelPart&>())
	.def( "EliminateNodes", &RecomputeNeighboursProcess::EliminateNodes )
	;

	class_<ComputeMLSShapeFunctionsProcess, bases<Process> >("ComputeMLSShapeFunctionsProcess",init<ModelPart&>());

	class_<ComputeLMEShapeFunctionsProcess, bases<Process> >("ComputeLMEShapeFunctionsProcess",init<ModelPart&>());

    class_<NodeAndElementEraseProcess, bases<Process> >("NodeAndElementEraseProcess", init < ModelPart& >());
    class_<Gauss_Coordinates_Update_Process, bases<Process> >("Gauss_Coordinates_Update_Process",init<ModelPart&>());
}

}  // namespace Python.

} // Namespace Kratos

ext: cpp

max_stars_repo_name: lcirrott/Kratos

max_issues_repo_name: lcirrott/Kratos

max_forks_repo_name: lcirrott/Kratos


text:
// This file is part of snark, a generic and flexible library for robotics research
// Copyright (c) 2018 The University of Sydney
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the name of the University of Sydney nor the
//    names of its contributors may be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
// GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
// HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/// @author Dave Jennings

#include "../ocular-thermal.h"
#include "../traits.h"
#include "../../../imaging/cv_mat/serialization.h"
#include <Image.h>
#include <RobotEyeThermal.h>
#include <comma/application/signal_flag.h>
#include <comma/csv/stream.h>
#include <comma/io/select.h>
#include <boost/thread.hpp>
#include <opencv2/core/core.hpp>

const unsigned int default_image_mode = 0;
const double default_max_speed = 10;    // 10Hz = 36000 deg/second

// Max frame rate is 7.5fps (133ms between frames) but unless the gap is
// substantially longer every second frame fails
const boost::chrono::milliseconds sleep_between_frames( 300 );
// Probably a good idea also, but relatively untested
const boost::chrono::milliseconds sleep_after_movement( 1000 );

static void bash_completion( unsigned const ac, char const * const * av )
{
    static const char* completion_options =
        " --help -h --verbose -v"
        " --input-fields --input-format"
        " --home --no-capture --speed --track"
        ;

    std::cout << completion_options << std::endl;
    exit( 0 );
}

#define QUOTED( arg ) #arg
#define STRINGIZED( arg ) QUOTED( arg )

void usage( bool )
{
    std::cerr << "\ncapture images from Ocular RobotEye thermal camera";
    std::cerr << "\noutput to stdout as serialized cv::Mat";
    std::cerr << "\n";
    std::cerr << "\nusage: cat <pan,tilt> | " << comma::verbose.app_name() << " <address> [<options>]";
    std::cerr << "\n    where <address> is ip address of ocular roboteye device";
    std::cerr << "\n          <pan,tilt> is pan and tilt in radians";
    std::cerr << "\n";
    std::cerr << "\noptions";
    std::cerr << "\n    --help,-h:      show help";
    std::cerr << "\n    --verbose,-v:   show detailed messages";
    std::cerr << "\n    --home:         home at the start";
    std::cerr << "\n    --image-mode=[<0-3>]: default=" << default_image_mode << "; set image mode";
    std::cerr << "\n    --input-fields: print input fields and exit";
    std::cerr << "\n    --input-format: print input format and exit";
    std::cerr << "\n    --no-capture:   don't capture images";
    std::cerr << "\n    --save=[<dir>]: save to <dir>, otherwise output to stdout";
    std::cerr << "\n    --speed=<Hz>:   default=" << default_max_speed << "; max speed (rotations/s)";
    std::cerr << "\n    --track         track input positions";
    std::cerr << "\n";
    std::cerr << "\n    where image mode is one of: 0 for None";
    std::cerr << "\n                                1 for Derotate";
    std::cerr << "\n                                2 for Circular Mask";
    std::cerr << "\n                                3 for both Derotate & Circular Mask";
    std::cerr << "\n";
    std::cerr << "\nNote that you have to set the environment variable GENICAM_ROOT_V3_0 first";
    std::cerr << "\n$ export GENICAM_ROOT_V3_0=" << STRINGIZED( OCULAR_ROBOTEYE_GENICAM_DIR );
    std::cerr << "\n";
    std::cerr << "\nexample:";
    std::cerr << "\n    io-console | control-from-console pantilt -a | " << comma::verbose.app_name() << " 192.168.1.150";
    std::cerr << "\n" << std::endl;
}

template< typename T > std::string field_names( bool full_xpath = false ) { return comma::join( comma::csv::names< T >( full_xpath ), ',' ); }
template< typename T > std::string format( bool full_xpath = false, const std::string& fields = "" ) { return comma::csv::format::value< T >( !fields.empty() ? fields : field_names< T >( full_xpath ), full_xpath ); }

using namespace snark::ocular::roboteye;

typedef std::pair< boost::posix_time::ptime, cv::Mat > timestamped_frame;

timestamped_frame image_to_timestamped_frame( const ::ocular::Image& image
                                            , const boost::posix_time::ptime& current_time )
{
    uint8_t pixel_type = image.GetPixelType();
    int opencv_pixel_type = pixel_type_to_opencv( image.GetPixelType() );
    comma::verbose << "ocular pixel type is \"" << (int)pixel_type << "\", mapping to " << opencv_pixel_type << std::endl;
    cv::Mat cv_mat( image.GetHeight()
                  , image.GetWidth()
                  , CV_8UC1
                  , (void*)image.GetDataPointer() );

    return std::make_pair( current_time, cv_mat );
}

void capture_frame( ocular::RobotEyeThermal& roboteye_thermal
                  , ocular::Image_Modes_t image_mode
                  , const boost::optional< std::string > save_dir
                  , snark::cv_mat::serialization& serialization )

{
    static unsigned int frame_num = 0;
    comma::verbose << "acquiring frame " << frame_num << std::endl;
    boost::this_thread::sleep_for( sleep_between_frames );
    ::ocular::Image image;
    if( check_dev_status( roboteye_thermal.GetImage( image, image_mode ), "GetImage" ).devCode == ::ocular::NO_ERR )
    {
        boost::posix_time::ptime current_time = boost::posix_time::microsec_clock::universal_time();

        if( save_dir )
        {
            const std::string file_name = *save_dir + "/frame" + std::to_string( frame_num ) + ".png";
            if( image.SaveFrame( file_name )) { comma::verbose << "frame " << frame_num << " saved successfully." << std::endl; }
        }
        else
        {
            timestamped_frame timestamped_frame = image_to_timestamped_frame( image, current_time );
            if( !timestamped_frame.first.is_not_a_date_time() )
            {
                serialization.write( std::cout, timestamped_frame );
            }
        }
        frame_num++;
    }
}

void move( ocular::RobotEye& roboteye
         , const position_t& position
         , double max_speed
         , bool track )
{
    double pan_degrees = position.pan / M_PI * 180;
    double tilt_degrees = position.tilt / M_PI * 180;
    comma::verbose << "moving to " << pan_degrees << "," << tilt_degrees << " degrees" << std::endl;

    if( track )
    {
        check_status( roboteye.StopStabilisation(), "StopStabilisation" );
        check_status( roboteye.SetApertureAngles( pan_degrees, tilt_degrees, max_speed ), "SetApertureAngles" );
        check_status( roboteye.StartStabilisation(), "StartStabilisation" );
        double roll = 0;
        check_status( roboteye.GetStabilisedRoll( roll ), "GetStabilisedRoll" );
    }
    else
    {
        check_status( roboteye.SetApertureAngles( pan_degrees, tilt_degrees, max_speed ), "SetApertureAngles" );
    }
}

int main( int argc, char** argv )
{
    // normally we'd try to set GENICAM_ROOT_V3_0 here but it's not soon enough
    // something static in the libraries requires it before we even get here
    try
    {
        comma::command_line_options options( argc, argv, usage );
        if( options.exists( "--bash-completion" )) bash_completion( argc, argv );
        if( options.exists( "--input-fields" )) { std::cout << field_names< position_t >( true ) << std::endl; return 0; }
        if( options.exists( "--input-format" )) { std::cout << format< position_t >() << std::endl; return 0; }

        comma::verbose << "GENICAM_ROOT_V3_0 set to " << ::getenv( "GENICAM_ROOT_V3_0" ) << std::endl;

        std::vector< std::string > unnamed = options.unnamed( comma::csv::options::valueless_options() + ",--verbose,-v,--track", "-.*" );
        if( unnamed.size() != 1 ) { COMMA_THROW( comma::exception, "require ip address" ); }

        std::string ip_address = unnamed[0];
        comma::verbose << "connecting to RobotEye at " << ip_address << std::endl;
        bool capture = !options.exists( "--no-capture" );
        boost::optional< std::string > save_dir;
        if( options.exists( "--save" )) { save_dir = options.value< std::string >( "--save" ); }
        double max_speed = options.value< double >( "--speed", default_max_speed );
        bool track = options.exists( "--track" );

        snark::cv_mat::serialization::options serialization_options;
        snark::cv_mat::serialization serialization( serialization_options );

        ocular::Image_Modes_t image_mode = static_cast< ocular::Image_Modes_t >( options.value< unsigned int >( "--image-mode", default_image_mode ));

        ocular::RobotEyeThermal roboteye_thermal( ip_address );
        ocular::RobotEye& roboteye = roboteye_thermal.GetRobotEye();

        std::string serial_no;
        if( roboteye.GetSerial( serial_no ) == ocular::NO_ERR )
        {
            comma::verbose << "Connected to RobotEye with serial number: " << serial_no << std::endl;
        }
        else
        {
            std::cerr << "Error getting serial number: "
                      << ocular::RobotEye::GetErrorString( roboteye.GetLastBlockingError() )
                      << std::endl;
        }

        ocular::ocular_error_t status;
        double azimuth = 0;
        double elevation = 0;
        status = check_status( roboteye.GetApertureAngles( azimuth, elevation ), "GetApertureAngles" );
        comma::verbose << "azimuth=" << azimuth << ", and elevation=" << elevation << std::endl;
        if( status == ocular::ERR_NOT_HOMED )
        {
            comma::verbose << "not homed, homing now..." << std::endl;
            status = roboteye.Home();
            if( status )
            {
                std::cout << "Home returned " << ocular::RobotEye::GetErrorString( status ) << std::endl;
                return 1;
            }
        }
        if( options.exists( "--home" ))
        {
            comma::verbose << "homing..." << std::endl;
            check_status( roboteye.Home(), "Home" );
        }

        if( capture )
        {
            comma::verbose << "setting pixel type" << std::endl;
            check_dev_status( roboteye_thermal.SetPixelType( ocular::thermal::PIXELTYPE_MONO_8 ), "SetPixelType" );
            comma::verbose << "set pixel type" << std::endl;
        }

        comma::csv::options csv( options );
        comma::csv::input_stream< position_t > istream( std::cin, csv );
        comma::io::select select;
        select.read().add( comma::io::stdin_fd );
        comma::signal_flag is_shutdown;
        bool acquiring = false;

        while( !is_shutdown && std::cin.good() )
        {
            while( select.check() && select.read().ready( comma::io::stdin_fd ) && std::cin.good() )
            {
                const position_t* position = istream.read();
                if( position )
                {
                    if( acquiring )
                    {
                        comma::verbose << "stopping frame acquisition" << std::endl;
                        check_dev_status( roboteye_thermal.StopAcquisition(), "StopAcquisition" );
                        acquiring = false;
                    }
                    move( roboteye, *position, max_speed, track );
                }
            }
            if( capture && !acquiring )
            {
                comma::verbose << "starting frame acquisition" << std::endl;
                boost::this_thread::sleep_for( sleep_after_movement );
                check_dev_status( roboteye_thermal.StartAcquisition(), "StartAcquisition" );
                acquiring = true;
            }
            if( capture ) { capture_frame( roboteye_thermal, image_mode, save_dir, serialization ); }
        }
        check_status( roboteye.Stop(), "Stop" );
        return 0;
    }
    catch( std::exception& ex )
    {
        std::cerr << comma::verbose.app_name() << ": exception: " << ex.what() << std::endl;
    }
    catch( ... )
    {
        std::cerr << comma::verbose.app_name() << ": " << "unknown exception" << std::endl;
    }
    return 1;
}

max_stars_repo_name: mission-systems-pty-ltd/snark

max_issues_repo_name: NEU-LC/snark

max_forks_repo_name: NEU-LC/snark


text:
/*
   Copyright 2012 Technical University of Denmark, DTU Compute.
   All rights reserved.

   This file is part of the Patmos simulator.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

      1. Redistributions of source code must retain the above copyright notice,
         this list of conditions and the following disclaimer.

      2. Redistributions in binary form must reproduce the above copyright
         notice, this list of conditions and the following disclaimer in the
         documentation and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
   NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

   The views and conclusions contained in the software and documentation are
   those of the authors and should not be interpreted as representing official
   policies, either expressed or implied, of the copyright holder.
 */

//
// Implementation of the instruction SPM..
//
#include "instr-spm.h"

#include "memory.h"
#include "exception.h"
#include "simulation-core.h"

#include <cmath>
#include <ostream>

#include <boost/format.hpp>

using namespace patmos;

bool instr_spm_t::fetch(simulator_t &s, uword_t base, uword_t address, word_t iw[NUM_SLOTS])
{
  if (address < Size) {
    // Just read directly from global memory without any latency.
    // TODO we should simulate copying the data to a local buffer though
    Memory->read_peek(s, address, reinterpret_cast<byte_t*>(iw),
                      sizeof(word_t)*NUM_SLOTS, true);
    return true;
  } else {
    return Cache->fetch(s, base, address, iw);
  }
}

bool instr_spm_t::load_method(simulator_t &s, uword_t address, word_t offset)
{
  if (address < Size) {
    Num_loads++;
    Method_stats[address]++;
    return true;
  } else {
    return Cache->load_method(s, address, offset);
  }
}

bool instr_spm_t::is_available(simulator_t &s, uword_t address)
{
  if (address < Size) {
    return true;
  } else {
    return Cache->is_available(s, address);
  }
}

void instr_spm_t::print_stats(const simulator_t &s, std::ostream &os,
                                   const stats_options_t& options)
{
  //os << "                              total        max.\n";
  os << "                              total\n";
  os << boost::format("   I-SPM calls/returns : %1$10d\n")
   % Num_loads;

  if (!options.short_stats && Num_loads > 0) {
    os << "\n";
    os << "       Method:        #hits\n";

    for(method_stats_t::iterator i(Method_stats.begin()),
        ie(Method_stats.end()); i != ie; i++)
    {
      os << boost::format("   0x%1$08x:   %2$10d       %3%\n")
        % i->first % i->second % s.Symbols.find(i->first);
    }
  }

  os << "\n";

  Cache->print_stats(s, os, options);
}

void instr_spm_t::reset_stats()
{
  Method_stats.clear();
  Num_loads = 0;

  Cache->reset_stats();
}

void instr_spm_t::flush_cache()
{
  // Note: we do not want to flush the I-SPM here (if we would Implement
  // the SPM as a local buffer), otherwise flushing the I$ through the
  // control-bits would also flush the I-SPM.

  Cache->flush_cache();
}

ext: cc

max_stars_repo_name: laurenkosub/wormhole-noc

max_issues_repo_name: laurenkosub/wormhole-noc

max_forks_repo_name: laurenkosub/wormhole-noc


text:
#define BOOST_TEST_NO_LIB
#define BOOST_TEST_MAIN
#include <gp/problem/problem.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <boost/test/unit_test.hpp>

using namespace gp;

BOOST_AUTO_TEST_SUITE(problem_test)
    BOOST_AUTO_TEST_CASE(problem_test) {
        utility::StringToType stringToType;
        stringToType.setTypeNamePair<int>("int");
        stringToType.setTypeNamePair<utility::LeftHandValue<int>>("lvalue[int]");
        stringToType.setTypeNamePair<utility::Reference<int>>("ref[int]");
        stringToType.setTypeNamePair<bool>("bool");
        stringToType.setTypeNamePair<double>("double");

        auto stringToValues = std::make_tuple(
                std::function<int(const std::string&)>([](const std::string& str){return boost::lexical_cast<int>(str);}),
                std::function<bool(const std::string&)>([](const std::string& str){return boost::lexical_cast<bool>(str);}),
                std::function<double(const std::string&)>([](const std::string& str){return boost::lexical_cast<double>(str);})
        );

        std::stringstream sstream(
                std::string("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
                            + "<problem>\n"
                            + "    <name>test</name>\n"
                            + "    <return_type>int</return_type>\n"
                            + "    <arguments>\n"
                            + "        <type>int</type>\n"
                            + "        <type>bool</type>\n"
                            + "        <type>double</type>\n"
                            + "    </arguments>\n"
                            + "    <teacher_data_set>\n"
                            + "        <data>\n"
                            + "            <argument idx = \"0\">1</argument>\n"
                            + "            <argument idx = \"1\">1</argument>\n"
                            + "            <argument idx = \"2\">5.5</argument>\n"
                            + "            <answer>2</answer>\n"
                            + "        </data>\n"
                            + "        <data>\n"
                            + "            <argument idx = \"0\">1</argument>\n"
                            + "            <argument idx = \"1\">0</argument>\n"
                            + "            <argument idx = \"2\">0</argument>\n"
                            + "            <answer>0</answer>\n"
                            + "        </data>\n"
                            + "        <data>\n"
                            + "            <argument idx = \"0\">10</argument>\n"
                            + "            <argument idx = \"1\">1</argument>\n"
                            + "            <argument idx = \"2\">0.5</argument>\n"
                            + "            <answer>15</answer>\n"
                            + "        </data>\n"
                            + "        <data>\n"
                            + "            <argument idx = \"0\">-10</argument>\n"
                            + "            <argument idx = \"1\">0</argument>\n"
                            + "            <argument idx = \"2\">-0.05</argument>\n"
                            + "            <answer>-5</answer>\n"
                            + "        </data>\n"
                            + "    </teacher_data_set>\n"
                            + "</problem>"
        );

        auto problemResult = problem::load(sstream, stringToType, stringToValues);
        BOOST_CHECK(problemResult);
        auto& problem1 = problemResult.unwrap();

        BOOST_CHECK_EQUAL(problem1.name, "test");
        BOOST_CHECK(*problem1.returnType == utility::typeInfo<int>());
        BOOST_CHECK_EQUAL(std::size(problem1.argumentTypes), 3);
        BOOST_CHECK(*problem1.argumentTypes[0] == utility::typeInfo<int>());
        BOOST_CHECK(*problem1.argumentTypes[1] == utility::typeInfo<bool>());
        BOOST_CHECK(*problem1.argumentTypes[2] == utility::typeInfo<double>());
        BOOST_CHECK_EQUAL(std::size(problem1.ansArgList), 4);
        {
            auto & [ans, args] = problem1.ansArgList[0];
            BOOST_CHECK_EQUAL(ans.get<int>(), 2);
            BOOST_CHECK_EQUAL(std::size(args), 3);
            BOOST_CHECK_EQUAL(args[0].get<int>(), 1);
            BOOST_CHECK_EQUAL(args[1].get<bool>(), true);
            BOOST_CHECK_EQUAL(args[2].get<double>(), 5.5);
        }
        {
            auto & [ans, args] = problem1.ansArgList[1];
            BOOST_CHECK_EQUAL(ans.get<int>(), 0);
            BOOST_CHECK_EQUAL(std::size(args), 3);
            BOOST_CHECK_EQUAL(args[0].get<int>(), 1);
            BOOST_CHECK_EQUAL(args[1].get<bool>(), false);
            BOOST_CHECK_EQUAL(args[2].get<double>(), 0);
        }
        {
            auto & [ans, args] = problem1.ansArgList[2];
            BOOST_CHECK_EQUAL(ans.get<int>(), 15);
            BOOST_CHECK_EQUAL(std::size(args), 3);
            BOOST_CHECK_EQUAL(args[0].get<int>(), 10);
            BOOST_CHECK_EQUAL(args[1].get<bool>(), true);
            BOOST_CHECK_EQUAL(args[2].get<double>(), 0.5);
        }
        {
            auto & [ans, args] = problem1.ansArgList[3];
            BOOST_CHECK_EQUAL(ans.get<int>(), -5);
            BOOST_CHECK_EQUAL(std::size(args), 3);
            BOOST_CHECK_EQUAL(args[0].get<int>(), -10);
            BOOST_CHECK_EQUAL(args[1].get<bool>(), false);
            BOOST_CHECK_EQUAL(args[2].get<double>(), -0.05);
        }
    }
BOOST_AUTO_TEST_SUITE_END()


text:
//  Copyright 2018 Stephan Menzel. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include "MRedisPubsubConnection.hpp"
#include "AsyncClient.hpp"
#include "MRedisCommands.hpp"

#include "tools/Log.hpp"
#include "tools/Assert.hpp"
#include "tools/Random.hpp"

#include <boost/algorithm/string.hpp>

namespace moose {
namespace mredis {

using namespace moose::tools;
namespace asio = boost::asio;
namespace ip = asio::ip;

MRedisPubsubConnection::MRedisPubsubConnection(AsyncClient &n_parent)
		: MRedisConnection(n_parent)
		, m_pending_subscriptions(128)
		, m_subscriptions_pending(0) {

}

MRedisPubsubConnection::~MRedisPubsubConnection() noexcept {

}

void MRedisPubsubConnection::stop() noexcept {

	// We may have pending subscribe requests that are no longer happening
	m_subscriptions_pending.store(0);
	pending_subscription *ps = 0;
	while (m_pending_subscriptions.pop(ps)) {
		if (ps->get<2>()) {
			ps->get<2>()->set_value(false);
			delete ps->get<2>();
		}
		delete ps;
	}

	for (pending_subscription &p : m_pending_confirms) {
		if (p.get<2>()) {
			p.get<2>()->set_value(false);
	//		delete ps->get<2>();
		}
	}
	m_pending_confirms.clear();

	MRedisConnection::stop();
}

// throws std::bad_alloc
boost::unique_future<bool> MRedisPubsubConnection::subscribe(const std::string &n_channel_name, boost::uint64_t *n_id, MessageCallback &&n_callback) {

	MOOSE_ASSERT((n_id));
	BOOST_LOG_SEV(logger(), normal) << "Subscribing to '" << n_channel_name << "'";

	{
		// Let's take care of the handler first and put it in our map
		boost::unique_lock<boost::mutex> slock(m_message_handlers_lock);

		// First we find a unique ID among our handlers
		bool duplicate = false;
		do {
			*n_id = tools::urand();
			for (std::map<std::string, SubscriptionMap>::value_type &channel : m_message_handlers) {
				for (SubscriptionMap::value_type &subs : channel.second) {
					if (subs.first == *n_id) {
						duplicate = true;
						break;
					}
				}
			}
		} while (duplicate || (*n_id == 0));

		SubscriptionMap &channel = m_message_handlers[n_channel_name];
		channel[*n_id] = std::move(n_callback);
	}

	// Now send the subscribe message. Since we are still in the caller's thread we must
	// hand things over to io_service now and wait for a future
	boost::promise<bool> *promised_retval = new boost::promise<bool>();

	boost::unique_future<bool> ret = promised_retval->get_future();

	m_pending_subscriptions.push(new pending_subscription{ n_channel_name, 0, promised_retval });
	m_subscriptions_pending++;

	asio::post(m_parent.io_context(), [this] {

		this->finish_subscriptions();
	});

	if (m_status == Status::Pubsub) {
		// Our connection may be waiting for messages already and not receive any.
		// In order for the io_service to become available, I send a dummy wakeup call
		// to ourselves. This is channel MREDIS_WAKEUP
		m_parent.publish("MREDIS_WAKEUP", "MOEP!");
	}

	return ret;
}

void MRedisPubsubConnection::unsubscribe(const boost::uint64_t n_id) {

	std::string channel_name;

	{
		// Let's take care of the handler first. An actual unsubscription is only in order if
		// we have no handlers for that channel anymore
		boost::unique_lock<boost::mutex> slock(m_message_handlers_lock);

		// Sadly, the handler could be anywhere in any of our maps
		for (std::map<std::string, SubscriptionMap>::value_type &channel : m_message_handlers) {
			SubscriptionMap::iterator i = channel.second.find(n_id);
			if (i != channel.second.end()) {
				channel_name = channel.first;
				channel.second.erase(i);  // if channel is empty now, we have set the name to the string
				break;
			} else {
				continue;
			}
		}
	}

	if (channel_name.empty()) {
		BOOST_LOG_SEV(logger(), warning) << "Could not un-subscribe id " << n_id << ", not found";
		return;  // We didn't find our subscription.
	}

	BOOST_LOG_SEV(logger(), normal) << "Unsubscribing from " << channel_name;

	m_pending_subscriptions.push(new pending_subscription{ channel_name, n_id, 0 });
	m_subscriptions_pending++;

	m_parent.io_context().post([this] () {

		this->finish_subscriptions();
	});

	return;
}

void MRedisPubsubConnection::finish_subscriptions() {

	pending_subscription *sub = 0;

	try {
		// if the streambuf is still in use so we have to wait for it to become available.
		if (m_send_buffer_busy) {
			m_send_retry_timer.expires_after(asio::chrono::milliseconds(1));
			m_send_retry_timer.async_wait(
				[this] (const boost::system::error_code &n_err) {

					if (!n_err && (this->m_status == Status::Pushing || this->m_status == Status::Pubsub)) {
						this->finish_subscriptions();
					}
			});
			return;
		}

		const bool subscribe_available = m_pending_subscriptions.pop(sub);
		if (!subscribe_available) {
			BOOST_LOG_SEV(logger(), normal) << "No outstanding subscriptions available";
			// This can happen when we receive a wakeup call someone else sent
			return;
		}

		// we have waited for our buffer to become available. Right now I assume there is
		// no async operation in progress on it
		MOOSE_ASSERT((!m_send_buffer_busy));
		m_send_buffer_busy = true;

		{
			std::ostream os(&m_send_streambuf);
			if (sub->get<1>() != 0) {
				format_unsubscribe(os, sub->get<0>());
			} else {
				format_subscribe(os, sub->get<0>());
			}
		}

		// send the content of the streambuf to redis
		// We also transfer ownership over the subscription
		asio::async_write(m_socket, m_send_streambuf,
			[this, sub] (const boost::system::error_code n_errc, const std::size_t) {

				m_send_buffer_busy = false;

				const std::string channel = sub->get<0>();
				boost::promise<bool> *prm = sub->get<2>();

				m_subscriptions_pending--;

				BOOST_LOG_SEV(logger(), normal) << "Write handler for channel " << channel;

				if (handle_error(n_errc, "sending (un)subscribe command to server")) {
					if (prm) {
						prm->set_exception(redis_error() << error_message("Could not write subscribe command"));
						delete prm;
					}
					delete sub;
					stop();
					return;
				}

				if (m_status >= Status::ShuttingDown) {
					if (prm) {
						prm->set_exception(redis_error() << error_message("Cannot subscribe. Connection shutting down"));
						delete prm;
					}
					delete sub;
					return;
				}

				// Keep the promise alive while waiting for confirmation.
				// I hand the raw ptr over to this map and wrap it into a unique_ptr
				// because this map need not be thread safe.
				m_pending_confirms.push_back(*sub);
				delete sub;

				if (!m_pending_confirms.rbegin()->get<1>()) {

					// The subscription struct however is now out of scope
					start_pubsub();

					// We should be in Pubsub state now and continuously read messages until
					// eventually the subscription notification comes in
				}
		});

		return;

	} catch (const boost::system::system_error &serr) {
		// Very likely we failed to set a retry timer. Doesn't matter. We still wake up as the next command comes in
		BOOST_LOG_SEV(logger(), warning) << "Error sending (un)subscribe command: " << boost::diagnostic_information(serr);
	} catch (const tools::moose_error &merr) {
		// Not expected at all
		BOOST_LOG_SEV(logger(), warning) << "Error sending (un)subscribe command: " << boost::diagnostic_information(merr);
	} catch (const std::exception &sex) {
		// The caller didn't provide callbacks that were nothrow
		BOOST_LOG_SEV(logger(), error) << "Unexpected exception in finish_subscriptions(): " << boost::diagnostic_information(sex);
	}

	if (sub) {
		if (sub->get<2>()) {
			sub->get<2>()->set_exception(redis_error() << error_message("Cannot (un)subscribe"));
			delete sub->get<2>();
		}
		delete sub;
		sub = 0;
	}
}

void MRedisPubsubConnection::start_pubsub() {

	// We are now in Pub/sub mode
	if (m_status == Status::Pushing) {
		m_status = Status::Pubsub;
		BOOST_LOG_SEV(logger(), normal) << "Connection entered pub/sub mode";
		read_message();
	} else if (m_status == Status::Pubsub) {
		// we are already in pubsub mode and do nothing
		BOOST_LOG_SEV(logger(), normal) << "Request sent, resuming pubsub";
		read_message();
	} else {
		// We should not be here at all
	}
}

class MessageVisitor : public boost::static_visitor<> {

	public:
	MessageVisitor(MRedisPubsubConnection &n_connection)
		: m_parent(n_connection) {
	}

	void operator()(const redis_error &n_error) const {

		BOOST_LOG_SEV(logger(), error) << "Received error message, while expecting an array: " << boost::diagnostic_information(n_error);
	}

	void operator()(const std::string &n_string) const {

		BOOST_LOG_SEV(logger(), error) << "Received string message, while expecting an array: " << n_string;
	}

	void operator()(const boost::int64_t &n_integer) const {

		BOOST_LOG_SEV(logger(), error) << "Received integer message, while expecting an array: " << n_integer;
	}

	void operator()(const null_result &n_null) const {

		BOOST_LOG_SEV(logger(), error) << "Received null message, while expecting an array";
	}

	void operator()(const std::vector<RedisMessage> &n_array) const {

		// From the redis specs:
		// A message is a Array reply with three elements.
		// The first element is the kind of message :
		//   subscribe: means that we successfully subscribed to the channel given as the second
		//              element in the reply. The third argument represents the number of channels
		//              we are currently subscribed to.
		//   unsubscribe: means that we successfully unsubscribed from the channel given as second
		//                element in the reply. The third argument represents the number of channels
		//                we are currently subscribed to. When the last argument is zero, we are no
		//                longer subscribed to any channel, and the client can issue any kind of
		//                Redis command as we are outside the Pub / Sub state.
		//   message: it is a message received as result of a PUBLISH command issued by another
		//            client.The second element is the name of the originating channel, and the
		//            third argument is the actual message payload.
		//

		if (n_array.size() != 3) {
			BOOST_LOG_SEV(logger(), error) << "Received array message with wrong number of elements: " << n_array.size();
			return;
		}

		// first element must be a string
		if (!is_string(n_array[0])) {
			BOOST_LOG_SEV(logger(), error) << "First message element is not a string: " << n_array[0].which();
			return;
		}

		const std::string &msgstr = boost::get<std::string>(n_array[0]);

		if (boost::algorithm::equals(msgstr, "message")) {

			if (!is_string(n_array[1])) {
				BOOST_LOG_SEV(logger(), error) << "Second message element is not a string: " << n_array[1].which();
				return;
			}

			// We know the message channel now
			const std::string &channel = boost::get<std::string>(n_array[1]);

			// This was a wakeup call to enable us to interrupt message read in order to send subscriptions
			if (boost::algorithm::equals(channel, "MREDIS_WAKEUP")) {
				BOOST_LOG_SEV(logger(), normal) << "Wakeup call received. See to subscriptions";
			} else {
				// Find the appropriate handler(s) and call
				boost::unique_lock<boost::mutex> slock(m_parent.m_message_handlers_lock);

				std::map<std::string, MRedisPubsubConnection::SubscriptionMap>::iterator i = m_parent.m_message_handlers.find(channel);
				if (i == m_parent.m_message_handlers.end()) {
					BOOST_LOG_SEV(logger(), error) << "No subscribed handler for channel '" << channel
							<< "'. This is a bug. We should not be getting this message.";
					return;
				} else {
					try {

						for (MRedisPubsubConnection::SubscriptionMap::value_type &sub : i->second) {
							sub.second(boost::get<std::string>(n_array[2]));
						}

					} catch (const std::exception &sex) {
						BOOST_LOG_SEV(logger(), error) << "Subscribed (no-throw) handler for channel '" << channel
							<< "' threw an exception: " << sex.what();
					} catch (...) {
						BOOST_LOG_SEV(logger(), error) << "Subscribed (no-throw) handler for channel '" << channel
							<< "' threw an unknown exception";
					}
				}
			}

		} else if (boost::algorithm::equals(msgstr, "subscribe")) {

			if (!is_string(n_array[1])) {
				BOOST_LOG_SEV(logger(), error) << "Second subscribe message element is not a string: " << n_array[1].which();
				return;
			}

			// Our subscribe was successful.
			const std::string &channel = boost::get<std::string>(n_array[1]);

			if (boost::algorithm::equals(channel, "MREDIS_WAKEUP")) {
				// internal wakeup call
				return;
			}

			// Find a subscription for that channel in our confirms vector
			std::vector<MRedisPubsubConnection::pending_subscription>::iterator i = std::find_if(
				m_parent.m_pending_confirms.begin(), m_parent.m_pending_confirms.end(),
				[&] (const MRedisPubsubConnection::pending_subscription &p) -> bool {
					return (boost::algorithm::equals(p.get<0>(), channel) && !p.get<1>());
			});

			if (i == m_parent.m_pending_confirms.end()) {
				BOOST_LOG_SEV(logger(), warning) << "Got an unexpected subscribe confirmation for channel '" << channel << "'";
				return;
			}

			// This will notify the original caller that we now are subscribed
			i->get<2>()->set_value(true);
			delete i->get<2>();
			m_parent.m_pending_confirms.erase(i);

		} else if (boost::algorithm::equals(msgstr, "unsubscribe")) {

			if (!is_string(n_array[1])) {
				BOOST_LOG_SEV(logger(), error) << "Second unsubscribe message element is not a string: " << n_array[1].which();
				return;
			}

			const std::string &channel = boost::get<std::string>(n_array[1]);

			// Find a unsubscription for that channel in our confirms vector
			std::vector<MRedisPubsubConnection::pending_subscription>::iterator i = std::find_if(
				m_parent.m_pending_confirms.begin(), m_parent.m_pending_confirms.end(),
				[&] (const MRedisPubsubConnection::pending_subscription &p) -> bool {
					return (boost::algorithm::equals(p.get<0>(), channel) && p.get<1>());
			});

			if (i == m_parent.m_pending_confirms.end()) {
				BOOST_LOG_SEV(logger(), warning) << "Got an unexpected unsubscribe confirmation for channel '" << channel << "'";
				// This is not so bad here. We may be unsubscribing from everything and get confirmations anyway
			} else {
				const boost::uint64_t id = i->get<1>();

				m_parent.m_pending_confirms.erase(i);
				BOOST_LOG_SEV(logger(), normal) << "Unsubscribed from channel '" << channel;

				// Finally remove our handler
				boost::unique_lock<boost::mutex> slock(m_parent.m_message_handlers_lock);
				m_parent.m_message_handlers[channel].erase(id);
				if (m_parent.m_message_handlers[channel].empty()) {
					m_parent.m_message_handlers.erase(channel);
				}

				if (m_parent.m_message_handlers.empty()) {
					BOOST_LOG_SEV(logger(), normal) << "Last subscription removed, leaving pubsub mode";
					m_parent.m_status = MRedisConnection::Status::Pushing;
				}
			}
		} else {
			BOOST_LOG_SEV(logger(), error) << "Unknown message type: " << n_array[0].which();
			return;
		}
	}

	MRedisPubsubConnection  &m_parent; //!< a reference to the connection that spawned this
};

void MRedisPubsubConnection::read_message() {

	if (m_status >= Status::ShuttingDown) {
		return;
	}

	try {
		// if the streambuf is in use we cannot push data into it
		// we have to wait for it to become available. We store both handlers until later
		if (m_receive_buffer_busy) {
			m_receive_retry_timer.expires_after(asio::chrono::milliseconds(1));
			m_receive_retry_timer.async_wait(
				[this] (const boost::system::error_code &n_err) {

					if (!n_err && this->m_status == Status::Pubsub) {
						this->read_message();
					}
			});

			return;
		}

		// we have waited for our buffer to become available. Right now I assume there is
		// no async operation in progress on it
		MOOSE_ASSERT((!m_send_buffer_busy));
		m_send_buffer_busy = true;

		// perhaps we already have bytes to read in our streambuf. If so, I parse those first
		while (m_send_streambuf.size()) {

			std::istream is(&m_send_streambuf);
			RedisMessage r;

			// As long as we can parse messages from our stream, continue to do so.
			bool success = parse_from_stream(is, r);
			if (success) {
				boost::apply_visitor(MessageVisitor(*this), r);
			} else {
				break;
			}
		}

		// We may have been woken up by a message, only to be able to see if we
		// got outstanding subscriptions
		if ((m_subscriptions_pending.load() > 0) && (m_receive_streambuf.size() == 0)) {
			m_send_buffer_busy = false;
			asio::post(m_parent.io_context(), [this] {
				this->finish_subscriptions();
			});
			return;
		}

		// handle_message may have caused us to leave pubsub mode by removing the last subscription
		if (m_status != Status::Pubsub) {
			m_send_buffer_busy = false;
			return;
		}

		// Otherwise read more from the socket
	//	BOOST_LOG_SEV(logger(), debug) << "Reading more messages";

		// read one messages and evaluate
		asio::async_read(m_socket, m_receive_streambuf, asio::transfer_at_least(1),
			[this] (const boost::system::error_code n_errc, const std::size_t) {

				m_receive_buffer_busy = false;

				if (handle_error(n_errc, "reading message")) {
					stop();
					return;
				}

				if (m_status >= Status::ShuttingDown) {
					BOOST_LOG_SEV(logger(), normal) << "Shutting down, not reading any more messages";
					return;
				}

				read_message();

// 				if (m_status != MRedisConnection::Status::Pubsub) {
// 					read_message();
// 				} else {
// 					// this is going to parse
// 					if (m_subscriptions_pending.load() > 0) {
// 						this->finish_subscriptions();
// 					} else {
// 						read_message();
// 					}
// 				}
		});
	} catch (const boost::system::system_error &serr) {
		// Very likely we failed to set a retry timer. Doesn't matter. We still wake up as the next command comes in
		BOOST_LOG_SEV(logger(), warning) << "Error reading message: " << boost::diagnostic_information(serr);
	} catch (const tools::moose_error &merr) {
		// Not expected at all
		BOOST_LOG_SEV(logger(), warning) << "Error reading message: " << boost::diagnostic_information(merr);
	} catch (const std::exception &sex) {
		// The caller didn't provide callbacks that were nothrow
		BOOST_LOG_SEV(logger(), error) << "Unexpected exception in read_response(): " << boost::diagnostic_information(sex);
	}
}

}
}

max_stars_repo_name: MrMoose/mredis

max_issues_repo_name: MrMoose/mredis

max_forks_repo_name: MrMoose/mredis


text:
/**
 *  Copyright (C) 2021 FISCO BCOS.
 *  SPDX-License-Identifier: Apache-2.0
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * @brief Unit tests for the Base64
 * @file Base64.cpp
 */

#include "interfaces/storage/TableInterface.h"
#include "libtable/Table.h"
#include "libtable/TableFactory.h"
#include <bcos-test/libutils/TestPromptFixture.h>
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <string>

using namespace bcos;
using namespace bcos::storage;
namespace bcos
{
namespace test
{
BOOST_FIXTURE_TEST_SUITE(StorageInterfaces, TestPromptFixture)

BOOST_AUTO_TEST_CASE(testStorageInterface)
{
    StorageInterface::Ptr storage = nullptr;
    TableInterface::Ptr tableI = nullptr;
    Table::Ptr table = nullptr;
    TableFactoryInterface::Ptr tableFactoryI = nullptr;
    TableFactory::Ptr tableFactory = nullptr;
    Entry::Ptr entry = nullptr;
}

BOOST_AUTO_TEST_SUITE_END()
}  // namespace test
}  // namespace bcos


text:
//Copyright (c) 2008-2016 Emil Dotchevski and Reverge Studios, Inc.

//Distributed under the Boost Software License, Version 1.0. (See accompanying
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef UUID_9C471450B3A611DEAF56C1F155D89593
#define UUID_9C471450B3A611DEAF56C1F155D89593

#include <boost/qvm/deduce_mat.hpp>
#include <boost/qvm/assert.hpp>
#include "test_qvm.hpp"

namespace
test_qvm
    {
    template <class Tag,int Rows,int Cols,class T=float>
    struct
    matrix
        {
        T a[Rows][Cols];
        mutable T b[Rows][Cols];

        explicit
        matrix( T start=T(0), T step=T(0) )
            {
            for( int i=0; i!=Rows; ++i )
                for( int j=0; j!=Cols; ++j,start+=step )
                    a[i][j]=b[i][j]=start;
            }
        };

    template <int Rows,int Cols,class Tag1,class T1,class Tag2,class T2>
    void
    dump_ab( matrix<Tag1,Rows,Cols,T1> const & a, matrix<Tag2,Rows,Cols,T2> const & b )
        {
        detail::dump_ab(a.a,b.a);
        }
    }

namespace
boost
    {
    namespace
    qvm
        {
        template <class Tag,int Rows,int Cols,class T>
        struct
        mat_traits< test_qvm::matrix<Tag,Rows,Cols,T> >
            {
            static int const rows=Rows;
            static int const cols=Cols;
            typedef T scalar_type;
            typedef test_qvm::matrix<Tag,Rows,Cols,T> this_matrix_type;

            template <int R,int C>
            static
            scalar_type &
            write_element( this_matrix_type & m )
                {
                BOOST_QVM_STATIC_ASSERT(R>=0);
                BOOST_QVM_STATIC_ASSERT(R<rows);
                BOOST_QVM_STATIC_ASSERT(C>=0);
                BOOST_QVM_STATIC_ASSERT(C<cols);
                return m.a[R][C];
                }

            template <int R,int C>
            static
            scalar_type
            read_element( this_matrix_type const & m )
                {
                BOOST_QVM_STATIC_ASSERT(R>=0);
                BOOST_QVM_STATIC_ASSERT(R<rows);
                BOOST_QVM_STATIC_ASSERT(C>=0);
                BOOST_QVM_STATIC_ASSERT(C<cols);
                return m.a[R][C];
                }

            static
            inline
            scalar_type &
            write_element_idx( int r, int c, this_matrix_type & m )
                {
                BOOST_QVM_ASSERT(r>=0);
                BOOST_QVM_ASSERT(r<rows);
                BOOST_QVM_ASSERT(c>=0);
                BOOST_QVM_ASSERT(c<cols);
                return m.a[r][c];
                }

            static
            inline
            scalar_type
            read_element_idx( int r, int c, this_matrix_type const & m )
                {
                BOOST_QVM_ASSERT(r>=0);
                BOOST_QVM_ASSERT(r<rows);
                BOOST_QVM_ASSERT(c>=0);
                BOOST_QVM_ASSERT(c<cols);
                return m.a[r][c];
                }
            };

        template <class Tag,class T,int R1,int C1,int R2,int C2,int Rows,int Cols>
        struct
        deduce_mat2<test_qvm::matrix<Tag,R1,C1,T>,test_qvm::matrix<Tag,R2,C2,T>,Rows,Cols>
            {
            typedef test_qvm::matrix<Tag,Rows,Cols,T> type;
            };
        }
    }

namespace
    {
    struct M1;
    struct M2;
    struct M3;
    }

#endif

max_stars_repo_name: gnified/boost

max_issues_repo_name: gnified/boost

max_forks_repo_name: gnified/boost


text:
/*=============================================================================
    Copyright (c) 2017 Paul Fultz II
    reverse_fold.cpp
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#include <boost/hof/reverse_fold.hpp>
#include "test.hpp"

struct max_f
{
    template<class T, class U>
    constexpr T operator()(T x, U y) const noexcept
    {
        return x > y ? x : y;
    }
};

struct sum_f
{
    template<class T, class U>
    constexpr T operator()(T x, U y) const BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(x+y)
    {
        return x + y;
    }
};

#if BOOST_HOF_HAS_NOEXCEPT_DEDUCTION
BOOST_HOF_TEST_CASE()
{
    static_assert(noexcept(boost::hof::reverse_fold(max_f(), 0)(2, 3, 4, 5)), "noexcept reverse_fold");
    static_assert(noexcept(boost::hof::reverse_fold(sum_f(), 0)(2, 3, 4, 5)), "noexcept reverse_fold");
    static_assert(!noexcept(boost::hof::reverse_fold(sum_f(), std::string())("hello", "-", "world")), "noexcept reverse_fold");
}
#endif

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(2, 3, 4, 5) == 5);
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(5, 4, 3, 2) == 5);
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(2, 3, 5, 4) == 5);

    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(2, 3, 4, 5) == 5);
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(5, 4, 3, 2) == 5);
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(2, 3, 5, 4) == 5);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)() == 0);
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(5) == 5);

    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)() == 0);
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f(), 0)(5) == 5);
}

template<class... Ts>
constexpr auto find_positive_max(Ts... xs) BOOST_HOF_RETURNS
(
    boost::hof::reverse_fold(max_f(), 0)(xs...)
);

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(find_positive_max() == 0);
    BOOST_HOF_TEST_CHECK(find_positive_max(5) == 5);

    BOOST_HOF_STATIC_TEST_CHECK(find_positive_max() == 0);
    BOOST_HOF_STATIC_TEST_CHECK(find_positive_max(5) == 5);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f())(5) == 5);

    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f())(5) == 5);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f())(2, 3, 4, 5) == 5);
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f())(5, 4, 3, 2) == 5);
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(max_f())(2, 3, 5, 4) == 5);

    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f())(2, 3, 4, 5) == 5);
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f())(5, 4, 3, 2) == 5);
    BOOST_HOF_STATIC_TEST_CHECK(boost::hof::reverse_fold(max_f())(2, 3, 5, 4) == 5);
}

BOOST_HOF_TEST_CASE()
{
    BOOST_HOF_TEST_CHECK(boost::hof::reverse_fold(sum_f(), std::string())("hello", "-", "world") == "world-hello");
}