<commit_before>//==============================================================================
// Single cell simulation view
//==============================================================================

#include "cellmlfile.h"
#include "cellmlfilemanager.h"
#include "cellmlfileruntime.h"
#include "singlecellsimulationview.h"
#include "toolbar.h"

//==============================================================================

#include "ui_singlecellsimulationview.h"

//==============================================================================

#include <QFileInfo>
#include <QListView>
#include <QProgressBar>
#include <QSplitter>
#include <QTime>

//==============================================================================

#include "qwt_plot_grid.h"
#include "qwt_plot_curve.h"

//==============================================================================

namespace OpenCOR {
namespace SingleCellSimulation {

//==============================================================================

GraphPanel::GraphPanel(QWidget *pParent) :
    QwtPlot(pParent)
{
    // Customise our simulation view widget

    setCanvasBackground(Qt::white);

    // Remove the canvas' border as it otherwise looks odd, not to say ugly,
    // with one

    setCanvasLineWidth(0);

    // Add a grid to our simulation view widget

    QwtPlotGrid *grid = new QwtPlotGrid;

    grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine));

    grid->attach(this);
}

//==============================================================================

GraphPanel::~GraphPanel()
{
    // Delete some internal objects

    resetCurves();
}

//==============================================================================

void GraphPanel::addCurve(QwtPlotCurve *pCurve, const bool &pRefresh)
{
    // Add the curve to our list of curves

    mCurves.append(pCurve);

    // Refresh the graph panel, if needed

    if (pRefresh)
        replot();
}

//==============================================================================

void GraphPanel::resetCurves()
{
    // Remove any existing curve

    foreach (QwtPlotCurve *curve, mCurves) {
        curve->detach();

        delete curve;
    }

    mCurves.clear();

    // Refresh the graph panel

    replot();
}

//==============================================================================

SingleCellSimulationView::SingleCellSimulationView(QWidget *pParent) :
    QWidget(pParent),
    mUi(new Ui::SingleCellSimulationView)
{
    // Set up the UI

    mUi->setupUi(this);

    // Create a toolbar with different buttons

    Core::ToolBar *toolbar = new Core::ToolBar(this);

    toolbar->addAction(mUi->action);

    mUi->verticalLayout->addWidget(toolbar);
    mUi->verticalLayout->addWidget(newSeparatingLine());

    // Create our vertical splitter

    QSplitter *mainVerticalSplitter = new QSplitter(Qt::Vertical, this);

    // Create a splitter for our graph panels and add a graph panel to it

    mGraphPanels = new QSplitter(Qt::Vertical, this);

    mGraphPanel = addGraphPanel();

    mGraphPanels->addWidget(mGraphPanel);
    mGraphPanels->addWidget(addGraphPanel());   //---GRY--- These two graph
    mGraphPanels->addWidget(addGraphPanel());   //          panels are just for
                                                //          testing purposes...

    // Create a simulation output widget with a vertical layout on which we put
    // a separating line and our simulation output list view
    // Note: the separating line is because we remove, for aesthetical reasons,
    //       the border of our simulation output list view...

    QWidget *simulationOutputWidget = new QWidget(this);
    QVBoxLayout *simulationOutputVerticalLayout= new QVBoxLayout(this);

    simulationOutputVerticalLayout->setContentsMargins(0, 0, 0, 0);
    simulationOutputVerticalLayout->setSpacing(0);

    simulationOutputWidget->setLayout(simulationOutputVerticalLayout);

    mSimulationOutput = new QListView(this);

    mSimulationOutput->setFrameStyle(QFrame::NoFrame);

    simulationOutputVerticalLayout->addWidget(newSeparatingLine());
    simulationOutputVerticalLayout->addWidget(mSimulationOutput);

    // Populate our splitter and add it to our view

    mainVerticalSplitter->addWidget(mGraphPanels);
    mainVerticalSplitter->addWidget(simulationOutputWidget);

    mUi->verticalLayout->addWidget(mainVerticalSplitter);

    // Create our simulation progress widget

    mProgressBar = new QProgressBar(this);

    mUi->verticalLayout->addWidget(newSeparatingLine());
    mUi->verticalLayout->addWidget(mProgressBar);
}

//==============================================================================

SingleCellSimulationView::~SingleCellSimulationView()
{
    // Delete the UI

    delete mUi;
}

//==============================================================================

void SingleCellSimulationView::retranslateUi()
{
    // Retranslate the whole view

    mUi->retranslateUi(this);
}

//==============================================================================

GraphPanel * SingleCellSimulationView::addGraphPanel()
{
    // Add a graph panel to our simulation view

    return new GraphPanel(this);
}

//==============================================================================

QFrame * SingleCellSimulationView::newSeparatingLine()
{
    // Return a separating line widget

    QFrame *res = new QFrame(this);

    res->setFrameShape(QFrame::HLine);
    res->setFrameShadow(QFrame::Sunken);

    return res;
}

//==============================================================================

void SingleCellSimulationView::updateWith(const QString &pFileName)
{
    qDebug("=======================================");
    qDebug("%s:", qPrintable(pFileName));

    // Get a runtime for the file

    CellMLSupport::CellmlFileRuntime *cellmlFileRuntime = CellMLSupport::CellmlFileManager::instance()->cellmlFile(pFileName)->runtime();

    if (cellmlFileRuntime->isValid()) {
        qDebug(" - The CellML file's runtime was properly generated.");
        qDebug("    [Information] Model type = %s", (cellmlFileRuntime->modelType() == CellMLSupport::CellmlFileRuntime::Ode)?"ODE":"DAE");
    } else {
        qDebug(" - The CellML file's runtime was NOT properly generated:");

        foreach (const CellMLSupport::CellmlFileIssue &issue,
                 cellmlFileRuntime->issues())
            qDebug("    [%s] %s",
                   (issue.type() == CellMLSupport::CellmlFileIssue::Error)?"Error":"Warning",
                   qPrintable(issue.formattedMessage()));
    }

    // Remove any existing curve

    mGraphPanel->resetCurves();

    // Compute the model, if supported

    enum Model {
        Unknown,
        VanDerPol1928,
        Hodgkin1952,
        Noble1962,
        Noble1984,
        Noble1991,
        Noble1998,
        Zhang2000,
        Mitchell2003
    } model;

    QString fileBaseName = QFileInfo(pFileName).baseName();

    if (!fileBaseName.compare("van_der_pol_model_1928"))
        model = VanDerPol1928;
    else if (   !fileBaseName.compare("hodgkin_huxley_squid_axon_model_1952")
             || !fileBaseName.compare("hodgkin_huxley_squid_axon_model_1952_modified")
             || !fileBaseName.compare("hodgkin_huxley_squid_axon_model_1952_original"))
        model = Hodgkin1952;
    else if (!fileBaseName.compare("noble_model_1962"))
        model = Noble1962;
    else if (!fileBaseName.compare("noble_noble_SAN_model_1984"))
        model = Noble1984;
    else if (!fileBaseName.compare("noble_model_1991"))
        model = Noble1991;
    else if (!fileBaseName.compare("noble_model_1998"))
        model = Noble1998;
    else if (   !fileBaseName.compare("zhang_SAN_model_2000_0D_capable")
             || !fileBaseName.compare("zhang_SAN_model_2000_1D_capable")
             || !fileBaseName.compare("zhang_SAN_model_2000_all")
             || !fileBaseName.compare("zhang_SAN_model_2000_published"))
        model = Zhang2000;
    else if (!fileBaseName.compare("mitchell_schaeffer_2003"))
        model = Mitchell2003;
    else
        model = Unknown;

    if (cellmlFileRuntime->isValid() && (model != Unknown)) {
        typedef QVector<double> Doubles;

        int statesCount = cellmlFileRuntime->statesCount();

        Doubles xData;
        Doubles yData[statesCount];

        double voi = 0;   // ms
        double voiStep;   // ms
        double voiMax;    // ms
        double constants[cellmlFileRuntime->constantsCount()];
        double rates[cellmlFileRuntime->ratesCount()];
        double states[statesCount];
        double algebraic[cellmlFileRuntime->algebraicCount()];
        int voiCount = 0;
        int voiOutputCount;   // ms

        switch (model) {
        case Hodgkin1952:
            voiStep        = 0.01;   // ms
            voiMax         = 50;     // ms
            voiOutputCount = 10;

            break;
        case Noble1962:
        case Mitchell2003:
            voiStep        = 0.01;   // ms
            voiMax         = 1000;   // ms
            voiOutputCount = 100;

            break;
        case Noble1984:
        case Noble1991:
        case Noble1998:
        case Zhang2000:
            voiStep        = 0.00001;   // s
            voiMax         = 1;         // s
            voiOutputCount = 100;

            break;
        default:   // van der Pol 1928
            voiStep        = 0.01;   // s
            voiMax         = 10;     // s
            voiOutputCount = 1;
        }

        CellMLSupport::CellmlFileRuntimeOdeFunctions odeFunctions = cellmlFileRuntime->odeFunctions();

        // Initialise the constants and compute the rates and variables

        QTime time;

        time.start();

        odeFunctions.initializeConstants(constants, rates, states);
        odeFunctions.computeRates(voi, constants, rates, states, algebraic);
        odeFunctions.computeVariables(voi, constants, rates, states, algebraic);

        do {
            // Output the current data, if needed

            if(voiCount % voiOutputCount == 0) {
                xData.append(voi);

                for (int i = 0; i < statesCount; ++i)
                    yData[i].append(states[i]);
            }

            // Compute the rates and variables

            odeFunctions.computeRates(voi, constants, rates, states, algebraic);
            odeFunctions.computeVariables(voi, constants, rates, states, algebraic);

            // Go to the next voiStep and integrate the states

            voi = ++voiCount*voiStep;

            for (int i = 0; i < statesCount; ++i)
                states[i] += voiStep*rates[i];
        } while (voi < voiMax);

        xData.append(voi);

        for (int i = 0; i < statesCount; ++i)
            yData[i].append(states[i]);

        qDebug(" - Simulation time: %s s", qPrintable(QString::number(0.001*time.elapsed(), 'g', 3)));

        // Add some curves to our plotting area

        for (int i = 0, iMax = (model == VanDerPol1928)?statesCount:1; i < iMax; ++i) {
            QwtPlotCurve *curve = new QwtPlotCurve();

            curve->setRenderHint(QwtPlotItem::RenderAntialiased);
            curve->setPen(QPen(i%2?Qt::darkBlue:Qt::darkRed));

            curve->setSamples(xData, yData[i]);

            curve->attach(mGraphPanel);

            // Keep track of the curve

            mGraphPanel->addCurve(curve, false);
        }

        // Make sure that the view is up-to-date

        mGraphPanel->replot();
    }
}

//==============================================================================

}   // namespace SingleCellSimulation
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Minor improvement to our SingleCellSimulation plugin.<commit_after>//==============================================================================
// Single cell simulation view
//==============================================================================

#include "cellmlfile.h"
#include "cellmlfilemanager.h"
#include "cellmlfileruntime.h"
#include "singlecellsimulationview.h"
#include "toolbar.h"

//==============================================================================

#include "ui_singlecellsimulationview.h"

//==============================================================================

#include <QFileInfo>
#include <QListView>
#include <QProgressBar>
#include <QSplitter>
#include <QTime>

//==============================================================================

#include "qwt_plot_grid.h"
#include "qwt_plot_curve.h"

//==============================================================================

namespace OpenCOR {
namespace SingleCellSimulation {

//==============================================================================

GraphPanel::GraphPanel(QWidget *pParent) :
    QwtPlot(pParent)
{
    // Allow the graph panel to be of any size

    setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

    // Have a white background by default

    setCanvasBackground(Qt::white);

    // Remove the canvas' border as it otherwise looks odd, not to say ugly,
    // with one

    setCanvasLineWidth(0);

    // Add a grid to our graph panel

    QwtPlotGrid *grid = new QwtPlotGrid;

    grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine));

    grid->attach(this);
}

//==============================================================================

GraphPanel::~GraphPanel()
{
    // Delete some internal objects

    resetCurves();
}

//==============================================================================

void GraphPanel::addCurve(QwtPlotCurve *pCurve, const bool &pRefresh)
{
    // Add the curve to our list of curves

    mCurves.append(pCurve);

    // Refresh the graph panel, if needed

    if (pRefresh)
        replot();
}

//==============================================================================

void GraphPanel::resetCurves()
{
    // Remove any existing curve

    foreach (QwtPlotCurve *curve, mCurves) {
        curve->detach();

        delete curve;
    }

    mCurves.clear();

    // Refresh the graph panel

    replot();
}

//==============================================================================

SingleCellSimulationView::SingleCellSimulationView(QWidget *pParent) :
    QWidget(pParent),
    mUi(new Ui::SingleCellSimulationView)
{
    // Set up the UI

    mUi->setupUi(this);

    // Create a toolbar with different buttons

    Core::ToolBar *toolbar = new Core::ToolBar(this);

    toolbar->addAction(mUi->action);

    mUi->verticalLayout->addWidget(toolbar);
    mUi->verticalLayout->addWidget(newSeparatingLine());

    // Create our vertical splitter

    QSplitter *mainVerticalSplitter = new QSplitter(Qt::Vertical, this);

    // Create a splitter for our graph panels and add a graph panel to it

    mGraphPanels = new QSplitter(Qt::Vertical, this);

    mGraphPanel = addGraphPanel();

    mGraphPanels->addWidget(mGraphPanel);
    mGraphPanels->addWidget(addGraphPanel());   //---GRY--- These two graph
    mGraphPanels->addWidget(addGraphPanel());   //          panels are just for
                                                //          testing purposes...

    // Create a simulation output widget with a vertical layout on which we put
    // a separating line and our simulation output list view
    // Note: the separating line is because we remove, for aesthetical reasons,
    //       the border of our simulation output list view...

    QWidget *simulationOutputWidget = new QWidget(this);
    QVBoxLayout *simulationOutputVerticalLayout= new QVBoxLayout(simulationOutputWidget);

    simulationOutputVerticalLayout->setContentsMargins(0, 0, 0, 0);
    simulationOutputVerticalLayout->setSpacing(0);

    simulationOutputWidget->setLayout(simulationOutputVerticalLayout);

    mSimulationOutput = new QListView(this);

    mSimulationOutput->setFrameStyle(QFrame::NoFrame);

    simulationOutputVerticalLayout->addWidget(newSeparatingLine());
    simulationOutputVerticalLayout->addWidget(mSimulationOutput);

    // Populate our splitter and add it to our view

    mainVerticalSplitter->addWidget(mGraphPanels);
    mainVerticalSplitter->addWidget(simulationOutputWidget);

    mUi->verticalLayout->addWidget(mainVerticalSplitter);

    // Create our simulation progress widget

    mProgressBar = new QProgressBar(this);

    mProgressBar->setAlignment(Qt::AlignCenter);

    mUi->verticalLayout->addWidget(newSeparatingLine());
    mUi->verticalLayout->addWidget(mProgressBar);
}

//==============================================================================

SingleCellSimulationView::~SingleCellSimulationView()
{
    // Delete the UI

    delete mUi;
}

//==============================================================================

void SingleCellSimulationView::retranslateUi()
{
    // Retranslate the whole view

    mUi->retranslateUi(this);
}

//==============================================================================

GraphPanel * SingleCellSimulationView::addGraphPanel()
{
    // Add a graph panel to our simulation view

    return new GraphPanel(this);
}

//==============================================================================

QFrame * SingleCellSimulationView::newSeparatingLine()
{
    // Return a separating line widget

    QFrame *res = new QFrame(this);

    res->setFrameShape(QFrame::HLine);
    res->setFrameShadow(QFrame::Sunken);

    return res;
}

//==============================================================================

void SingleCellSimulationView::updateWith(const QString &pFileName)
{
    qDebug("=======================================");
    qDebug("%s:", qPrintable(pFileName));

    // Get a runtime for the file

    CellMLSupport::CellmlFileRuntime *cellmlFileRuntime = CellMLSupport::CellmlFileManager::instance()->cellmlFile(pFileName)->runtime();

    if (cellmlFileRuntime->isValid()) {
        qDebug(" - The CellML file's runtime was properly generated.");
        qDebug("    [Information] Model type = %s", (cellmlFileRuntime->modelType() == CellMLSupport::CellmlFileRuntime::Ode)?"ODE":"DAE");
    } else {
        qDebug(" - The CellML file's runtime was NOT properly generated:");

        foreach (const CellMLSupport::CellmlFileIssue &issue,
                 cellmlFileRuntime->issues())
            qDebug("    [%s] %s",
                   (issue.type() == CellMLSupport::CellmlFileIssue::Error)?"Error":"Warning",
                   qPrintable(issue.formattedMessage()));
    }

    // Remove any existing curve

    mGraphPanel->resetCurves();

    // Compute the model, if supported

    enum Model {
        Unknown,
        VanDerPol1928,
        Hodgkin1952,
        Noble1962,
        Noble1984,
        Noble1991,
        Noble1998,
        Zhang2000,
        Mitchell2003
    } model;

    QString fileBaseName = QFileInfo(pFileName).baseName();

    if (!fileBaseName.compare("van_der_pol_model_1928"))
        model = VanDerPol1928;
    else if (   !fileBaseName.compare("hodgkin_huxley_squid_axon_model_1952")
             || !fileBaseName.compare("hodgkin_huxley_squid_axon_model_1952_modified")
             || !fileBaseName.compare("hodgkin_huxley_squid_axon_model_1952_original"))
        model = Hodgkin1952;
    else if (!fileBaseName.compare("noble_model_1962"))
        model = Noble1962;
    else if (!fileBaseName.compare("noble_noble_SAN_model_1984"))
        model = Noble1984;
    else if (!fileBaseName.compare("noble_model_1991"))
        model = Noble1991;
    else if (!fileBaseName.compare("noble_model_1998"))
        model = Noble1998;
    else if (   !fileBaseName.compare("zhang_SAN_model_2000_0D_capable")
             || !fileBaseName.compare("zhang_SAN_model_2000_1D_capable")
             || !fileBaseName.compare("zhang_SAN_model_2000_all")
             || !fileBaseName.compare("zhang_SAN_model_2000_published"))
        model = Zhang2000;
    else if (!fileBaseName.compare("mitchell_schaeffer_2003"))
        model = Mitchell2003;
    else
        model = Unknown;

    if (cellmlFileRuntime->isValid() && (model != Unknown)) {
        typedef QVector<double> Doubles;

        int statesCount = cellmlFileRuntime->statesCount();

        Doubles xData;
        Doubles yData[statesCount];

        double voi = 0;   // ms
        double voiStep;   // ms
        double voiMax;    // ms
        double constants[cellmlFileRuntime->constantsCount()];
        double rates[cellmlFileRuntime->ratesCount()];
        double states[statesCount];
        double algebraic[cellmlFileRuntime->algebraicCount()];
        int voiCount = 0;
        int voiOutputCount;   // ms

        switch (model) {
        case Hodgkin1952:
            voiStep        = 0.01;   // ms
            voiMax         = 50;     // ms
            voiOutputCount = 10;

            break;
        case Noble1962:
        case Mitchell2003:
            voiStep        = 0.01;   // ms
            voiMax         = 1000;   // ms
            voiOutputCount = 100;

            break;
        case Noble1984:
        case Noble1991:
        case Noble1998:
        case Zhang2000:
            voiStep        = 0.00001;   // s
            voiMax         = 1;         // s
            voiOutputCount = 100;

            break;
        default:   // van der Pol 1928
            voiStep        = 0.01;   // s
            voiMax         = 10;     // s
            voiOutputCount = 1;
        }

        CellMLSupport::CellmlFileRuntimeOdeFunctions odeFunctions = cellmlFileRuntime->odeFunctions();

        // Initialise the constants and compute the rates and variables

        QTime time;

        time.start();

        odeFunctions.initializeConstants(constants, rates, states);
        odeFunctions.computeRates(voi, constants, rates, states, algebraic);
        odeFunctions.computeVariables(voi, constants, rates, states, algebraic);

        do {
            // Output the current data, if needed

            if(voiCount % voiOutputCount == 0) {
                xData.append(voi);

                for (int i = 0; i < statesCount; ++i)
                    yData[i].append(states[i]);
            }

            // Compute the rates and variables

            odeFunctions.computeRates(voi, constants, rates, states, algebraic);
            odeFunctions.computeVariables(voi, constants, rates, states, algebraic);

            // Go to the next voiStep and integrate the states

            voi = ++voiCount*voiStep;

            for (int i = 0; i < statesCount; ++i)
                states[i] += voiStep*rates[i];
        } while (voi < voiMax);

        xData.append(voi);

        for (int i = 0; i < statesCount; ++i)
            yData[i].append(states[i]);

        qDebug(" - Simulation time: %s s", qPrintable(QString::number(0.001*time.elapsed(), 'g', 3)));

        // Add some curves to our plotting area

        for (int i = 0, iMax = (model == VanDerPol1928)?statesCount:1; i < iMax; ++i) {
            QwtPlotCurve *curve = new QwtPlotCurve();

            curve->setRenderHint(QwtPlotItem::RenderAntialiased);
            curve->setPen(QPen(i%2?Qt::darkBlue:Qt::darkRed));

            curve->setSamples(xData, yData[i]);

            curve->attach(mGraphPanel);

            // Keep track of the curve

            mGraphPanel->addCurve(curve, false);
        }

        // Make sure that the view is up-to-date

        mGraphPanel->replot();
    }
}

//==============================================================================

}   // namespace SingleCellSimulation
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/*
    Copyright (c) 2017-2019 Xavier Leclercq and the wxCharts contributors.

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/

#include "WxMath2DFrame.h"
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/charts/wxcharts.h>
#include <cmath>

const int ID_LineChart = 1;
const int ID_StemChart = 2;
const int ID_StepChart = 3;
const int ID_CustomXAxis = 4;
const int ID_CustomYAxis = 5;
const int ID_Grid = 6;

WxMath2DFrame::WxMath2DFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title)
{
    m_menubar = new wxMenuBar( 0 );
    m_typeMenu = new wxMenu();
    wxMenuItem* m_line = new wxMenuItem( m_typeMenu, ID_LineChart, wxString( wxT("Line") ), wxEmptyString, wxITEM_RADIO );
    m_typeMenu->Append( m_line );

    wxMenuItem* m_stem = new wxMenuItem( m_typeMenu, ID_StemChart, wxString( wxT("Stem") ), wxEmptyString, wxITEM_RADIO );
    m_typeMenu->Append( m_stem );

    wxMenuItem* m_step = new wxMenuItem( m_typeMenu, ID_StepChart, wxString( wxT("Step") ), wxEmptyString, wxITEM_RADIO );
    m_typeMenu->Append( m_step );

    m_menubar->Append( m_typeMenu, wxT("ChartType") );

    m_axisMenu = new wxMenu();

    wxMenuItem* m_customX = new wxMenuItem( m_axisMenu, ID_CustomXAxis, wxString( wxT("CustomX(exp)") ), wxEmptyString, wxITEM_CHECK );
    m_axisMenu->Append( m_customX );

    wxMenuItem* m_customY = new wxMenuItem( m_axisMenu, ID_CustomYAxis, wxString( wxT("CustomY(exp)") ), wxEmptyString, wxITEM_CHECK );
    m_axisMenu->Append( m_customY );

    m_menubar->Append( m_axisMenu, wxT("AxisType") );

    m_gridMenu = new wxMenu();
    wxMenuItem* m_grid = new wxMenuItem( m_gridMenu, ID_Grid, wxString( wxT("Grid") ), wxEmptyString, wxITEM_CHECK );
    m_grid->Check( true );
    m_gridMenu->Append( m_grid );

    m_menubar->Append( m_gridMenu, wxT("Grid") );
    this->SetMenuBar( m_menubar );

    wxPanel* panel = new wxPanel(this, wxID_ANY);

    wxMath2DPlotData chartData;
    wxSharedPtr<wxMath2DPlotOptions> options(new wxMath2DPlotOptions());
    options->GetCommonOptions().SetShowTooltips(false);

    wxVector<wxPoint2DDouble> points;
    auto pi = 3.1415926535897;
    auto tstart = -2*pi;
    for(auto i = 0u; i<100; i++)
    {
        auto x = tstart+0.1*i;
        points.push_back(wxPoint2DDouble(x,cos(x)*sin(x)));
    }

    wxMath2DPlotDataset::ptr dataset(
        new wxMath2DPlotDataset(
            wxColor(255, 255, 255, 0),
            wxColor(250, 20, 20, 0x78),
            wxColor(0, 0, 0, 0xB8),
            points)
    );
    chartData.AddDataset(dataset);

    math2dPlotCtrl = new wxMath2DPlotCtrl(panel, wxID_ANY, chartData, options);
    wxChartGridOptions opt = math2dPlotCtrl->GetGridOptions();
    opt.GetHorizontalGridLineOptions().SetMajorGridLineColor(wxColour("Grey"));
    opt.GetVerticalGridLineOptions().SetMajorGridLineColor(wxColour("Grey"));
    math2dPlotCtrl->SetGridOptions(opt);

    wxBoxSizer* panelSizer = new wxBoxSizer(wxHORIZONTAL);
    panelSizer->Add(math2dPlotCtrl, 1, wxEXPAND);
    panel->SetSizer(panelSizer);

    wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL);
    topSizer->Add(panel, 1, wxEXPAND);
    SetSizerAndFit(topSizer);

    Binds();
}

void WxMath2DFrame::Binds()
{
    m_gridMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        auto opt = math2dPlotCtrl->GetGridOptions();
        opt.SetShowGridLines(m_gridMenu->IsChecked(ID_Grid));
        math2dPlotCtrl->SetGridOptions(opt);
    }, ID_Grid);

    m_axisMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        auto opt = math2dPlotCtrl->GetChartOptions();
        if (m_axisMenu->IsChecked(ID_CustomXAxis))
            opt.SetAxisFuncX([](wxDouble x){return std::exp(x);});
        else
            opt.SetAxisFuncX([](wxDouble x){return x;});
        math2dPlotCtrl->SetChartOptions(opt);
    }, ID_CustomXAxis);
    m_axisMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        auto opt = math2dPlotCtrl->GetChartOptions();
        if (m_axisMenu->IsChecked(ID_CustomYAxis))
            opt.SetAxisFuncY([](wxDouble x){return std::exp(x);});
        else
            opt.SetAxisFuncY([](wxDouble x){return x;});
        math2dPlotCtrl->SetChartOptions(opt);
    }, ID_CustomYAxis);
    m_typeMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        math2dPlotCtrl->SetChartType(0,wxCHARTTYPE_LINE);
    }, ID_LineChart);
    m_typeMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        math2dPlotCtrl->SetChartType(0,wxCHARTTYPE_STEPPED);
    }, ID_StepChart);
    m_typeMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        math2dPlotCtrl->SetChartType(0,wxCHARTTYPE_STEM);
    }, ID_StemChart);
}
<commit_msg>Fix WxMath2D sample compilation<commit_after>/*
    Copyright (c) 2017-2019 Xavier Leclercq and the wxCharts contributors.

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/

#include "WxMath2DFrame.h"
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/charts/wxcharts.h>
#include <cmath>

const int ID_LineChart = 1;
const int ID_StemChart = 2;
const int ID_StepChart = 3;
const int ID_CustomXAxis = 4;
const int ID_CustomYAxis = 5;
const int ID_Grid = 6;

WxMath2DFrame::WxMath2DFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title)
{
    m_menubar = new wxMenuBar( 0 );
    m_typeMenu = new wxMenu();
    wxMenuItem* m_line = new wxMenuItem( m_typeMenu, ID_LineChart, wxString( wxT("Line") ), wxEmptyString, wxITEM_RADIO );
    m_typeMenu->Append( m_line );

    wxMenuItem* m_stem = new wxMenuItem( m_typeMenu, ID_StemChart, wxString( wxT("Stem") ), wxEmptyString, wxITEM_RADIO );
    m_typeMenu->Append( m_stem );

    wxMenuItem* m_step = new wxMenuItem( m_typeMenu, ID_StepChart, wxString( wxT("Step") ), wxEmptyString, wxITEM_RADIO );
    m_typeMenu->Append( m_step );

    m_menubar->Append( m_typeMenu, wxT("ChartType") );

    m_axisMenu = new wxMenu();

    wxMenuItem* m_customX = new wxMenuItem( m_axisMenu, ID_CustomXAxis, wxString( wxT("CustomX(exp)") ), wxEmptyString, wxITEM_CHECK );
    m_axisMenu->Append( m_customX );

    wxMenuItem* m_customY = new wxMenuItem( m_axisMenu, ID_CustomYAxis, wxString( wxT("CustomY(exp)") ), wxEmptyString, wxITEM_CHECK );
    m_axisMenu->Append( m_customY );

    m_menubar->Append( m_axisMenu, wxT("AxisType") );

    m_gridMenu = new wxMenu();
    wxMenuItem* m_grid = new wxMenuItem( m_gridMenu, ID_Grid, wxString( wxT("Grid") ), wxEmptyString, wxITEM_CHECK );
    m_grid->Check( true );
    m_gridMenu->Append( m_grid );

    m_menubar->Append( m_gridMenu, wxT("Grid") );
    this->SetMenuBar( m_menubar );

    wxPanel* panel = new wxPanel(this, wxID_ANY);

    wxMath2DPlotData chartData;
    wxSharedPtr<wxMath2DPlotOptions> options(new wxMath2DPlotOptions());
    options->GetCommonOptions().SetShowTooltips(false);

    wxVector<wxPoint2DDouble> points;
    auto pi = 3.1415926535897;
    auto tstart = -2*pi;
    for(auto i = 0u; i<100; i++)
    {
        auto x = tstart+0.1*i;
        points.push_back(wxPoint2DDouble(x,cos(x)*sin(x)));
    }

    wxMath2DPlotDataset::ptr dataset(
        new wxMath2DPlotDataset(
            wxColor(255, 255, 255, 0),
            wxColor(250, 20, 20, 0x78),
            wxColor(0, 0, 0, 0xB8),
            points)
    );
    chartData.AddDataset(dataset);

    math2dPlotCtrl = new wxMath2DPlotCtrl(panel, wxID_ANY, chartData, options);
    wxChartsGridOptions opt = math2dPlotCtrl->GetGridOptions();
    opt.GetHorizontalGridLineOptions().SetMajorGridLineColor(wxColour("Grey"));
    opt.GetVerticalGridLineOptions().SetMajorGridLineColor(wxColour("Grey"));
    math2dPlotCtrl->SetGridOptions(opt);

    wxBoxSizer* panelSizer = new wxBoxSizer(wxHORIZONTAL);
    panelSizer->Add(math2dPlotCtrl, 1, wxEXPAND);
    panel->SetSizer(panelSizer);

    wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL);
    topSizer->Add(panel, 1, wxEXPAND);
    SetSizerAndFit(topSizer);

    Binds();
}

void WxMath2DFrame::Binds()
{
    m_gridMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        auto opt = math2dPlotCtrl->GetGridOptions();
        opt.SetShowGridLines(m_gridMenu->IsChecked(ID_Grid));
        math2dPlotCtrl->SetGridOptions(opt);
    }, ID_Grid);

    m_axisMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        auto opt = math2dPlotCtrl->GetChartOptions();
        if (m_axisMenu->IsChecked(ID_CustomXAxis))
            opt.SetAxisFuncX([](wxDouble x){return std::exp(x);});
        else
            opt.SetAxisFuncX([](wxDouble x){return x;});
        math2dPlotCtrl->SetChartOptions(opt);
    }, ID_CustomXAxis);
    m_axisMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        auto opt = math2dPlotCtrl->GetChartOptions();
        if (m_axisMenu->IsChecked(ID_CustomYAxis))
            opt.SetAxisFuncY([](wxDouble x){return std::exp(x);});
        else
            opt.SetAxisFuncY([](wxDouble x){return x;});
        math2dPlotCtrl->SetChartOptions(opt);
    }, ID_CustomYAxis);
    m_typeMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        math2dPlotCtrl->SetChartType(0,wxCHARTTYPE_LINE);
    }, ID_LineChart);
    m_typeMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        math2dPlotCtrl->SetChartType(0,wxCHARTTYPE_STEPPED);
    }, ID_StepChart);
    m_typeMenu->Bind(wxEVT_COMMAND_MENU_SELECTED,[&](wxCommandEvent &)
    {
        math2dPlotCtrl->SetChartType(0,wxCHARTTYPE_STEM);
    }, ID_StemChart);
}
<|endoftext|>


<commit_before>/* Copyright 2014-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <folly/SocketAddress.h>
#include <folly/String.h>
#include <folly/net/NetworkSocket.h>
#include <memory>
#include "FileDescriptor.h"
#include "Pipe.h"

using watchman::FileDescriptor;
using watchman::Pipe;
using namespace watchman;

static const int kWriteTimeout = 60000;

namespace {
// This trait allows w_poll_events to wait on either a PipeEvent or
// a descriptor contained in a UnixStream
class PollableEvent : public watchman_event {
 public:
  virtual FileDescriptor::system_handle_type getFd() const = 0;
};

// The event object, implemented as pipe
class PipeEvent : public PollableEvent {
 public:
  SocketPair pipe;

  void notify() override {
    ignore_result(pipe.write.write("a", 1).hasValue());
  }

  bool testAndClear() override {
    char buf[64];
    bool signalled = false;
    while (true) {
      auto res = pipe.read.read(buf, sizeof(buf));
      if (res.hasError() || res.value() == 0) {
        break;
      }
      signalled = true;
    }
    return signalled;
  }

  FileDescriptor::system_handle_type getFd() const override {
    return pipe.read.system_handle();
  }

  FileDescriptor::system_handle_type system_handle() override {
    return pipe.read.system_handle();
  }

  bool isSocket() override {
    return true;
  }
};

// Event object that UnixStream returns via getEvents.
// It cannot be poked by hand; it is just a helper to
// allow waiting on a socket using w_poll_events.
class FakeSocketEvent : public PollableEvent {
 private:
  FileDescriptor::system_handle_type socket;

 public:
  explicit FakeSocketEvent(FileDescriptor::system_handle_type fd)
      : socket(fd) {}

  void notify() override {}
  bool testAndClear() override {
    return false;
  }
  FileDescriptor::system_handle_type getFd() const override {
    return socket;
  }

  FileDescriptor::system_handle_type system_handle() override {
    return socket;
  }

  bool isSocket() override {
    return true;
  }
};

class UnixStream : public watchman_stream {
 public:
  FileDescriptor fd;
  FakeSocketEvent evt;
#ifdef SO_PEERCRED
  struct ucred cred;
#elif defined(LOCAL_PEERCRED)
  struct xucred cred;
#elif defined(SO_RECVUCRED)
  struct ucred_deleter {
    void operator()(ucred_t* utp) {
      ucred_free(utp);
    }
  };
  std::unique_ptr<ucred_t, ucred_deleter> cred;
#endif
  bool credvalid{false};
  bool blocking_{false};

  explicit UnixStream(FileDescriptor&& descriptor)
      : fd(std::move(descriptor)), evt(fd.system_handle()) {
#ifdef SO_PEERCRED
    socklen_t len = sizeof(cred);
    credvalid = getsockopt(fd.fd(), SOL_SOCKET, SO_PEERCRED, &cred, &len) == 0;
#elif defined(LOCAL_PEERCRED)
    socklen_t len = sizeof(cred);
#if defined(__FreeBSD__) || defined(__DragonFly__)
    credvalid = getsockopt(fd.fd(), 0, LOCAL_PEERCRED, &cred, &len) == 0;
#else
    credvalid =
        getsockopt(fd.fd(), SOL_LOCAL, LOCAL_PEERCRED, &cred, &len) == 0;
#endif
#elif defined(SO_RECVUCRED)
    ucred_t* peer_cred{nullptr};
    credvalid = getpeerucred(fd.fd(), &peer_cred) == 0;
    cred.reset(peer_cred);
#endif
  }

  const FileDescriptor& getFileDescriptor() const override {
    return fd;
  }

  int read(void* buf, int size) override {
    auto res = fd.read(buf, size);
    if (res.hasError()) {
#ifdef _WIN32
      errno = map_win32_err(res.error().value());
#else
      errno = res.error().value();
#endif
      return -1;
    }
    errno = 0;
    return res.value();
  }

  int write(const void* buf, int size) override {
    if (blocking_) {
      int wrote = 0;

      while (size > 0) {
        struct pollfd pfd;
        pfd.fd = fd.system_handle();
        pfd.events = POLLOUT;
#ifdef _WIN32
        if (WSAPoll(&pfd, 1, kWriteTimeout) == 0) {
          errno = map_win32_err(WSAGetLastError());
          break;
        }
#else
        if (poll(&pfd, 1, kWriteTimeout) == 0) {
          break;
        }
#endif
        if (pfd.revents & (POLLERR | POLLHUP)) {
          break;
        }
        auto x = fd.write(buf, size);
        if (x.hasError()) {
#ifdef _WIN32
          errno = map_win32_err(x.error().value());
#else
          errno = x.error().value();
#endif
          break;
        }
        if (x.value() == 0) {
          errno = 0;
          break;
        }

        wrote += x.value();
        size -= x.value();
        buf = reinterpret_cast<const void*>(
            reinterpret_cast<const char*>(buf) + x.value());
      }
      return wrote == 0 ? -1 : wrote;
    }
    auto x = fd.write(buf, size);
    if (x.hasError()) {
#ifdef _WIN32
      errno = map_win32_err(x.error().value());
#else
      errno = x.error().value();
#endif
      return -1;
    }
    errno = 0;
    return x.value();
  }

  w_evt_t getEvents() override {
    return &evt;
  }

  void setNonBlock(bool nonb) override {
    if (nonb) {
      fd.setNonBlock();
    } else {
      fd.clearNonBlock();
    }
    blocking_ = !nonb;
  }

  bool rewind() override {
#ifndef _WIN32
    return lseek(fd.fd(), 0, SEEK_SET) == 0;
#else
    return false;
#endif
  }

  bool shutdown() override {
    return ::shutdown(
        fd.system_handle(),
#ifdef SHUT_RDWR
        SHUT_RDWR
#else
        SD_BOTH
#endif
    );
  }

  // For these PEERCRED things, the uid reported is the effective uid of
  // the process, which may have been altered due to setuid or similar
  // mechanisms.  We'll treat the other process as an owner if their
  // effective UID matches ours, or if they are root.
  bool peerIsOwner() override {
#ifdef _WIN32
    return true;
#else
    if (!credvalid) {
      return false;
    }
#ifdef SO_PEERCRED
    if (cred.uid == getuid() || cred.uid == 0) {
      return true;
    }
#elif defined(LOCAL_PEERCRED)
    if (cred.cr_uid == getuid() || cred.cr_uid == 0) {
      return true;
    }
#elif defined(SO_RECVUCRED)
    uid_t ucreduid = ucred_getruid(cred.get());
    if (ucreduid == getuid() || ucreduid == 0) {
      return true;
    }
#endif
    return false;
#endif
  }

  pid_t getPeerProcessID() const override {
    if (!credvalid) {
      return 0;
    }
#ifdef SO_PEERCRED
    return cred.pid;
#elif defined(SO_RECVUCRED)
    pid_t ucredpid = ucred_getpid(cred.get());
    if (ucredpid == (pid_t)-1) {
      return 0;
    }
    return ucredpid;
#else
    return 0;
#endif
  }
};
} // namespace

std::unique_ptr<watchman_event> w_event_make_sockets(void) {
  return std::make_unique<PipeEvent>();
}

#define MAX_POLL_EVENTS 63 // Must match MAXIMUM_WAIT_OBJECTS-1 on win
int w_poll_events_sockets(struct watchman_event_poll* p, int n, int timeoutms) {
  struct pollfd pfds[MAX_POLL_EVENTS];
  int i;
  int res;

  if (n > MAX_POLL_EVENTS) {
    // Programmer error :-/
    logf(FATAL, "{} > MAX_POLL_EVENTS ({})\n", n, MAX_POLL_EVENTS);
  }

  for (i = 0; i < n; i++) {
    auto pe = dynamic_cast<PollableEvent*>(p[i].evt);
    w_check(pe != nullptr, "PollableEvent!?");
    pfds[i].fd = pe->getFd();
    pfds[i].events = POLLIN;
    pfds[i].revents = 0;
  }

#ifdef _WIN32
  res = WSAPoll(pfds, n, timeoutms);
  auto win_err = WSAGetLastError();
  errno = map_win32_err(win_err);
#else
  res = poll(pfds, n, timeoutms);
#endif

  for (i = 0; i < n; i++) {
    p[i].ready = pfds[i].revents != 0;
  }

  return res;
}

std::unique_ptr<watchman_stream> w_stm_fdopen(FileDescriptor&& fd) {
  if (!fd) {
    return nullptr;
  }
#ifdef _WIN32
  if (fd.fdType() != FileDescriptor::FDType::Socket) {
    return w_stm_fdopen_windows(std::move(fd));
  }
#endif
  return std::make_unique<UnixStream>(std::move(fd));
}

std::unique_ptr<watchman_stream> w_stm_connect_unix(
    const char* path,
    int timeoutms) {
  struct sockaddr_un un {};
  int max_attempts = timeoutms / 10;
  int attempts = 0;

  if (strlen(path) >= sizeof(un.sun_path) - 1) {
    logf(ERR, "w_stm_connect_unix({}) path is too long\n", path);
    errno = E2BIG;
    return NULL;
  }

  FileDescriptor fd(
      ::socket(
          PF_LOCAL,
#ifdef SOCK_CLOEXEC
          SOCK_CLOEXEC |
#endif
              SOCK_STREAM,
          0),
      FileDescriptor::FDType::Socket);
  if (!fd) {
    return nullptr;
  }
  fd.setCloExec();

  un.sun_family = PF_LOCAL;
  memcpy(un.sun_path, path, strlen(path) + 1);

retry_connect:

  if (::connect(fd.system_handle(), (struct sockaddr*)&un, sizeof(un))) {
#ifdef _WIN32
    int win_err = WSAGetLastError();
    int err = map_win32_err(win_err);
#else
    int err = errno;
#endif

    if (err == ECONNREFUSED || err == ENOENT) {
      if (attempts++ < max_attempts) {
        /* sleep override */ std::this_thread::sleep_for(
            std::chrono::microseconds(10000));
        goto retry_connect;
      }
    }

    logf(
        ERR,
        "w_stm_connect_unix({}) failed to connect: {}\n",
        path,
        folly::errnoStr(err));
    errno = err;
    return nullptr;
  }

  int bufsize = WATCHMAN_IO_BUF_SIZE;
  ::setsockopt(
      fd.system_handle(),
      SOL_SOCKET,
      SO_RCVBUF,
      reinterpret_cast<const char*>(&bufsize),
      sizeof(bufsize));

  return w_stm_fdopen(std::move(fd));
}

#ifndef _WIN32
std::unique_ptr<watchman_stream>
w_stm_open(const char* filename, int flags, ...) {
  int mode = 0;

  // If we're creating, pull out the mode flag
  if (flags & O_CREAT) {
    va_list ap;
    va_start(ap, flags);
    mode = va_arg(ap, int);
    va_end(ap);
  }

  return w_stm_fdopen(FileDescriptor(
      open(filename, flags, mode), FileDescriptor::FDType::Unknown));
}
#endif
<commit_msg>Back out "log when connecting to unix socket fails"<commit_after>/* Copyright 2014-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <folly/SocketAddress.h>
#include <folly/net/NetworkSocket.h>
#include <memory>
#include "FileDescriptor.h"
#include "Pipe.h"

using watchman::FileDescriptor;
using watchman::Pipe;
using namespace watchman;

static const int kWriteTimeout = 60000;

namespace {
// This trait allows w_poll_events to wait on either a PipeEvent or
// a descriptor contained in a UnixStream
class PollableEvent : public watchman_event {
 public:
  virtual FileDescriptor::system_handle_type getFd() const = 0;
};

// The event object, implemented as pipe
class PipeEvent : public PollableEvent {
 public:
  SocketPair pipe;

  void notify() override {
    ignore_result(pipe.write.write("a", 1).hasValue());
  }

  bool testAndClear() override {
    char buf[64];
    bool signalled = false;
    while (true) {
      auto res = pipe.read.read(buf, sizeof(buf));
      if (res.hasError() || res.value() == 0) {
        break;
      }
      signalled = true;
    }
    return signalled;
  }

  FileDescriptor::system_handle_type getFd() const override {
    return pipe.read.system_handle();
  }

  FileDescriptor::system_handle_type system_handle() override {
    return pipe.read.system_handle();
  }

  bool isSocket() override {
    return true;
  }
};

// Event object that UnixStream returns via getEvents.
// It cannot be poked by hand; it is just a helper to
// allow waiting on a socket using w_poll_events.
class FakeSocketEvent : public PollableEvent {
 private:
  FileDescriptor::system_handle_type socket;

 public:
  explicit FakeSocketEvent(FileDescriptor::system_handle_type fd)
      : socket(fd) {}

  void notify() override {}
  bool testAndClear() override {
    return false;
  }
  FileDescriptor::system_handle_type getFd() const override {
    return socket;
  }

  FileDescriptor::system_handle_type system_handle() override {
    return socket;
  }

  bool isSocket() override {
    return true;
  }
};

class UnixStream : public watchman_stream {
 public:
  FileDescriptor fd;
  FakeSocketEvent evt;
#ifdef SO_PEERCRED
  struct ucred cred;
#elif defined(LOCAL_PEERCRED)
  struct xucred cred;
#elif defined(SO_RECVUCRED)
  struct ucred_deleter {
    void operator()(ucred_t* utp) {
      ucred_free(utp);
    }
  };
  std::unique_ptr<ucred_t, ucred_deleter> cred;
#endif
  bool credvalid{false};
  bool blocking_{false};

  explicit UnixStream(FileDescriptor&& descriptor)
      : fd(std::move(descriptor)), evt(fd.system_handle()) {
#ifdef SO_PEERCRED
    socklen_t len = sizeof(cred);
    credvalid = getsockopt(fd.fd(), SOL_SOCKET, SO_PEERCRED, &cred, &len) == 0;
#elif defined(LOCAL_PEERCRED)
    socklen_t len = sizeof(cred);
#if defined(__FreeBSD__) || defined(__DragonFly__)
    credvalid = getsockopt(fd.fd(), 0, LOCAL_PEERCRED, &cred, &len) == 0;
#else
    credvalid =
        getsockopt(fd.fd(), SOL_LOCAL, LOCAL_PEERCRED, &cred, &len) == 0;
#endif
#elif defined(SO_RECVUCRED)
    ucred_t* peer_cred{nullptr};
    credvalid = getpeerucred(fd.fd(), &peer_cred) == 0;
    cred.reset(peer_cred);
#endif
  }

  const FileDescriptor& getFileDescriptor() const override {
    return fd;
  }

  int read(void* buf, int size) override {
    auto res = fd.read(buf, size);
    if (res.hasError()) {
#ifdef _WIN32
      errno = map_win32_err(res.error().value());
#else
      errno = res.error().value();
#endif
      return -1;
    }
    errno = 0;
    return res.value();
  }

  int write(const void* buf, int size) override {
    if (blocking_) {
      int wrote = 0;

      while (size > 0) {
        struct pollfd pfd;
        pfd.fd = fd.system_handle();
        pfd.events = POLLOUT;
#ifdef _WIN32
        if (WSAPoll(&pfd, 1, kWriteTimeout) == 0) {
          errno = map_win32_err(WSAGetLastError());
          break;
        }
#else
        if (poll(&pfd, 1, kWriteTimeout) == 0) {
          break;
        }
#endif
        if (pfd.revents & (POLLERR | POLLHUP)) {
          break;
        }
        auto x = fd.write(buf, size);
        if (x.hasError()) {
#ifdef _WIN32
          errno = map_win32_err(x.error().value());
#else
          errno = x.error().value();
#endif
          break;
        }
        if (x.value() == 0) {
          errno = 0;
          break;
        }

        wrote += x.value();
        size -= x.value();
        buf = reinterpret_cast<const void*>(
            reinterpret_cast<const char*>(buf) + x.value());
      }
      return wrote == 0 ? -1 : wrote;
    }
    auto x = fd.write(buf, size);
    if (x.hasError()) {
#ifdef _WIN32
      errno = map_win32_err(x.error().value());
#else
      errno = x.error().value();
#endif
      return -1;
    }
    errno = 0;
    return x.value();
  }

  w_evt_t getEvents() override {
    return &evt;
  }

  void setNonBlock(bool nonb) override {
    if (nonb) {
      fd.setNonBlock();
    } else {
      fd.clearNonBlock();
    }
    blocking_ = !nonb;
  }

  bool rewind() override {
#ifndef _WIN32
    return lseek(fd.fd(), 0, SEEK_SET) == 0;
#else
    return false;
#endif
  }

  bool shutdown() override {
    return ::shutdown(
        fd.system_handle(),
#ifdef SHUT_RDWR
        SHUT_RDWR
#else
        SD_BOTH
#endif
    );
  }

  // For these PEERCRED things, the uid reported is the effective uid of
  // the process, which may have been altered due to setuid or similar
  // mechanisms.  We'll treat the other process as an owner if their
  // effective UID matches ours, or if they are root.
  bool peerIsOwner() override {
#ifdef _WIN32
    return true;
#else
    if (!credvalid) {
      return false;
    }
#ifdef SO_PEERCRED
    if (cred.uid == getuid() || cred.uid == 0) {
      return true;
    }
#elif defined(LOCAL_PEERCRED)
    if (cred.cr_uid == getuid() || cred.cr_uid == 0) {
      return true;
    }
#elif defined(SO_RECVUCRED)
    uid_t ucreduid = ucred_getruid(cred.get());
    if (ucreduid == getuid() || ucreduid == 0) {
      return true;
    }
#endif
    return false;
#endif
  }

  pid_t getPeerProcessID() const override {
    if (!credvalid) {
      return 0;
    }
#ifdef SO_PEERCRED
    return cred.pid;
#elif defined(SO_RECVUCRED)
    pid_t ucredpid = ucred_getpid(cred.get());
    if (ucredpid == (pid_t)-1) {
      return 0;
    }
    return ucredpid;
#else
    return 0;
#endif
  }
};
} // namespace

std::unique_ptr<watchman_event> w_event_make_sockets(void) {
  return std::make_unique<PipeEvent>();
}

#define MAX_POLL_EVENTS 63 // Must match MAXIMUM_WAIT_OBJECTS-1 on win
int w_poll_events_sockets(struct watchman_event_poll* p, int n, int timeoutms) {
  struct pollfd pfds[MAX_POLL_EVENTS];
  int i;
  int res;

  if (n > MAX_POLL_EVENTS) {
    // Programmer error :-/
    logf(FATAL, "{} > MAX_POLL_EVENTS ({})\n", n, MAX_POLL_EVENTS);
  }

  for (i = 0; i < n; i++) {
    auto pe = dynamic_cast<PollableEvent*>(p[i].evt);
    w_check(pe != nullptr, "PollableEvent!?");
    pfds[i].fd = pe->getFd();
    pfds[i].events = POLLIN;
    pfds[i].revents = 0;
  }

#ifdef _WIN32
  res = WSAPoll(pfds, n, timeoutms);
  auto win_err = WSAGetLastError();
  errno = map_win32_err(win_err);
#else
  res = poll(pfds, n, timeoutms);
#endif

  for (i = 0; i < n; i++) {
    p[i].ready = pfds[i].revents != 0;
  }

  return res;
}

std::unique_ptr<watchman_stream> w_stm_fdopen(FileDescriptor&& fd) {
  if (!fd) {
    return nullptr;
  }
#ifdef _WIN32
  if (fd.fdType() != FileDescriptor::FDType::Socket) {
    return w_stm_fdopen_windows(std::move(fd));
  }
#endif
  return std::make_unique<UnixStream>(std::move(fd));
}

std::unique_ptr<watchman_stream> w_stm_connect_unix(
    const char* path,
    int timeoutms) {
  struct sockaddr_un un {};
  int max_attempts = timeoutms / 10;
  int attempts = 0;

  if (strlen(path) >= sizeof(un.sun_path) - 1) {
    logf(ERR, "w_stm_connect_unix({}) path is too long\n", path);
    errno = E2BIG;
    return NULL;
  }

  FileDescriptor fd(
      ::socket(
          PF_LOCAL,
#ifdef SOCK_CLOEXEC
          SOCK_CLOEXEC |
#endif
              SOCK_STREAM,
          0),
      FileDescriptor::FDType::Socket);
  if (!fd) {
    return nullptr;
  }
  fd.setCloExec();

  un.sun_family = PF_LOCAL;
  memcpy(un.sun_path, path, strlen(path) + 1);

retry_connect:

  if (::connect(fd.system_handle(), (struct sockaddr*)&un, sizeof(un))) {
#ifdef _WIN32
    int win_err = WSAGetLastError();
    int err = map_win32_err(win_err);
#else
    int err = errno;
#endif

    if (err == ECONNREFUSED || err == ENOENT) {
      if (attempts++ < max_attempts) {
        /* sleep override */ std::this_thread::sleep_for(
            std::chrono::microseconds(10000));
        goto retry_connect;
      }
    }

    errno = err;
    return nullptr;
  }

  int bufsize = WATCHMAN_IO_BUF_SIZE;
  ::setsockopt(
      fd.system_handle(),
      SOL_SOCKET,
      SO_RCVBUF,
      reinterpret_cast<const char*>(&bufsize),
      sizeof(bufsize));

  return w_stm_fdopen(std::move(fd));
}

#ifndef _WIN32
std::unique_ptr<watchman_stream>
w_stm_open(const char* filename, int flags, ...) {
  int mode = 0;

  // If we're creating, pull out the mode flag
  if (flags & O_CREAT) {
    va_list ap;
    va_start(ap, flags);
    mode = va_arg(ap, int);
    va_end(ap);
  }

  return w_stm_fdopen(FileDescriptor(
      open(filename, flags, mode), FileDescriptor::FDType::Unknown));
}
#endif
<|endoftext|>


<commit_before>/***********************************************************************
filename:   SampleData.cpp
created:    4/6/2012
author:     Lukas E Meindl
*************************************************************************/
/***************************************************************************
*   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
*
*   Permission is hereby granted, free of charge, to any person obtaining
*   a copy of this software and associated documentation files (the
*   "Software"), to deal in the Software without restriction, including
*   without limitation the rights to use, copy, modify, merge, publish,
*   distribute, sublicense, and/or sell copies of the Software, and to
*   permit persons to whom the Software is furnished to do so, subject to
*   the following conditions:
*
*   The above copyright notice and this permission notice shall be
*   included in all copies or substantial portions of the Software.
*
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "SampleData.h"
#include "Sample.h"

#include "Samples_xmlHandler.h"

#include "CEGUI/DynamicModule.h"
#include "CEGUI/Version.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "CEGUI/TextureTarget.h"
#include "CEGUI/BasicImage.h"
#include "CEGUI/GUIContext.h"
#include "CEGUI/Texture.h"
#include "CEGUI/ImageManager.h"
#include "CEGUI/Window.h"

using namespace CEGUI;

#define S_(X) #X
#define STRINGIZE(X) S_(X)

typedef Sample& (*getSampleInstance)();
#define GetSampleInstanceFuncName "getSampleInstance"

SampleData::SampleData(CEGUI::String sampleName, CEGUI::String summary,
    CEGUI::String description, SampleType sampleTypeEnum)
    : d_name(sampleName),
    d_summary(summary),
    d_description(description),
    d_type(sampleTypeEnum),
    d_guiContext(0),
    d_textureTarget(0),
    d_textureTargetImage(0),
    d_sampleWindow(0),
    d_usedFilesString("")
{
}

SampleData::~SampleData()
{

}

CEGUI::String SampleData::getName()
{
    return d_name;
}

CEGUI::String SampleData::getSummary()
{
    return d_summary;
}

CEGUI::String SampleData::getSampleTypeString()
{
    switch(d_type)
    {
    case ST_Module:
        return SampleDataHandler::SampleTypeCppModule;
        break;
    case ST_Lua:
        return SampleDataHandler::SampleTypeLua;
        break;
    case ST_Python:
        return SampleDataHandler::SampleTypePython;
    default:
        return "";
    }
}

CEGUI::String SampleData::getDescription()
{
    return d_description;
}

CEGUI::String SampleData::getUsedFilesString()
{
    return d_usedFilesString;
}

void SampleData::setSampleWindow(CEGUI::Window* sampleWindow)
{
    d_sampleWindow = sampleWindow;
}

CEGUI::Window* SampleData::getSampleWindow()
{
    return d_sampleWindow;
}

void SampleData::initialise()
{
    CEGUI::System& system(System::getSingleton());

    d_textureTarget = system.getRenderer()->createTextureTarget();
    d_guiContext = &system.createGUIContext((RenderTarget&)*d_textureTarget);

    CEGUI::String imageName(d_textureTarget->getTexture().getName());
    d_textureTargetImage = static_cast<CEGUI::BasicImage*>(&CEGUI::ImageManager::getSingleton().create("BasicImage", "SampleBrowser/" + imageName));
    d_textureTargetImage->setTexture(&d_textureTarget->getTexture());
}

void SampleData::deinitialise()
{
    CEGUI::System& system(System::getSingleton());

    if(d_guiContext)
    {
        system.destroyGUIContext(*d_guiContext);
        d_guiContext = 0;
    }

    if(d_textureTarget)
    {
        system.getRenderer()->destroyTextureTarget(d_textureTarget);
        d_textureTarget = 0;
    }
}

GUIContext* SampleData::getGuiContext()
{
    return d_guiContext;
}

void SampleData::handleNewWindowSize(float width, float height)
{
    CEGUI::Sizef windowSize(width, height);
    CEGUI::Rectf renderArea(CEGUI::Rectf(0.f, height, width, 0.f));

    d_textureTargetImage->setArea(renderArea);
    d_textureTarget->declareRenderSize(windowSize);

    d_sampleWindow->getRenderingSurface()->invalidate();
}

CEGUI::Image& SampleData::getRTTImage()
{
    return *d_textureTargetImage;
}

void SampleData::setGUIContextRTT()
{
    d_guiContext->setRenderTarget(*d_textureTarget);
}

void SampleData::clearRTTTexture()
{
    d_textureTarget->clear();
}

SampleDataModule::SampleDataModule(CEGUI::String sampleName, CEGUI::String summary,
    CEGUI::String description, SampleType sampleTypeEnum)
    : SampleData(sampleName, summary, description ,sampleTypeEnum)
{

}

SampleDataModule::~SampleDataModule()
{
}

void SampleDataModule::initialise()
{
    SampleData::initialise();

    getSampleInstanceFromDLL();

    d_usedFilesString = d_sample->getUsedFilesString();
    d_sample->initialise(d_guiContext);
}

void SampleDataModule::deinitialise()
{
    SampleData::deinitialise();

    d_sample->deinitialise();
}

void SampleDataModule::getSampleInstanceFromDLL()
{
    // Version suffix for the dlls
    static const CEGUI::String versionSuffix( "-" STRINGIZE(CEGUI_VERSION_MAJOR) "." STRINGIZE(CEGUI_VERSION_MINOR) );

    CEGUI::DynamicModule* sampleModule = new CEGUI::DynamicModule(d_name + versionSuffix);
    getSampleInstance functionPointerGetSample = (getSampleInstance)sampleModule->getSymbolAddress(CEGUI::String(GetSampleInstanceFuncName));

    if(functionPointerGetSample == 0)
    {
        CEGUI::String errorMessage = "The sample creation function is not defined in the dynamic library of " + d_name;
        CEGUI_THROW(CEGUI::InvalidRequestException(errorMessage.c_str()));
    }

    d_sample =  &(functionPointerGetSample());
}<commit_msg>MOD: Start size fix<commit_after>/***********************************************************************
filename:   SampleData.cpp
created:    4/6/2012
author:     Lukas E Meindl
*************************************************************************/
/***************************************************************************
*   Copyright (C) 2004 - 2012 Paul D Turner & The CEGUI Development Team
*
*   Permission is hereby granted, free of charge, to any person obtaining
*   a copy of this software and associated documentation files (the
*   "Software"), to deal in the Software without restriction, including
*   without limitation the rights to use, copy, modify, merge, publish,
*   distribute, sublicense, and/or sell copies of the Software, and to
*   permit persons to whom the Software is furnished to do so, subject to
*   the following conditions:
*
*   The above copyright notice and this permission notice shall be
*   included in all copies or substantial portions of the Software.
*
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "SampleData.h"
#include "Sample.h"

#include "Samples_xmlHandler.h"

#include "CEGUI/DynamicModule.h"
#include "CEGUI/Version.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/System.h"
#include "CEGUI/TextureTarget.h"
#include "CEGUI/BasicImage.h"
#include "CEGUI/GUIContext.h"
#include "CEGUI/Texture.h"
#include "CEGUI/ImageManager.h"
#include "CEGUI/Window.h"

using namespace CEGUI;

#define S_(X) #X
#define STRINGIZE(X) S_(X)

typedef Sample& (*getSampleInstance)();
#define GetSampleInstanceFuncName "getSampleInstance"

SampleData::SampleData(CEGUI::String sampleName, CEGUI::String summary,
    CEGUI::String description, SampleType sampleTypeEnum)
    : d_name(sampleName),
    d_summary(summary),
    d_description(description),
    d_type(sampleTypeEnum),
    d_guiContext(0),
    d_textureTarget(0),
    d_textureTargetImage(0),
    d_sampleWindow(0),
    d_usedFilesString("")
{
}

SampleData::~SampleData()
{

}

CEGUI::String SampleData::getName()
{
    return d_name;
}

CEGUI::String SampleData::getSummary()
{
    return d_summary;
}

CEGUI::String SampleData::getSampleTypeString()
{
    switch(d_type)
    {
    case ST_Module:
        return SampleDataHandler::SampleTypeCppModule;
        break;
    case ST_Lua:
        return SampleDataHandler::SampleTypeLua;
        break;
    case ST_Python:
        return SampleDataHandler::SampleTypePython;
    default:
        return "";
    }
}

CEGUI::String SampleData::getDescription()
{
    return d_description;
}

CEGUI::String SampleData::getUsedFilesString()
{
    return d_usedFilesString;
}

void SampleData::setSampleWindow(CEGUI::Window* sampleWindow)
{
    d_sampleWindow = sampleWindow;
}

CEGUI::Window* SampleData::getSampleWindow()
{
    return d_sampleWindow;
}

void SampleData::initialise()
{
    CEGUI::System& system(System::getSingleton());

    d_textureTarget = system.getRenderer()->createTextureTarget();
    d_guiContext = &system.createGUIContext((RenderTarget&)*d_textureTarget);
    d_textureTarget->declareRenderSize(CEGUI::Sizef(200.f, 200.f));

    CEGUI::String imageName(d_textureTarget->getTexture().getName());
    d_textureTargetImage = static_cast<CEGUI::BasicImage*>(&CEGUI::ImageManager::getSingleton().create("BasicImage", "SampleBrowser/" + imageName));
    d_textureTargetImage->setTexture(&d_textureTarget->getTexture());
}

void SampleData::deinitialise()
{
    CEGUI::System& system(System::getSingleton());

    if(d_guiContext)
    {
        system.destroyGUIContext(*d_guiContext);
        d_guiContext = 0;
    }

    if(d_textureTarget)
    {
        system.getRenderer()->destroyTextureTarget(d_textureTarget);
        d_textureTarget = 0;
    }
}

GUIContext* SampleData::getGuiContext()
{
    return d_guiContext;
}

void SampleData::handleNewWindowSize(float width, float height)
{
    CEGUI::Sizef windowSize(width, height);
    CEGUI::Rectf renderArea(CEGUI::Rectf(0.f, height, width, 0.f));

    d_textureTargetImage->setArea(renderArea);
    d_textureTarget->declareRenderSize(windowSize);

    d_sampleWindow->getRenderingSurface()->invalidate();
}

CEGUI::Image& SampleData::getRTTImage()
{
    return *d_textureTargetImage;
}

void SampleData::setGUIContextRTT()
{
    d_guiContext->setRenderTarget(*d_textureTarget);
}

void SampleData::clearRTTTexture()
{
    d_textureTarget->clear();
}

SampleDataModule::SampleDataModule(CEGUI::String sampleName, CEGUI::String summary,
    CEGUI::String description, SampleType sampleTypeEnum)
    : SampleData(sampleName, summary, description ,sampleTypeEnum)
{

}

SampleDataModule::~SampleDataModule()
{
}

void SampleDataModule::initialise()
{
    SampleData::initialise();

    getSampleInstanceFromDLL();

    d_usedFilesString = d_sample->getUsedFilesString();
    d_sample->initialise(d_guiContext);
}

void SampleDataModule::deinitialise()
{
    SampleData::deinitialise();

    d_sample->deinitialise();
}

void SampleDataModule::getSampleInstanceFromDLL()
{
    // Version suffix for the dlls
    static const CEGUI::String versionSuffix( "-" STRINGIZE(CEGUI_VERSION_MAJOR) "." STRINGIZE(CEGUI_VERSION_MINOR) );

    CEGUI::DynamicModule* sampleModule = new CEGUI::DynamicModule(d_name + versionSuffix);
    getSampleInstance functionPointerGetSample = (getSampleInstance)sampleModule->getSymbolAddress(CEGUI::String(GetSampleInstanceFuncName));

    if(functionPointerGetSample == 0)
    {
        CEGUI::String errorMessage = "The sample creation function is not defined in the dynamic library of " + d_name;
        CEGUI_THROW(CEGUI::InvalidRequestException(errorMessage.c_str()));
    }

    d_sample =  &(functionPointerGetSample());
}<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/fastos/fastos.h>
#include "document_iterator.h"
#include <vespa/document/select/gid_filter.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/persistence/spi/docentry.h>
#include <algorithm>
#include <vespa/log/log.h>
LOG_SETUP(".proton.persistenceengine.document_iterator");

using storage::spi::IterateResult;
using storage::spi::DocEntry;
using storage::spi::Timestamp;
using document::Document;
using document::DocumentId;

namespace proton {

namespace {

DocEntry *createDocEntry(Timestamp timestamp, bool removed) {
    int flags = removed ? storage::spi::REMOVE_ENTRY : storage::spi::NONE;
    return new DocEntry(timestamp, flags);
}

DocEntry *createDocEntry(Timestamp timestamp, bool removed, Document::UP doc, ssize_t defaultSerializedSize) {
    if (doc) {
        if (removed) {
            return new DocEntry(timestamp, storage::spi::REMOVE_ENTRY, doc->getId());
        } else {
            ssize_t serializedSize = defaultSerializedSize >= 0 ? defaultSerializedSize : doc->getSerializedSize();
            return new DocEntry(timestamp, storage::spi::NONE, std::move(doc), serializedSize);
        }
    } else {
        return createDocEntry(timestamp, removed);
    }
}

} // namespace proton::<unnamed>

bool
DocumentIterator::useDocumentSelection() const
{
    return (!_metaOnly &&
            !_selection.getDocumentSelection().getDocumentSelection().empty());
}

bool
DocumentIterator::checkMeta(const search::DocumentMetaData &meta) const
{
    if (!meta.valid()) {
        return false;
    }
    if (!_selection.getTimestampSubset().empty()) {
        return (std::binary_search(_selection.getTimestampSubset().begin(),
                                   _selection.getTimestampSubset().end(),
                                   Timestamp(meta.timestamp)));
    }
    if ((meta.timestamp < _selection.getFromTimestamp()) ||
        (meta.timestamp > _selection.getToTimestamp()))
    {
        return false;
    }
    if ((_versions == storage::spi::NEWEST_DOCUMENT_ONLY) && meta.removed) {
        return false;
    }
    return true;
}

DocumentIterator::DocumentIterator(const storage::spi::Bucket &bucket,
                                   const document::FieldSet& fields,
                                   const storage::spi::Selection &selection,
                                   storage::spi::IncludedVersions versions,
                                   ssize_t defaultSerializedSize,
                                   bool ignoreMaxBytes,
                                   ReadConsistency readConsistency)
    : _bucket(bucket),
      _selection(selection),
      _versions(versions),
      _fields(fields.clone()),
      _defaultSerializedSize(defaultSerializedSize),
      _readConsistency(readConsistency),
      _metaOnly(fields.getType() == document::FieldSet::NONE),
      _ignoreMaxBytes(ignoreMaxBytes),
      _sources(),
      _nextItem(0),
      _list()
{
}

void
DocumentIterator::add(const IDocumentRetriever::SP &retriever)
{
    _sources.push_back(retriever);
}

IterateResult
DocumentIterator::iterate(size_t maxBytes)
{
    if (_list.empty()) {
        for (const IDocumentRetriever::SP & source : _sources) {
            fetchCompleteSource(*source, _list);
        }
    }
    if ( _ignoreMaxBytes ) {
        return IterateResult(std::move(_list), true);
    } else {
        IterateResult::List results;
        for (size_t sz(0); (_nextItem < _list.size()) && ((sz < maxBytes) || results.empty()); _nextItem++) {
            DocEntry::LP & item = _list[_nextItem];
            sz += item->getSize();
            results.push_back(item);
            item.reset();
        }
        return IterateResult(results, _nextItem >= _list.size());
    }
}

namespace {

class Match {
public:
    Match(const IDocumentRetriever & source, bool metaOnly, const vespalib::string & selection) :
        _dscTrue(true),
        _metaOnly(metaOnly),
        _willAlwaysFail(false),
        _docidLimit(source.getDocIdLimit())
    {
        if (!(_metaOnly || selection.empty())) {
            LOG(spam, "ParseSelect: %s", selection.c_str());
            _cs = source.parseSelect(selection);
            CachedSelect &cs(*_cs);
            _dscTrue = cs._allTrue;
            if (cs._allFalse || cs._allInvalid) {
                assert(!_dscTrue);
                LOG(debug, "Nothing will ever match cs._allFalse = '%d' cs._allInvalid = '%d'", cs._allFalse, cs._allInvalid);
                _willAlwaysFail = true;
            } else {
                _select = (cs._attrSelect ? cs._attrSelect->clone()
                                          : cs._select->clone());
                using document::select::GidFilter;
                _gidFilter = GidFilter::for_selection_root_node(*_select);
                _sc.reset(new SelectContext(*_cs));
                _sc->getAttributeGuards();
            }
        } else {
            _dscTrue = true;
        }
    }

    ~Match() {
        if (_sc) {
            _sc->dropAttributeGuards();
        }
    }

    bool willAlwaysFail() const { return _willAlwaysFail; }

    bool match(const search::DocumentMetaData & meta) const {
        if (_dscTrue || _metaOnly) {
            return true;
        }
        if (meta.lid >= _docidLimit) {
            return false;
        }
        if (_sc) {
            _sc->_docId = meta.lid;
        }
        if (!_gidFilter.gid_might_match_selection(meta.gid)) {
            return false;
        }
        return (! _cs->_attrSelect) ||
                (_cs->_attrSelect && (_select->contains(*_sc) == document::select::Result::True));
    }
    bool match(const search::DocumentMetaData & meta, const Document * doc) const {
        if (_dscTrue || _metaOnly) {
            return true;
        }
        return (doc && (doc->getId().getGlobalId() == meta.gid) &&
               (_cs->_attrSelect || (_select->contains(*doc) == document::select::Result::True)));
    }
private:
    bool                           _dscTrue;
    bool                           _metaOnly;
    bool                           _willAlwaysFail;
    uint32_t                       _docidLimit;
    CachedSelect::SP               _cs;
    document::select::Node::UP     _select;
    document::select::GidFilter    _gidFilter;
    std::unique_ptr<SelectContext> _sc;
};

typedef vespalib::hash_map<uint32_t, uint32_t> LidIndexMap;

class MatchVisitor : public search::IDocumentVisitor
{
public:
    MatchVisitor(const Match & matcher, const search::DocumentMetaData::Vector & metaData,
                 const LidIndexMap & lidIndexMap, const document::FieldSet * fields, IterateResult::List & list,
                 ssize_t defaultSerializedSize) :
        _matcher(matcher),
        _metaData(metaData),
        _lidIndexMap(lidIndexMap),
        _fields(fields),
        _list(list),
        _defaultSerializedSize(defaultSerializedSize)
    { }
    void visit(uint32_t lid, document::Document::UP doc) override {
        const search::DocumentMetaData & meta = _metaData[_lidIndexMap[lid]];
        assert(lid == meta.lid);
        if (_matcher.match(meta, doc.get())) {
            if (doc && _fields) {
                document::FieldSet::stripFields(*doc, *_fields);
            }
            _list.emplace_back(createDocEntry(meta.timestamp, meta.removed, std::move(doc), _defaultSerializedSize));
        }
    }
private:
    const Match                            & _matcher;
    const search::DocumentMetaData::Vector & _metaData;
    const LidIndexMap                      & _lidIndexMap;
    const document::FieldSet               * _fields;
    IterateResult::List                    & _list;
    size_t                                   _defaultSerializedSize;
};

}

void
DocumentIterator::fetchCompleteSource(const IDocumentRetriever & source, IterateResult::List & list)
{
    IDocumentRetriever::ReadGuard sourceReadGuard(source.getReadGuard());
    search::DocumentMetaData::Vector metaData;
    source.getBucketMetaData(_bucket, metaData);
    if (metaData.empty()) {
        return;
    }
    LOG(debug, "metadata count before filtering: %zu", metaData.size());

    Match matcher(source, _metaOnly, _selection.getDocumentSelection().getDocumentSelection());
    if (matcher.willAlwaysFail()) {
        return;
    }

    LidIndexMap lidIndexMap(3*metaData.size());
    IDocumentRetriever::LidVector lidsToFetch;
    lidsToFetch.reserve(metaData.size());
    for (size_t i(0); i < metaData.size(); i++) {
        const search::DocumentMetaData & meta = metaData[i];
        if (checkMeta(meta)) {
            if (matcher.match(meta)) {
                lidsToFetch.emplace_back(meta.lid);
                lidIndexMap[meta.lid] = i;
            }
        }
    }
    LOG(debug, "metadata count after filtering: %zu", lidsToFetch.size());

    if ( _metaOnly ) {
        for (uint32_t lid : lidsToFetch) {
            const search::DocumentMetaData & meta = metaData[lidIndexMap[lid]];
            assert(lid == meta.lid);
            list.emplace_back(createDocEntry(meta.timestamp, meta.removed));
        }
    } else {
        MatchVisitor visitor(matcher, metaData, lidIndexMap, _fields.get(), list, _defaultSerializedSize);
        source.visitDocuments(lidsToFetch, visitor, _readConsistency);
    }

}

} // namespace proton
<commit_msg>Holding the lidlimit is mandatory.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/fastos/fastos.h>
#include "document_iterator.h"
#include <vespa/document/select/gid_filter.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/persistence/spi/docentry.h>
#include <algorithm>
#include <vespa/log/log.h>
LOG_SETUP(".proton.persistenceengine.document_iterator");

using storage::spi::IterateResult;
using storage::spi::DocEntry;
using storage::spi::Timestamp;
using document::Document;
using document::DocumentId;

namespace proton {

namespace {

DocEntry *createDocEntry(Timestamp timestamp, bool removed) {
    int flags = removed ? storage::spi::REMOVE_ENTRY : storage::spi::NONE;
    return new DocEntry(timestamp, flags);
}

DocEntry *createDocEntry(Timestamp timestamp, bool removed, Document::UP doc, ssize_t defaultSerializedSize) {
    if (doc) {
        if (removed) {
            return new DocEntry(timestamp, storage::spi::REMOVE_ENTRY, doc->getId());
        } else {
            ssize_t serializedSize = defaultSerializedSize >= 0 ? defaultSerializedSize : doc->getSerializedSize();
            return new DocEntry(timestamp, storage::spi::NONE, std::move(doc), serializedSize);
        }
    } else {
        return createDocEntry(timestamp, removed);
    }
}

} // namespace proton::<unnamed>

bool
DocumentIterator::useDocumentSelection() const
{
    return (!_metaOnly &&
            !_selection.getDocumentSelection().getDocumentSelection().empty());
}

bool
DocumentIterator::checkMeta(const search::DocumentMetaData &meta) const
{
    if (!meta.valid()) {
        return false;
    }
    if (!_selection.getTimestampSubset().empty()) {
        return (std::binary_search(_selection.getTimestampSubset().begin(),
                                   _selection.getTimestampSubset().end(),
                                   Timestamp(meta.timestamp)));
    }
    if ((meta.timestamp < _selection.getFromTimestamp()) ||
        (meta.timestamp > _selection.getToTimestamp()))
    {
        return false;
    }
    if ((_versions == storage::spi::NEWEST_DOCUMENT_ONLY) && meta.removed) {
        return false;
    }
    return true;
}

DocumentIterator::DocumentIterator(const storage::spi::Bucket &bucket,
                                   const document::FieldSet& fields,
                                   const storage::spi::Selection &selection,
                                   storage::spi::IncludedVersions versions,
                                   ssize_t defaultSerializedSize,
                                   bool ignoreMaxBytes,
                                   ReadConsistency readConsistency)
    : _bucket(bucket),
      _selection(selection),
      _versions(versions),
      _fields(fields.clone()),
      _defaultSerializedSize(defaultSerializedSize),
      _readConsistency(readConsistency),
      _metaOnly(fields.getType() == document::FieldSet::NONE),
      _ignoreMaxBytes(ignoreMaxBytes),
      _sources(),
      _nextItem(0),
      _list()
{
}

void
DocumentIterator::add(const IDocumentRetriever::SP &retriever)
{
    _sources.push_back(retriever);
}

IterateResult
DocumentIterator::iterate(size_t maxBytes)
{
    if (_list.empty()) {
        for (const IDocumentRetriever::SP & source : _sources) {
            fetchCompleteSource(*source, _list);
        }
    }
    if ( _ignoreMaxBytes ) {
        return IterateResult(std::move(_list), true);
    } else {
        IterateResult::List results;
        for (size_t sz(0); (_nextItem < _list.size()) && ((sz < maxBytes) || results.empty()); _nextItem++) {
            DocEntry::LP & item = _list[_nextItem];
            sz += item->getSize();
            results.push_back(item);
            item.reset();
        }
        return IterateResult(results, _nextItem >= _list.size());
    }
}

namespace {

class Match {
public:
    Match(const IDocumentRetriever & source, bool metaOnly, const vespalib::string & selection) :
        _dscTrue(true),
        _metaOnly(metaOnly),
        _willAlwaysFail(false),
        _docidLimit(source.getDocIdLimit())
    {
        if (!(_metaOnly || selection.empty())) {
            LOG(spam, "ParseSelect: %s", selection.c_str());
            _cs = source.parseSelect(selection);
            CachedSelect &cs(*_cs);
            _dscTrue = cs._allTrue;
            if (cs._allFalse || cs._allInvalid) {
                assert(!_dscTrue);
                LOG(debug, "Nothing will ever match cs._allFalse = '%d' cs._allInvalid = '%d'", cs._allFalse, cs._allInvalid);
                _willAlwaysFail = true;
            } else {
                _select = (cs._attrSelect ? cs._attrSelect->clone()
                                          : cs._select->clone());
                using document::select::GidFilter;
                _gidFilter = GidFilter::for_selection_root_node(*_select);
                _sc.reset(new SelectContext(*_cs));
                _sc->getAttributeGuards();
            }
        } else {
            _dscTrue = true;
        }
    }

    ~Match() {
        if (_sc) {
            _sc->dropAttributeGuards();
        }
    }

    bool willAlwaysFail() const { return _willAlwaysFail; }

    bool match(const search::DocumentMetaData & meta) const {
        if (meta.lid >= _docidLimit) {
            return false;
        }
        if (_dscTrue || _metaOnly) {
            return true;
        }
        if (_sc) {
            _sc->_docId = meta.lid;
        }
        if (!_gidFilter.gid_might_match_selection(meta.gid)) {
            return false;
        }
        return (! _cs->_attrSelect) ||
                (_cs->_attrSelect && (_select->contains(*_sc) == document::select::Result::True));
    }
    bool match(const search::DocumentMetaData & meta, const Document * doc) const {
        if (_dscTrue || _metaOnly) {
            return true;
        }
        return (doc && (doc->getId().getGlobalId() == meta.gid) &&
               (_cs->_attrSelect || (_select->contains(*doc) == document::select::Result::True)));
    }
private:
    bool                           _dscTrue;
    bool                           _metaOnly;
    bool                           _willAlwaysFail;
    uint32_t                       _docidLimit;
    CachedSelect::SP               _cs;
    document::select::Node::UP     _select;
    document::select::GidFilter    _gidFilter;
    std::unique_ptr<SelectContext> _sc;
};

typedef vespalib::hash_map<uint32_t, uint32_t> LidIndexMap;

class MatchVisitor : public search::IDocumentVisitor
{
public:
    MatchVisitor(const Match & matcher, const search::DocumentMetaData::Vector & metaData,
                 const LidIndexMap & lidIndexMap, const document::FieldSet * fields, IterateResult::List & list,
                 ssize_t defaultSerializedSize) :
        _matcher(matcher),
        _metaData(metaData),
        _lidIndexMap(lidIndexMap),
        _fields(fields),
        _list(list),
        _defaultSerializedSize(defaultSerializedSize)
    { }
    void visit(uint32_t lid, document::Document::UP doc) override {
        const search::DocumentMetaData & meta = _metaData[_lidIndexMap[lid]];
        assert(lid == meta.lid);
        if (_matcher.match(meta, doc.get())) {
            if (doc && _fields) {
                document::FieldSet::stripFields(*doc, *_fields);
            }
            _list.emplace_back(createDocEntry(meta.timestamp, meta.removed, std::move(doc), _defaultSerializedSize));
        }
    }
private:
    const Match                            & _matcher;
    const search::DocumentMetaData::Vector & _metaData;
    const LidIndexMap                      & _lidIndexMap;
    const document::FieldSet               * _fields;
    IterateResult::List                    & _list;
    size_t                                   _defaultSerializedSize;
};

}

void
DocumentIterator::fetchCompleteSource(const IDocumentRetriever & source, IterateResult::List & list)
{
    IDocumentRetriever::ReadGuard sourceReadGuard(source.getReadGuard());
    search::DocumentMetaData::Vector metaData;
    source.getBucketMetaData(_bucket, metaData);
    if (metaData.empty()) {
        return;
    }
    LOG(debug, "metadata count before filtering: %zu", metaData.size());

    Match matcher(source, _metaOnly, _selection.getDocumentSelection().getDocumentSelection());
    if (matcher.willAlwaysFail()) {
        return;
    }

    LidIndexMap lidIndexMap(3*metaData.size());
    IDocumentRetriever::LidVector lidsToFetch;
    lidsToFetch.reserve(metaData.size());
    for (size_t i(0); i < metaData.size(); i++) {
        const search::DocumentMetaData & meta = metaData[i];
        if (checkMeta(meta)) {
            if (matcher.match(meta)) {
                lidsToFetch.emplace_back(meta.lid);
                lidIndexMap[meta.lid] = i;
            }
        }
    }
    LOG(debug, "metadata count after filtering: %zu", lidsToFetch.size());

    if ( _metaOnly ) {
        for (uint32_t lid : lidsToFetch) {
            const search::DocumentMetaData & meta = metaData[lidIndexMap[lid]];
            assert(lid == meta.lid);
            list.emplace_back(createDocEntry(meta.timestamp, meta.removed));
        }
    } else {
        MatchVisitor visitor(matcher, metaData, lidIndexMap, _fields.get(), list, _defaultSerializedSize);
        source.visitDocuments(lidsToFetch, visitor, _readConsistency);
    }

}

} // namespace proton
<|endoftext|>


<commit_before>#include <algorithm>
#include <ctime>

#include "caffe2/core/net.h"
#include "caffe2/core/operator.h"
#include "caffe2/core/workspace.h"
#include "caffe2/proto/caffe2.pb.h"

namespace caffe2 {

// TODO(Yangqing): move all the checks to a less fatal check mechanism.
OperatorBase::OperatorBase(const OperatorDef& operator_def, Workspace* ws)
    : operator_def_(operator_def) {
  for (auto& arg : operator_def.arg()) {
    CHECK_GT(arg.name().size(), 0) << "Argument must have a name.";
    CHECK_EQ(arg_map_.count(arg.name()), 0) << "Duplicated argument name.";
    arg_map_[arg.name()] = &arg;
  }
  for (const string& input_str : operator_def_.input()) {
    inputs_.push_back(CHECK_NOTNULL(ws->GetBlob(input_str)));
  }
  for (const string& output_str : operator_def_.output()) {
    outputs_.push_back(CHECK_NOTNULL(ws->CreateBlob(output_str)));
  }
}

// Parameter getters. You can use these to get the arguments that you want.
// We need to deal with the fact that we cannot really template into
// protocol buffers... yuck.
#define INSTANTIATE_GET_SINGLE_ARGUMENT(dtype, fieldname)                      \
template <>                                                                    \
dtype OperatorBase::GetSingleArgument<dtype>(                                  \
    const string& name, const dtype& default_value) {                          \
  if (arg_map_.count(name) == 0) {                                             \
    DVLOG(1) << "Using default parameter value " << default_value;             \
    return default_value;                                                      \
  }                                                                            \
  CHECK(arg_map_[name]->has_##fieldname())                                     \
      << "Argument does not have the right field: expected "                   \
      << #fieldname;                                                           \
  return arg_map_[name]->fieldname();                                          \
}

INSTANTIATE_GET_SINGLE_ARGUMENT(float, f)
INSTANTIATE_GET_SINGLE_ARGUMENT(int, i)
INSTANTIATE_GET_SINGLE_ARGUMENT(string, s)
// Undefine the argument just to be safe.
#undef INSTANTIATE_GET_SINGLE_ARGUMENT

#define INSTANTIATE_GET_REPEATED_ARGUMENT(dtype, fieldname)                    \
template <>                                                                    \
vector<dtype> OperatorBase::GetRepeatedArgument<dtype>(                        \
    const string& name) {                                                      \
  if (arg_map_.count(name) == 0) {                                             \
    return vector<dtype>();                                                    \
  }                                                                            \
  vector<dtype> values;                                                        \
  CHECK(arg_map_[name]->fieldname##_size())                                    \
      << "Argument does not have the right field: expected "                   \
      << #fieldname;                                                           \
  for (const auto& v : arg_map_[name]->fieldname()) values.push_back(v);       \
  return values;                                                               \
}

INSTANTIATE_GET_REPEATED_ARGUMENT(float, floats)
INSTANTIATE_GET_REPEATED_ARGUMENT(int, ints)
INSTANTIATE_GET_REPEATED_ARGUMENT(string, strings)
#undef INSTANTIATE_GET_REPEATED_ARGUMENT

bool OperatorBase::Verify() {
  // Check Blob counts.
  if (operator_def_.input_size() < MinInput() ||
      operator_def_.input_size() > MaxInput()) {
    LOG(ERROR) << "Input size " << operator_def_.input_size()
               << " not in range [min=" << MinInput() << ", max="
               << MaxInput() << "].";
    LOG(ERROR) << "Error at operator " << operator_def_.name() << ":"
               << operator_def_.type();
    return false;
  }
  if (operator_def_.output_size() < MinOutput() ||
      operator_def_.output_size() > MaxOutput()) {
    LOG(ERROR) << "Output size " << operator_def_.output_size()
               << " not in range [min=" << MinOutput() << ", max="
               << MaxOutput() << "].";
    LOG(ERROR) << "Error at operator " << operator_def_.name() << ":"
               << operator_def_.type();
    return false;
  }
  return true;
}

OperatorBase* CreateOperator(const OperatorDef& operator_def, Workspace* ws) {
  const string& key = operator_def.type();
  switch (operator_def.device_option().device_type()) {
  case CPU:
    VLOG(1) << "Creating CPU operator " << key;
    return CPUOperatorRegistry()->Create(key, operator_def, ws);
  case CUDA:
    VLOG(1) << "Creating CUDA operator " << key;
    return CUDAOperatorRegistry()->Create(key, operator_def, ws);
  case CUDNN:
    VLOG(1) << "Using CuDNN implementation.";
    return CUDNNOperatorRegistry()->Create(key, operator_def, ws);
  }
  // Just to suppress some compiler error
  return nullptr;
}

DEFINE_REGISTRY(CPUOperatorRegistry, OperatorBase,
                const OperatorDef&, Workspace*);
DEFINE_REGISTRY(CUDAOperatorRegistry, OperatorBase,
                const OperatorDef&, Workspace*);
DEFINE_REGISTRY(CUDNNOperatorRegistry, OperatorBase,
                const OperatorDef&, Workspace*);

}  // namespace caffe2
<commit_msg>operator.cc: remove check for empty repeated argument (to allow empty shapes and other use cases)<commit_after>#include <algorithm>
#include <ctime>

#include "caffe2/core/net.h"
#include "caffe2/core/operator.h"
#include "caffe2/core/workspace.h"
#include "caffe2/proto/caffe2.pb.h"

namespace caffe2 {

// TODO(Yangqing): move all the checks to a less fatal check mechanism.
OperatorBase::OperatorBase(const OperatorDef& operator_def, Workspace* ws)
    : operator_def_(operator_def) {
  for (auto& arg : operator_def.arg()) {
    CHECK_GT(arg.name().size(), 0) << "Argument must have a name.";
    CHECK_EQ(arg_map_.count(arg.name()), 0) << "Duplicated argument name.";
    arg_map_[arg.name()] = &arg;
  }
  for (const string& input_str : operator_def_.input()) {
    inputs_.push_back(CHECK_NOTNULL(ws->GetBlob(input_str)));
  }
  for (const string& output_str : operator_def_.output()) {
    outputs_.push_back(CHECK_NOTNULL(ws->CreateBlob(output_str)));
  }
}

// Parameter getters. You can use these to get the arguments that you want.
// We need to deal with the fact that we cannot really template into
// protocol buffers... yuck.
#define INSTANTIATE_GET_SINGLE_ARGUMENT(dtype, fieldname)                      \
template <>                                                                    \
dtype OperatorBase::GetSingleArgument<dtype>(                                  \
    const string& name, const dtype& default_value) {                          \
  if (arg_map_.count(name) == 0) {                                             \
    DVLOG(1) << "Using default parameter value " << default_value;             \
    return default_value;                                                      \
  }                                                                            \
  CHECK(arg_map_[name]->has_##fieldname())                                     \
      << "Argument does not have the right field: expected "                   \
      << #fieldname;                                                           \
  return arg_map_[name]->fieldname();                                          \
}

INSTANTIATE_GET_SINGLE_ARGUMENT(float, f)
INSTANTIATE_GET_SINGLE_ARGUMENT(int, i)
INSTANTIATE_GET_SINGLE_ARGUMENT(string, s)
// Undefine the argument just to be safe.
#undef INSTANTIATE_GET_SINGLE_ARGUMENT

#define INSTANTIATE_GET_REPEATED_ARGUMENT(dtype, fieldname)                    \
template <>                                                                    \
vector<dtype> OperatorBase::GetRepeatedArgument<dtype>(                        \
    const string& name) {                                                      \
  if (arg_map_.count(name) == 0) {                                             \
    return vector<dtype>();                                                    \
  }                                                                            \
  vector<dtype> values;                                                        \
  for (const auto& v : arg_map_[name]->fieldname()) values.push_back(v);       \
  return values;                                                               \
}

INSTANTIATE_GET_REPEATED_ARGUMENT(float, floats)
INSTANTIATE_GET_REPEATED_ARGUMENT(int, ints)
INSTANTIATE_GET_REPEATED_ARGUMENT(string, strings)
#undef INSTANTIATE_GET_REPEATED_ARGUMENT

bool OperatorBase::Verify() {
  // Check Blob counts.
  if (operator_def_.input_size() < MinInput() ||
      operator_def_.input_size() > MaxInput()) {
    LOG(ERROR) << "Input size " << operator_def_.input_size()
               << " not in range [min=" << MinInput() << ", max="
               << MaxInput() << "].";
    LOG(ERROR) << "Error at operator " << operator_def_.name() << ":"
               << operator_def_.type();
    return false;
  }
  if (operator_def_.output_size() < MinOutput() ||
      operator_def_.output_size() > MaxOutput()) {
    LOG(ERROR) << "Output size " << operator_def_.output_size()
               << " not in range [min=" << MinOutput() << ", max="
               << MaxOutput() << "].";
    LOG(ERROR) << "Error at operator " << operator_def_.name() << ":"
               << operator_def_.type();
    return false;
  }
  return true;
}

OperatorBase* CreateOperator(const OperatorDef& operator_def, Workspace* ws) {
  const string& key = operator_def.type();
  switch (operator_def.device_option().device_type()) {
  case CPU:
    VLOG(1) << "Creating CPU operator " << key;
    return CPUOperatorRegistry()->Create(key, operator_def, ws);
  case CUDA:
    VLOG(1) << "Creating CUDA operator " << key;
    return CUDAOperatorRegistry()->Create(key, operator_def, ws);
  case CUDNN:
    VLOG(1) << "Using CuDNN implementation.";
    return CUDNNOperatorRegistry()->Create(key, operator_def, ws);
  }
  // Just to suppress some compiler error
  return nullptr;
}

DEFINE_REGISTRY(CPUOperatorRegistry, OperatorBase,
                const OperatorDef&, Workspace*);
DEFINE_REGISTRY(CUDAOperatorRegistry, OperatorBase,
                const OperatorDef&, Workspace*);
DEFINE_REGISTRY(CUDNNOperatorRegistry, OperatorBase,
                const OperatorDef&, Workspace*);

}  // namespace caffe2
<|endoftext|>