<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "version.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QCloseEvent>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    ui->PauseResume_Button->setFocus();

    connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(close()));

    connect(ui->actionCenter_All,                       SIGNAL(triggered()),        &ui->centralwidget->universe,   SLOT(centerAll()));
    connect(ui->actionDelete,                           SIGNAL(triggered()),        &ui->centralwidget->universe,   SLOT(deleteSelected()));
    connect(ui->actionDelete_Escapees,                  SIGNAL(triggered()),        &ui->centralwidget->universe,   SLOT(deleteEscapees()));
    connect(ui->actionInteractive_Planet_Placement,     SIGNAL(triggered()),        ui->centralwidget,              SLOT(beginInteractiveCreation()));
    connect(ui->actionInteractive_Planet_Placement,     SIGNAL(triggered(bool)),    ui->toggleFiringModePushButton, SLOT(setChecked(bool)));
    connect(ui->actionInteractive_Orbital_Placement,    SIGNAL(triggered()),        ui->centralwidget,              SLOT(beginOrbitalCreation()));
    connect(ui->toggleFiringModePushButton,             SIGNAL(toggled(bool)),      ui->centralwidget,              SLOT(enableFiringMode(bool)));
    connect(ui->actionTake_Screenshot,                  SIGNAL(triggered()),        ui->centralwidget,              SLOT(takeScreenshot()));
    connect(ui->gridRangeSpinBox,                       SIGNAL(valueChanged(int)),  ui->centralwidget,              SLOT(setGridRange(int)));

    ui->statusbar->addPermanentWidget(planetCountLabel = new QLabel(ui->statusbar));
    ui->statusbar->addPermanentWidget(fpsLabel = new QLabel(ui->statusbar));
    ui->statusbar->addPermanentWidget(averagefpsLabel = new QLabel(ui->statusbar));
    fpsLabel->setFixedWidth(120);
    planetCountLabel->setFixedWidth(120);
    averagefpsLabel->setFixedWidth(160);

    connect(&ui->centralwidget->universe,   SIGNAL(updatePlanetCountMessage(QString)),      planetCountLabel, SLOT(setText(QString)));
    connect(ui->centralwidget,              SIGNAL(updateFPSStatusMessage(QString)),        fpsLabel,         SLOT(setText(QString)));
    connect(ui->centralwidget,              SIGNAL(updateAverageFPSStatusMessage(QString)), averagefpsLabel,  SLOT(setText(QString)));

    connect(ui->actionNew_Planet,           SIGNAL(toggled(bool)),              ui->newPlanet_DockWidget,       SLOT(setVisible(bool)));
    connect(ui->newPlanet_DockWidget,       SIGNAL(visibilityChanged(bool)),    ui->actionNew_Planet,           SLOT(setChecked(bool)));
    connect(ui->actionSpeed_Control,        SIGNAL(toggled(bool)),              ui->speedControl_DockWidget,    SLOT(setVisible(bool)));
    connect(ui->speedControl_DockWidget,    SIGNAL(visibilityChanged(bool)),    ui->actionSpeed_Control,        SLOT(setChecked(bool)));
    connect(ui->actionView_Settings,        SIGNAL(toggled(bool)),              ui->viewSettings_DockWidget,    SLOT(setVisible(bool)));
    connect(ui->viewSettings_DockWidget,    SIGNAL(visibilityChanged(bool)),    ui->actionView_Settings,        SLOT(setChecked(bool)));
    connect(ui->actionFiring_Mode_Settings, SIGNAL(toggled(bool)),              ui->firingSettings_DockWidget,  SLOT(setVisible(bool)));
    connect(ui->firingSettings_DockWidget,  SIGNAL(visibilityChanged(bool)),    ui->actionFiring_Mode_Settings, SLOT(setChecked(bool)));
    connect(ui->actionRandom_Settings,      SIGNAL(toggled(bool)),              ui->randomSettings_DockWidget,  SLOT(setVisible(bool)));
    connect(ui->randomSettings_DockWidget,  SIGNAL(visibilityChanged(bool)),    ui->actionRandom_Settings,      SLOT(setChecked(bool)));

    ui->actionFiring_Mode_Settings->setChecked(false);
    ui->actionRandom_Settings->setChecked(false);
}

MainWindow::~MainWindow(){
    delete ui;
    delete planetCountLabel;
    delete averagefpsLabel;
    delete fpsLabel;
}

void MainWindow::closeEvent(QCloseEvent *e){
    if(!ui->centralwidget->universe.isEmpty()){
        float tmpsimspeed = ui->centralwidget->universe.simspeed;
        ui->centralwidget->universe.simspeed = 0.0f;

        if(QMessageBox::warning(this, tr("Are You Sure?"), tr("Are you sure you wish to exit? (universe will not be saved...)"),
                                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No){
            ui->centralwidget->universe.simspeed = tmpsimspeed;
            return e->ignore();
        }
    }
    e->accept();
}

void MainWindow::on_createPlanet_PushButton_clicked(){
    ui->centralwidget->universe.selected = ui->centralwidget->universe.addPlanet(
                Planet(QVector3D(ui->newPosX_SpinBox->value(),      ui->newPosY_SpinBox->value(),      ui->newPosZ_SpinBox->value()),
                       QVector3D(ui->newVelocityX_SpinBox->value(), ui->newVelocityY_SpinBox->value(), ui->newVelocityZ_SpinBox->value()) * PlanetsUniverse::velocityfac,
                       ui->newMass_SpinBox->value()));
}

void MainWindow::on_actionClear_Velocity_triggered(){
    if(ui->centralwidget->universe.isSelectedValid()){
        ui->centralwidget->universe.getSelected().velocity = QVector3D();
    }
}

void MainWindow::on_speed_Dial_valueChanged(int value){
    ui->centralwidget->universe.simspeed = float(value * speeddialmax) / ui->speed_Dial->maximum();
    ui->speedDisplay_lcdNumber->display(ui->centralwidget->universe.simspeed);
    if(ui->centralwidget->universe.simspeed <= 0.0f){
        ui->PauseResume_Button->setText(tr("Resume"));
        ui->PauseResume_Button->setIcon(QIcon(":/icons/silk/control_play_blue.png"));
    }else{
        ui->PauseResume_Button->setText(tr("Pause"));
        ui->PauseResume_Button->setIcon(QIcon(":/icons/silk/control_pause_blue.png"));
    }
}

void MainWindow::on_PauseResume_Button_clicked(){
    if(ui->speed_Dial->value() == 0){
        ui->speed_Dial->setValue(ui->speed_Dial->maximum() / speeddialmax);
    }else{
        ui->speed_Dial->setValue(0);
    }
}

void MainWindow::on_FastForward_Button_clicked(){
    if(ui->speed_Dial->value() == ui->speed_Dial->maximum() || ui->speed_Dial->value() == 0){
        ui->speed_Dial->setValue(ui->speed_Dial->maximum() / speeddialmax);
    }else{
        ui->speed_Dial->setValue(ui->speed_Dial->value() * 2);
    }
}

void MainWindow::on_actionNew_Simulation_triggered(){
    if(!ui->centralwidget->universe.isEmpty()){
        float tmpsimspeed = ui->centralwidget->universe.simspeed;
        ui->centralwidget->universe.simspeed = 0.0f;

        if(QMessageBox::warning(this, tr("Are You Sure?"), tr("Are you sure you wish to destroy the universe? (i.e. delete all planets.)"),
                                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes){
            ui->centralwidget->universe.deleteAll();
        }
        ui->centralwidget->universe.simspeed = tmpsimspeed;
    }
}

void MainWindow::on_actionOpen_Simulation_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    QString filename = QFileDialog::getOpenFileName(this, tr("Open Simulation"), "", tr("Simulation files (*.xml)"));
    ui->centralwidget->universe.load(filename);

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_actionSave_Simulation_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    if(!ui->centralwidget->universe.isEmpty()){
        QString filename = QFileDialog::getSaveFileName(this, tr("Save Simulation"), "", tr("Simulation files (*.xml)"));
        ui->centralwidget->universe.save(filename);
    }else{
        QMessageBox::warning(this, tr("Error Saving Simulation."), tr("No planets to save!"));
    }

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_actionFollow_Selection_triggered(){
    ui->centralwidget->following = ui->centralwidget->universe.selected;
    ui->centralwidget->followState = PlanetsWidget::Single;
}

void MainWindow::on_actionClear_Follow_triggered(){
    ui->centralwidget->following = 0;
    ui->centralwidget->followState = PlanetsWidget::FollowNone;
}

void MainWindow::on_actionPlain_Average_triggered(){
    ui->centralwidget->followState = PlanetsWidget::PlainAverage;
}

void MainWindow::on_actionWeighted_Average_triggered(){
    ui->centralwidget->followState = PlanetsWidget::WeightedAverage;
}

void MainWindow::on_actionAbout_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    QMessageBox::about(this, tr("About Planets3D"),
                       tr(""
                          "
Planets3D is a simple 3D gravitational simulator
"
                          "
Website: github.com/chipgw/planets-3d
"
                          "
Build Info:

"
                          "
Git sha1: %2
"
                          "
Build type: %3
"
                          "
Compiler: %4
"
                          "
")
                       .arg(version::git_revision)
                       .arg(version::build_type)
                       .arg(version::compiler));

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_actionAbout_Qt_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    QMessageBox::aboutQt(this);

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_stepsPerFrameSpinBox_valueChanged(int value){
    ui->centralwidget->universe.stepsPerFrame = value;
}

void MainWindow::on_trailLengthSpinBox_valueChanged(int value){
    Planet::pathLength = value;
}

void MainWindow::on_trailRecordDistanceDoubleSpinBox_valueChanged(double value){
    Planet::pathRecordDistance = value * value;
}

void MainWindow::on_firingVelocityDoubleSpinBox_valueChanged(double value){
    ui->centralwidget->firingSpeed = value * PlanetsUniverse::velocityfac;
}

void MainWindow::on_firingMassSpinBox_valueChanged(int value){
    ui->centralwidget->firingMass = value;
}

void MainWindow::on_actionGrid_toggled(bool value){
    ui->centralwidget->drawGrid = value;
}

void MainWindow::on_actionDraw_Paths_toggled(bool value){
    ui->centralwidget->drawPlanetTrails = value;
}

void MainWindow::on_actionPlanet_Colors_toggled(bool value){
    ui->centralwidget->drawPlanetColors = value;
}

void MainWindow::on_actionHide_Planets_toggled(bool value){
    ui->centralwidget->hidePlanets = value;

    if(value){
        ui->actionDraw_Paths->setChecked(true);
    }
}

void MainWindow::on_generateRandomPushButton_clicked(){
    ui->centralwidget->universe.generateRandom(ui->randomAmountSpinBox->value(), ui->randomRangeDoubleSpinBox->value(),
                                               ui->randomSpeedDoubleSpinBox->value() * PlanetsUniverse::velocityfac,
                                               ui->randomMassDoubleSpinBox->value());
}

const int MainWindow::speeddialmax = 32;
<commit_msg>load file from command line arguments.<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "version.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QCloseEvent>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    ui->PauseResume_Button->setFocus();

    connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(close()));

    connect(ui->actionCenter_All,                       SIGNAL(triggered()),        &ui->centralwidget->universe,   SLOT(centerAll()));
    connect(ui->actionDelete,                           SIGNAL(triggered()),        &ui->centralwidget->universe,   SLOT(deleteSelected()));
    connect(ui->actionDelete_Escapees,                  SIGNAL(triggered()),        &ui->centralwidget->universe,   SLOT(deleteEscapees()));
    connect(ui->actionInteractive_Planet_Placement,     SIGNAL(triggered()),        ui->centralwidget,              SLOT(beginInteractiveCreation()));
    connect(ui->actionInteractive_Planet_Placement,     SIGNAL(triggered(bool)),    ui->toggleFiringModePushButton, SLOT(setChecked(bool)));
    connect(ui->actionInteractive_Orbital_Placement,    SIGNAL(triggered()),        ui->centralwidget,              SLOT(beginOrbitalCreation()));
    connect(ui->toggleFiringModePushButton,             SIGNAL(toggled(bool)),      ui->centralwidget,              SLOT(enableFiringMode(bool)));
    connect(ui->actionTake_Screenshot,                  SIGNAL(triggered()),        ui->centralwidget,              SLOT(takeScreenshot()));
    connect(ui->gridRangeSpinBox,                       SIGNAL(valueChanged(int)),  ui->centralwidget,              SLOT(setGridRange(int)));

    ui->statusbar->addPermanentWidget(planetCountLabel = new QLabel(ui->statusbar));
    ui->statusbar->addPermanentWidget(fpsLabel = new QLabel(ui->statusbar));
    ui->statusbar->addPermanentWidget(averagefpsLabel = new QLabel(ui->statusbar));
    fpsLabel->setFixedWidth(120);
    planetCountLabel->setFixedWidth(120);
    averagefpsLabel->setFixedWidth(160);

    connect(&ui->centralwidget->universe,   SIGNAL(updatePlanetCountMessage(QString)),      planetCountLabel, SLOT(setText(QString)));
    connect(ui->centralwidget,              SIGNAL(updateFPSStatusMessage(QString)),        fpsLabel,         SLOT(setText(QString)));
    connect(ui->centralwidget,              SIGNAL(updateAverageFPSStatusMessage(QString)), averagefpsLabel,  SLOT(setText(QString)));

    connect(ui->actionNew_Planet,           SIGNAL(toggled(bool)),              ui->newPlanet_DockWidget,       SLOT(setVisible(bool)));
    connect(ui->newPlanet_DockWidget,       SIGNAL(visibilityChanged(bool)),    ui->actionNew_Planet,           SLOT(setChecked(bool)));
    connect(ui->actionSpeed_Control,        SIGNAL(toggled(bool)),              ui->speedControl_DockWidget,    SLOT(setVisible(bool)));
    connect(ui->speedControl_DockWidget,    SIGNAL(visibilityChanged(bool)),    ui->actionSpeed_Control,        SLOT(setChecked(bool)));
    connect(ui->actionView_Settings,        SIGNAL(toggled(bool)),              ui->viewSettings_DockWidget,    SLOT(setVisible(bool)));
    connect(ui->viewSettings_DockWidget,    SIGNAL(visibilityChanged(bool)),    ui->actionView_Settings,        SLOT(setChecked(bool)));
    connect(ui->actionFiring_Mode_Settings, SIGNAL(toggled(bool)),              ui->firingSettings_DockWidget,  SLOT(setVisible(bool)));
    connect(ui->firingSettings_DockWidget,  SIGNAL(visibilityChanged(bool)),    ui->actionFiring_Mode_Settings, SLOT(setChecked(bool)));
    connect(ui->actionRandom_Settings,      SIGNAL(toggled(bool)),              ui->randomSettings_DockWidget,  SLOT(setVisible(bool)));
    connect(ui->randomSettings_DockWidget,  SIGNAL(visibilityChanged(bool)),    ui->actionRandom_Settings,      SLOT(setChecked(bool)));

    ui->actionFiring_Mode_Settings->setChecked(false);
    ui->actionRandom_Settings->setChecked(false);

    const QStringList &arguments = QApplication::arguments();

    foreach (const QString &argument, arguments) {
        if(argument != QApplication::applicationFilePath() && ui->centralwidget->universe.load(argument)){
            break;
        }
    }
}

MainWindow::~MainWindow(){
    delete ui;
    delete planetCountLabel;
    delete averagefpsLabel;
    delete fpsLabel;
}

void MainWindow::closeEvent(QCloseEvent *e){
    if(!ui->centralwidget->universe.isEmpty()){
        float tmpsimspeed = ui->centralwidget->universe.simspeed;
        ui->centralwidget->universe.simspeed = 0.0f;

        if(QMessageBox::warning(this, tr("Are You Sure?"), tr("Are you sure you wish to exit? (universe will not be saved...)"),
                                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::No){
            ui->centralwidget->universe.simspeed = tmpsimspeed;
            return e->ignore();
        }
    }
    e->accept();
}

void MainWindow::on_createPlanet_PushButton_clicked(){
    ui->centralwidget->universe.selected = ui->centralwidget->universe.addPlanet(
                Planet(QVector3D(ui->newPosX_SpinBox->value(),      ui->newPosY_SpinBox->value(),      ui->newPosZ_SpinBox->value()),
                       QVector3D(ui->newVelocityX_SpinBox->value(), ui->newVelocityY_SpinBox->value(), ui->newVelocityZ_SpinBox->value()) * PlanetsUniverse::velocityfac,
                       ui->newMass_SpinBox->value()));
}

void MainWindow::on_actionClear_Velocity_triggered(){
    if(ui->centralwidget->universe.isSelectedValid()){
        ui->centralwidget->universe.getSelected().velocity = QVector3D();
    }
}

void MainWindow::on_speed_Dial_valueChanged(int value){
    ui->centralwidget->universe.simspeed = float(value * speeddialmax) / ui->speed_Dial->maximum();
    ui->speedDisplay_lcdNumber->display(ui->centralwidget->universe.simspeed);
    if(ui->centralwidget->universe.simspeed <= 0.0f){
        ui->PauseResume_Button->setText(tr("Resume"));
        ui->PauseResume_Button->setIcon(QIcon(":/icons/silk/control_play_blue.png"));
    }else{
        ui->PauseResume_Button->setText(tr("Pause"));
        ui->PauseResume_Button->setIcon(QIcon(":/icons/silk/control_pause_blue.png"));
    }
}

void MainWindow::on_PauseResume_Button_clicked(){
    if(ui->speed_Dial->value() == 0){
        ui->speed_Dial->setValue(ui->speed_Dial->maximum() / speeddialmax);
    }else{
        ui->speed_Dial->setValue(0);
    }
}

void MainWindow::on_FastForward_Button_clicked(){
    if(ui->speed_Dial->value() == ui->speed_Dial->maximum() || ui->speed_Dial->value() == 0){
        ui->speed_Dial->setValue(ui->speed_Dial->maximum() / speeddialmax);
    }else{
        ui->speed_Dial->setValue(ui->speed_Dial->value() * 2);
    }
}

void MainWindow::on_actionNew_Simulation_triggered(){
    if(!ui->centralwidget->universe.isEmpty()){
        float tmpsimspeed = ui->centralwidget->universe.simspeed;
        ui->centralwidget->universe.simspeed = 0.0f;

        if(QMessageBox::warning(this, tr("Are You Sure?"), tr("Are you sure you wish to destroy the universe? (i.e. delete all planets.)"),
                                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes){
            ui->centralwidget->universe.deleteAll();
        }
        ui->centralwidget->universe.simspeed = tmpsimspeed;
    }
}

void MainWindow::on_actionOpen_Simulation_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    QString filename = QFileDialog::getOpenFileName(this, tr("Open Simulation"), "", tr("Simulation files (*.xml)"));
    ui->centralwidget->universe.load(filename);

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_actionSave_Simulation_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    if(!ui->centralwidget->universe.isEmpty()){
        QString filename = QFileDialog::getSaveFileName(this, tr("Save Simulation"), "", tr("Simulation files (*.xml)"));
        ui->centralwidget->universe.save(filename);
    }else{
        QMessageBox::warning(this, tr("Error Saving Simulation."), tr("No planets to save!"));
    }

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_actionFollow_Selection_triggered(){
    ui->centralwidget->following = ui->centralwidget->universe.selected;
    ui->centralwidget->followState = PlanetsWidget::Single;
}

void MainWindow::on_actionClear_Follow_triggered(){
    ui->centralwidget->following = 0;
    ui->centralwidget->followState = PlanetsWidget::FollowNone;
}

void MainWindow::on_actionPlain_Average_triggered(){
    ui->centralwidget->followState = PlanetsWidget::PlainAverage;
}

void MainWindow::on_actionWeighted_Average_triggered(){
    ui->centralwidget->followState = PlanetsWidget::WeightedAverage;
}

void MainWindow::on_actionAbout_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    QMessageBox::about(this, tr("About Planets3D"),
                       tr(""
                          "
Planets3D is a simple 3D gravitational simulator
"
                          "
Website: github.com/chipgw/planets-3d
"
                          "
Build Info:

"
                          "
Git sha1: %2
"
                          "
Build type: %3
"
                          "
Compiler: %4
"
                          "
")
                       .arg(version::git_revision)
                       .arg(version::build_type)
                       .arg(version::compiler));

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_actionAbout_Qt_triggered(){
    float tmpsimspeed = ui->centralwidget->universe.simspeed;
    ui->centralwidget->universe.simspeed = 0.0f;

    QMessageBox::aboutQt(this);

    ui->centralwidget->universe.simspeed = tmpsimspeed;
}

void MainWindow::on_stepsPerFrameSpinBox_valueChanged(int value){
    ui->centralwidget->universe.stepsPerFrame = value;
}

void MainWindow::on_trailLengthSpinBox_valueChanged(int value){
    Planet::pathLength = value;
}

void MainWindow::on_trailRecordDistanceDoubleSpinBox_valueChanged(double value){
    Planet::pathRecordDistance = value * value;
}

void MainWindow::on_firingVelocityDoubleSpinBox_valueChanged(double value){
    ui->centralwidget->firingSpeed = value * PlanetsUniverse::velocityfac;
}

void MainWindow::on_firingMassSpinBox_valueChanged(int value){
    ui->centralwidget->firingMass = value;
}

void MainWindow::on_actionGrid_toggled(bool value){
    ui->centralwidget->drawGrid = value;
}

void MainWindow::on_actionDraw_Paths_toggled(bool value){
    ui->centralwidget->drawPlanetTrails = value;
}

void MainWindow::on_actionPlanet_Colors_toggled(bool value){
    ui->centralwidget->drawPlanetColors = value;
}

void MainWindow::on_actionHide_Planets_toggled(bool value){
    ui->centralwidget->hidePlanets = value;

    if(value){
        ui->actionDraw_Paths->setChecked(true);
    }
}

void MainWindow::on_generateRandomPushButton_clicked(){
    ui->centralwidget->universe.generateRandom(ui->randomAmountSpinBox->value(), ui->randomRangeDoubleSpinBox->value(),
                                               ui->randomSpeedDoubleSpinBox->value() * PlanetsUniverse::velocityfac,
                                               ui->randomMassDoubleSpinBox->value());
}

const int MainWindow::speeddialmax = 32;
<|endoftext|>


<commit_before>#include "mainwindow.hpp"

MainWindow::MainWindow()
{
    lastPath = QDir::currentPath();
    connect(&worker, SIGNAL(status(QString)), this, SLOT(status(QString)));
    connect(&worker, SIGNAL(progress(int)), this, SLOT(progress(int)));
    connect(&worker, SIGNAL(enableButtons()), this, SLOT(enableButtons()));
    connect(&worker, SIGNAL(disableButtons()), this, SLOT(disableButtons()));

    widget = std::unique_ptr<QWidget>(new QWidget(this));
    grid = std::unique_ptr<QGridLayout>(new QGridLayout);

    fileButton = std::unique_ptr<QPushButton>(
        new QPushButton("Pick a WAV file...")
    );
    connect(fileButton.get(), SIGNAL(clicked()), this, SLOT(pick()));
    grid->addWidget(fileButton.get(), 0, 0);

    progressBarWidget = std::unique_ptr<QWidget>(new QWidget);
    progressBarBox = std::unique_ptr<QBoxLayout>(
        new QBoxLayout(QBoxLayout::LeftToRight)
    );
    progressBar = std::unique_ptr<QProgressBar>(new QProgressBar);
    progress(0);
    progressBarBox->addWidget(progressBar.get(), 0);
    progressBarBox->setContentsMargins(1, 0, 0, 0);
    progressBarWidget->setLayout(progressBarBox.get());
    grid->addWidget(progressBarWidget.get(), 1, 0);

    uploadButton = std::unique_ptr<QPushButton>(new QPushButton("Upload"));
    uploadButton->setEnabled(false);
    connect(uploadButton.get(), SIGNAL(clicked()), this, SLOT(upload()));
    grid->addWidget(uploadButton.get(), 2, 0);

    verifyButton = std::unique_ptr<QPushButton>(new QPushButton("Verify"));
    verifyButton->setEnabled(false);
    connect(verifyButton.get(), SIGNAL(clicked()), this, SLOT(verify()));
    grid->addWidget(verifyButton.get(), 3, 0);

    widget->setLayout(grid.get());
    setCentralWidget(widget.get());
    setWindowTitle("RS-SBI");
    statusBar()->setSizeGripEnabled(false);
    update();
    setFixedSize(256, minimumSizeHint().height());
    setWindowFlags(Qt::MSWindowsFixedSizeDialogHint);
    show();

}

MainWindow::~MainWindow()
{
    clearPages();
}

void MainWindow::clearPages()
{
    pageNumber = 0;
    while (!pages.empty())
        delete pages.front(), pages.pop_front();
}

void MainWindow::pick()
{
    disableButtons();
    QString filePath = QFileDialog::getOpenFileName(
        this, "Pick WAV file", lastPath, "WAV (*.wav;*.wave;*.w64)"
    );
    QFile fileHandle(filePath);

    if (!fileHandle.exists()) {
        update();
        enableButtons(false);
        return;
    }

    QFileInfo fileInfo(filePath);
    lastPath = fileInfo.canonicalPath();

    if (!fileHandle.open(QIODevice::ReadOnly)) {
        update("ERROR: Failed to open the file");
        enableButtons(false);
        return;
    }

    char infoBuffer[4];

    fileHandle.seek(16);
    fileHandle.read(infoBuffer, 4);
    quint32 headerSize = qFromLittleEndian<quint32>((uchar*)infoBuffer);
    fileHandle.read(infoBuffer, 2);
    quint16 audioFormat = qFromLittleEndian<quint16>((uchar*)infoBuffer);
    fileHandle.read(infoBuffer, 2);
    quint16 channels = qFromLittleEndian<quint16>((uchar*)infoBuffer);
    fileHandle.read(infoBuffer, 4);
    quint32 sampleRate = qFromLittleEndian<quint32>((uchar*)infoBuffer);

    fileHandle.seek(34);
    fileHandle.read(infoBuffer, 2);
    quint16 bytesPerSample = qFromLittleEndian<quint16>((uchar*)infoBuffer) / 8;

    fileHandle.seek(headerSize + 24);
    fileHandle.read(infoBuffer, 4);
    quint32 dataSize = qFromLittleEndian<quint32>((uchar*)infoBuffer);
    quint32 samples = dataSize / 2;

    QString error = "";
    if (audioFormat != 1)
        error = "Not a valid WAV PCM file";
    else if (channels != 1)
        error = "Only mono supported";
    else if (bytesPerSample != 2)
        error = "Only 16 bits/sample supported";
    else if (dataSize > 2097144)
        error = "The file is larger than 2 MB";

    if (!error.isEmpty()) {
        fileHandle.close();
        update("ERROR: " + error);
        enableButtons(false);
        return;
    }

    char pageRawBuffer[528], *pageBuffer = NULL;
    quint8 pageOffset = 8;
    quint16 pageSize = 520, pageRawBufferSize, sample;
    quint32 remaining = dataSize;
    clearPages();
    while (remaining > 0) {
        pageRawBufferSize = remaining > pageSize ? pageSize : remaining;
        fileHandle.read(pageRawBuffer, pageRawBufferSize);
        pageBuffer = new char[4225]();
        pageBuffer[4224] = CS;
        for (int i = 0; i < pageRawBufferSize/2; ++i) {
            sample = qFromLittleEndian<quint16>(
                (uchar*)(pageRawBuffer + i*2)
            ) + 0x8000;
            Helper::encodeByte(
                pageBuffer, i*2 + pageOffset, (char)(sample & 0xFF)
            );
            Helper::encodeByte(
                pageBuffer, i*2 + pageOffset + 1, (char)(sample >> 8)
            );
        }

        remaining = remaining > pageSize ? remaining - pageSize : 0;
        if (pageSize == 520) {
            Helper::encodeByte(pageBuffer, 0, (char)(sampleRate & 0xFF));
            Helper::encodeByte(pageBuffer, 1, (char)((sampleRate >> 8) & 0xFF));
            Helper::encodeByte(
                pageBuffer, 2, (char)((sampleRate >> 16) & 0xFF)
            );
            Helper::encodeByte(pageBuffer, 3, (char)(sampleRate >> 24));
            Helper::encodeByte(pageBuffer, 4, (char)(samples & 0xFF));
            Helper::encodeByte(pageBuffer, 5, (char)((samples >> 8) & 0xFF));
            Helper::encodeByte(pageBuffer, 6, (char)((samples >> 16) & 0xFF));
            Helper::encodeByte(pageBuffer, 7, (char)(samples >> 24));

            pageRawBufferSize += 8;
            pageOffset = 0;
            pageSize = 528;
        }

        pages.push_back(pageBuffer);
        ++pageNumber;
    }

    fileHandle.close();
    update(
        "© 2013 Orekus Ltd.", fileInfo.completeBaseName(), dataSize, sampleRate
    );
    enableButtons();
}

void MainWindow::upload()
{
    worker.start(&pages, pageNumber, true);
}

void MainWindow::verify()
{
    worker.start(&pages, pageNumber, false);
}

void MainWindow::status(const QString &message)
{
    statusBar()->showMessage(message);
}

void MainWindow::progress(const int percentage)
{
    progressBar->setValue(percentage);
}

void MainWindow::enableButtons(bool all)
{
    fileButton->setEnabled(true);
    if (all) {
        uploadButton->setEnabled(true);
        verifyButton->setEnabled(true);
    }
}

void MainWindow::disableButtons(bool all)
{
    fileButton->setEnabled(false);
    if (all) {
        uploadButton->setEnabled(false);
        verifyButton->setEnabled(false);
    }
}

void MainWindow::update(const QString &message)
{
    status(message);
    progress(0);
    fileButton->setText("Pick a WAV file...");
    uploadButton->setEnabled(false);
    verifyButton->setEnabled(false);
}

void MainWindow::update(
    const QString &message, const QString &baseName,
    quint32 dataSize, quint32 sampleRate
)
{
    status(message);
    fileButton->setText(
        baseName + " [" + QString::number(
        (dataSize / (sampleRate * 2.0)), 'f', 3) + "s " +
        QString::number(sampleRate) + "Hz]"
    );
    enableButtons();
    progress(0);
}
<commit_msg>minor refactoring<commit_after>#include "mainwindow.hpp"

MainWindow::MainWindow()
{
    lastPath = QDir::currentPath();
    connect(&worker, SIGNAL(status(QString)), this, SLOT(status(QString)));
    connect(&worker, SIGNAL(progress(int)), this, SLOT(progress(int)));
    connect(&worker, SIGNAL(enableButtons()), this, SLOT(enableButtons()));
    connect(&worker, SIGNAL(disableButtons()), this, SLOT(disableButtons()));

    widget = std::unique_ptr<QWidget>(new QWidget(this));
    grid = std::unique_ptr<QGridLayout>(new QGridLayout);

    fileButton = std::unique_ptr<QPushButton>(
        new QPushButton("Pick a WAV file...")
    );
    connect(fileButton.get(), SIGNAL(clicked()), this, SLOT(pick()));
    grid->addWidget(fileButton.get(), 0, 0);

    progressBarWidget = std::unique_ptr<QWidget>(new QWidget);
    progressBarBox = std::unique_ptr<QBoxLayout>(
        new QBoxLayout(QBoxLayout::LeftToRight)
    );
    progressBar = std::unique_ptr<QProgressBar>(new QProgressBar);
    progress(0);
    progressBarBox->addWidget(progressBar.get(), 0);
    progressBarBox->setContentsMargins(1, 0, 0, 0);
    progressBarWidget->setLayout(progressBarBox.get());
    grid->addWidget(progressBarWidget.get(), 1, 0);

    uploadButton = std::unique_ptr<QPushButton>(new QPushButton("Upload"));
    uploadButton->setEnabled(false);
    connect(uploadButton.get(), SIGNAL(clicked()), this, SLOT(upload()));
    grid->addWidget(uploadButton.get(), 2, 0);

    verifyButton = std::unique_ptr<QPushButton>(new QPushButton("Verify"));
    verifyButton->setEnabled(false);
    connect(verifyButton.get(), SIGNAL(clicked()), this, SLOT(verify()));
    grid->addWidget(verifyButton.get(), 3, 0);

    widget->setLayout(grid.get());
    setCentralWidget(widget.get());
    setWindowTitle("RS-SBI");
    statusBar()->setSizeGripEnabled(false);
    update();
    setFixedSize(256, minimumSizeHint().height());
    setWindowFlags(Qt::MSWindowsFixedSizeDialogHint);
    show();
}

MainWindow::~MainWindow()
{
    clearPages();
}

void MainWindow::clearPages()
{
    pageNumber = 0;
    while (!pages.empty())
        delete pages.front(), pages.pop_front();
}

void MainWindow::pick()
{
    disableButtons();
    QString filePath = QFileDialog::getOpenFileName(
        this, "Pick WAV file", lastPath, "WAV (*.wav;*.wave;*.w64)"
    );
    QFile fileHandle(filePath);

    if (!fileHandle.exists()) {
        update();
        enableButtons(false);
        return;
    }

    QFileInfo fileInfo(filePath);
    lastPath = fileInfo.canonicalPath();

    if (!fileHandle.open(QIODevice::ReadOnly)) {
        update("ERROR: Failed to open the file");
        enableButtons(false);
        return;
    }

    char infoBuffer[4];

    fileHandle.seek(16);
    fileHandle.read(infoBuffer, 4);
    quint32 headerSize = qFromLittleEndian<quint32>((uchar*)infoBuffer);
    fileHandle.read(infoBuffer, 2);
    quint16 audioFormat = qFromLittleEndian<quint16>((uchar*)infoBuffer);
    fileHandle.read(infoBuffer, 2);
    quint16 channels = qFromLittleEndian<quint16>((uchar*)infoBuffer);
    fileHandle.read(infoBuffer, 4);
    quint32 sampleRate = qFromLittleEndian<quint32>((uchar*)infoBuffer);

    fileHandle.seek(34);
    fileHandle.read(infoBuffer, 2);
    quint16 bytesPerSample = qFromLittleEndian<quint16>((uchar*)infoBuffer) / 8;

    fileHandle.seek(headerSize + 24);
    fileHandle.read(infoBuffer, 4);
    quint32 dataSize = qFromLittleEndian<quint32>((uchar*)infoBuffer);
    quint32 samples = dataSize / 2;

    QString error = "";
    if (audioFormat != 1)
        error = "Not a valid WAV PCM file";
    else if (channels != 1)
        error = "Only mono supported";
    else if (bytesPerSample != 2)
        error = "Only 16 bits/sample supported";
    else if (dataSize > 2097144)
        error = "The file is larger than 2 MB";

    if (!error.isEmpty()) {
        fileHandle.close();
        update("ERROR: " + error);
        enableButtons(false);
        return;
    }

    char pageRawBuffer[528], *pageBuffer = NULL;
    quint8 pageOffset = 8;
    quint16 pageSize = 520, pageRawBufferSize, sample;
    quint32 remaining = dataSize;
    clearPages();
    while (remaining > 0) {
        pageRawBufferSize = remaining > pageSize ? pageSize : remaining;
        fileHandle.read(pageRawBuffer, pageRawBufferSize);
        pageBuffer = new char[4225]();
        pageBuffer[4224] = CS;
        for (int i = 0; i < pageRawBufferSize/2; ++i) {
            sample = qFromLittleEndian<quint16>(
                (uchar*)(pageRawBuffer + i*2)
            ) + 0x8000;
            Helper::encodeByte(
                pageBuffer, i*2 + pageOffset, (char)(sample & 0xFF)
            );
            Helper::encodeByte(
                pageBuffer, i*2 + pageOffset + 1, (char)(sample >> 8)
            );
        }

        remaining = remaining > pageSize ? remaining - pageSize : 0;
        if (pageSize == 520) {
            Helper::encodeByte(pageBuffer, 0, (char)(sampleRate & 0xFF));
            Helper::encodeByte(pageBuffer, 1, (char)((sampleRate >> 8) & 0xFF));
            Helper::encodeByte(
                pageBuffer, 2, (char)((sampleRate >> 16) & 0xFF)
            );
            Helper::encodeByte(pageBuffer, 3, (char)(sampleRate >> 24));
            Helper::encodeByte(pageBuffer, 4, (char)(samples & 0xFF));
            Helper::encodeByte(pageBuffer, 5, (char)((samples >> 8) & 0xFF));
            Helper::encodeByte(pageBuffer, 6, (char)((samples >> 16) & 0xFF));
            Helper::encodeByte(pageBuffer, 7, (char)(samples >> 24));

            pageRawBufferSize += 8;
            pageOffset = 0;
            pageSize = 528;
        }

        pages.push_back(pageBuffer);
        ++pageNumber;
    }

    fileHandle.close();
    update(
        "© 2013 Orekus Ltd.", fileInfo.completeBaseName(), dataSize, sampleRate
    );
    enableButtons();
}

void MainWindow::upload()
{
    worker.start(&pages, pageNumber, true);
}

void MainWindow::verify()
{
    worker.start(&pages, pageNumber, false);
}

void MainWindow::status(const QString &message)
{
    statusBar()->showMessage(message);
}

void MainWindow::progress(const int percentage)
{
    progressBar->setValue(percentage);
}

void MainWindow::enableButtons(bool all)
{
    fileButton->setEnabled(true);
    if (all) {
        uploadButton->setEnabled(true);
        verifyButton->setEnabled(true);
    }
}

void MainWindow::disableButtons(bool all)
{
    fileButton->setEnabled(false);
    if (all) {
        uploadButton->setEnabled(false);
        verifyButton->setEnabled(false);
    }
}

void MainWindow::update(const QString &message)
{
    status(message);
    progress(0);
    fileButton->setText("Pick a WAV file...");
    uploadButton->setEnabled(false);
    verifyButton->setEnabled(false);
}

void MainWindow::update(
    const QString &message, const QString &baseName,
    quint32 dataSize, quint32 sampleRate
)
{
    status(message);
    fileButton->setText(
        baseName + " [" + QString::number(
        (dataSize / (sampleRate * 2.0)), 'f', 3) + "s " +
        QString::number(sampleRate) + "Hz]"
    );
    enableButtons();
    progress(0);
}
<|endoftext|>


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

#pragma once

#include <deque>
#include <functional>
#include <sstream>
#include <stdexcept>

namespace ngraph
{
    class ConstString
    {
    public:
        template <size_t SIZE>
        constexpr ConstString(const char (&p)[SIZE])
            : m_string(p)
            , m_size(SIZE)
        {
        }

        constexpr char operator[](size_t i) const
        {
            return i < m_size ? m_string[i] : throw std::out_of_range("");
        }
        constexpr const char* get_ptr(size_t offset) const { return &m_string[offset]; }
        constexpr size_t size() const { return m_size; }
    private:
        const char* m_string;
        size_t m_size;
    };

    constexpr const char* find_last(ConstString s, size_t offset, char ch)
    {
        return offset == 0 ? s.get_ptr(0) : (s[offset] == ch ? s.get_ptr(offset + 1)
                                                             : find_last(s, offset - 1, ch));
    }

    constexpr const char* find_last(ConstString s, char ch)
    {
        return find_last(s, s.size() - 1, ch);
    }

    constexpr const char* get_file_name(ConstString s) { return find_last(s, '/'); }
    enum class LOG_TYPE
    {
        _LOG_TYPE_ERROR,
        _LOG_TYPE_WARNING,
        _LOG_TYPE_INFO,
        _LOG_TYPE_DEBUG,
    };

    class LogHelper
    {
    public:
        LogHelper(LOG_TYPE,
                  const char* file,
                  int line,
                  std::function<void(const std::string&)> m_handler_func);
        ~LogHelper();

        std::ostream& stream() { return m_stream; }
    private:
        std::function<void(const std::string&)> m_handler_func;
        std::stringstream m_stream;
    };

    class Logger
    {
        friend class LogHelper;

    public:
        static void set_log_path(const std::string& path);
        static void start();
        static void stop();

    private:
        static void log_item(const std::string& s);
        static void process_event(const std::string& s);
        static void thread_entry(void* param);
        static std::string m_log_path;
        static std::deque<std::string> m_queue;
    };

    extern std::ostream& get_nil_stream();

    void default_logger_handler_func(const std::string& s);

#define NGRAPH_ERR                                                                                \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_ERROR,                                           \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      default_logger_handler_func)                                                 \
        .stream()

#define NGRAPH_WARN                                                                                \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_WARNING,                                         \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      default_logger_handler_func)                                                 \
        .stream()

#define NGRAPH_INFO                                                                                \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_INFO,                                            \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      default_logger_handler_func)                                                 \
        .stream()

#ifdef NGRAPH_DEBUG_ENABLE
#define NGRAPH_DEBUG                                                                               \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_DEBUG,                                           \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      default_logger_handler_func)                                                 \
        .stream()
#else
#define NGRAPH_DEBUG ngraph::get_nil_stream()
#endif
}
<commit_msg>fix namespace error in macro (#1194)<commit_after>/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#pragma once

#include <deque>
#include <functional>
#include <sstream>
#include <stdexcept>

namespace ngraph
{
    class ConstString
    {
    public:
        template <size_t SIZE>
        constexpr ConstString(const char (&p)[SIZE])
            : m_string(p)
            , m_size(SIZE)
        {
        }

        constexpr char operator[](size_t i) const
        {
            return i < m_size ? m_string[i] : throw std::out_of_range("");
        }
        constexpr const char* get_ptr(size_t offset) const { return &m_string[offset]; }
        constexpr size_t size() const { return m_size; }
    private:
        const char* m_string;
        size_t m_size;
    };

    constexpr const char* find_last(ConstString s, size_t offset, char ch)
    {
        return offset == 0 ? s.get_ptr(0) : (s[offset] == ch ? s.get_ptr(offset + 1)
                                                             : find_last(s, offset - 1, ch));
    }

    constexpr const char* find_last(ConstString s, char ch)
    {
        return find_last(s, s.size() - 1, ch);
    }

    constexpr const char* get_file_name(ConstString s) { return find_last(s, '/'); }
    enum class LOG_TYPE
    {
        _LOG_TYPE_ERROR,
        _LOG_TYPE_WARNING,
        _LOG_TYPE_INFO,
        _LOG_TYPE_DEBUG,
    };

    class LogHelper
    {
    public:
        LogHelper(LOG_TYPE,
                  const char* file,
                  int line,
                  std::function<void(const std::string&)> m_handler_func);
        ~LogHelper();

        std::ostream& stream() { return m_stream; }
    private:
        std::function<void(const std::string&)> m_handler_func;
        std::stringstream m_stream;
    };

    class Logger
    {
        friend class LogHelper;

    public:
        static void set_log_path(const std::string& path);
        static void start();
        static void stop();

    private:
        static void log_item(const std::string& s);
        static void process_event(const std::string& s);
        static void thread_entry(void* param);
        static std::string m_log_path;
        static std::deque<std::string> m_queue;
    };

    extern std::ostream& get_nil_stream();

    void default_logger_handler_func(const std::string& s);

#define NGRAPH_ERR                                                                                \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_ERROR,                                           \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      ngraph::default_logger_handler_func)                                         \
        .stream()

#define NGRAPH_WARN                                                                                \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_WARNING,                                         \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      ngraph::default_logger_handler_func)                                         \
        .stream()

#define NGRAPH_INFO                                                                                \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_INFO,                                            \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      ngraph::default_logger_handler_func)                                         \
        .stream()

#ifdef NGRAPH_DEBUG_ENABLE
#define NGRAPH_DEBUG                                                                               \
    ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_DEBUG,                                           \
                      ngraph::get_file_name(__FILE__),                                             \
                      __LINE__,                                                                    \
                      ngraph::default_logger_handler_func)                                         \
        .stream()
#else
#define NGRAPH_DEBUG ngraph::get_nil_stream()
#endif
}
<|endoftext|>


<commit_before>#include <nan.h>

#include <string>
#include <cstdlib>

#include "../edlib/edlib.h"

/**
 * Converts string to sequence (array of unsigned chars).
 * Expects seqC to point to array.
 * Saves mapping of letters to numbers in letterIdx, also updated inAlphabet and alphabetLength.
 * letterIdx, inAlphabet and alphabetLength are also used as inputs.
 */
void convertStringToSequence(std::string seq, unsigned char* seqC,
                             unsigned char letterIdx[], bool inAlphabet[], int &alphabetLength) {
    for (unsigned int i = 0; i < seq.length(); i++) {
        if (seq[i] < 0) {
            //ThrowException(Exception::TypeError(String::New("Character is not in range")));
            continue;
        }
        unsigned char c = (unsigned char)seq[i];
        if (!inAlphabet[c]) {
            inAlphabet[c] = true;
            letterIdx[c] = alphabetLength++;
        }
        seqC[i] = letterIdx[c];
    }
}

/**
 * Arguments expected: {string} query, {string} target,  mode
 * @param {string} query
 * @param {string} target
 * @param {object} params {
 *   mode: 'HW' || 'SHW' || 'NW'
 * }
 * @return {
 *   editDistance: integer,
 *   locations: [{
 *     start: integer,
 *     end: integer
 *   }]
 * }
 */
void align(const Nan::FunctionCallbackInfo<v8::Value>& args) {
    EdlibAlignMode edlibMode = EDLIB_MODE_HW;

    // TODO: support more input parameters, and return alignment.
    // TODO: understand difference between Handle and Local -> I may be doing something wrong.

    // ------------------------ TRANSFORM INPUT -------------------- //
    if (args.Length() < 2 || args.Length() > 3) {
        Nan::ThrowTypeError("Wrong number of arguments");
        return;
    }
    if (!args[0]->IsString() || !args[1]->IsString()) {
        Nan::ThrowTypeError("First and second argument must be strings");
        return;
    }

    std::string query(*Nan::Utf8String(args[0]->ToString()));
    std::string target(*Nan::Utf8String(args[1]->ToString()));

    v8::Local<v8::Object> params = (args.Length() == 3) ? args[2]->ToObject() : Nan::New<v8::Object>();
    v8::Local<v8::Value> mode = params->Get(Nan::New("mode").ToLocalChecked());
    if (mode->IsString()) {
        std::string modeString(*Nan::Utf8String(mode->ToString()));
        if (modeString == "HW") edlibMode = EDLIB_MODE_HW;
        else if (modeString == "NW") edlibMode = EDLIB_MODE_NW;
        else if (modeString == "SHW") edlibMode = EDLIB_MODE_SHW;
        else {
            Nan::ThrowTypeError("Invalid edlib mode");
            return;
        }
    }
    // -------------------------------------------------------------- //

    // --------------------- FIND ALIGNMENT ------------------------- //
    EdlibAlignResult edlibResult = edlibAlign(query.c_str(), query.length(), target.c_str(), target.length(),
                                              edlibNewAlignConfig(-1, edlibMode, EDLIB_TASK_LOC));
    // -------------------------------------------------------------- //

    v8::Local<v8::Object> result = Nan::New<v8::Object>();
    result->Set(Nan::New("editDistance").ToLocalChecked(), Nan::New(edlibResult.editDistance));
    if (edlibResult.startLocations || edlibResult.endLocations) {
        v8::Local<v8::Array> locations = Nan::New<v8::Array>(edlibResult.numLocations);
        for (int i = 0; i < edlibResult.numLocations; i++) {
            v8::Local<v8::Object> location = Nan::New<v8::Object>();
            if (edlibResult.startLocations) {
                location->Set(Nan::New("start").ToLocalChecked(), Nan::New(edlibResult.startLocations[i]));
            }
            if (edlibResult.endLocations) {
                location->Set(Nan::New("end").ToLocalChecked(), Nan::New(edlibResult.endLocations[i]));
            }
            locations->Set(i, location);
        }
        result->Set(Nan::New("locations").ToLocalChecked(), locations);
    }

    edlibFreeAlignResult(edlibResult);
    args.GetReturnValue().Set(result);
}

void init(v8::Local<v8::Object> exports) {
    exports->Set(Nan::New("align").ToLocalChecked(),
                 Nan::New<v8::FunctionTemplate>(align)->GetFunction());
}

NODE_MODULE(node_edlib, init)
<commit_msg>Removed redundant function.<commit_after>#include <nan.h>

#include <string>
#include <cstdlib>

#include "../edlib/edlib.h"

/**
 * Arguments expected: {string} query, {string} target,  mode
 * @param {string} query
 * @param {string} target
 * @param {object} params {
 *   mode: 'HW' || 'SHW' || 'NW'
 * }
 * @return {
 *   editDistance: integer,
 *   locations: [{
 *     start: integer,
 *     end: integer
 *   }]
 * }
 */
void align(const Nan::FunctionCallbackInfo<v8::Value>& args) {
    EdlibAlignMode edlibMode = EDLIB_MODE_HW;

    // TODO: support more input parameters, and return alignment.
    // TODO: understand difference between Handle and Local -> I may be doing something wrong.

    // ------------------------ TRANSFORM INPUT -------------------- //
    if (args.Length() < 2 || args.Length() > 3) {
        Nan::ThrowTypeError("Wrong number of arguments");
        return;
    }
    if (!args[0]->IsString() || !args[1]->IsString()) {
        Nan::ThrowTypeError("First and second argument must be strings");
        return;
    }

    std::string query(*Nan::Utf8String(args[0]->ToString()));
    std::string target(*Nan::Utf8String(args[1]->ToString()));

    v8::Local<v8::Object> params = (args.Length() == 3) ? args[2]->ToObject() : Nan::New<v8::Object>();
    v8::Local<v8::Value> mode = params->Get(Nan::New("mode").ToLocalChecked());
    if (mode->IsString()) {
        std::string modeString(*Nan::Utf8String(mode->ToString()));
        if (modeString == "HW") edlibMode = EDLIB_MODE_HW;
        else if (modeString == "NW") edlibMode = EDLIB_MODE_NW;
        else if (modeString == "SHW") edlibMode = EDLIB_MODE_SHW;
        else {
            Nan::ThrowTypeError("Invalid edlib mode");
            return;
        }
    }
    // -------------------------------------------------------------- //

    // --------------------- FIND ALIGNMENT ------------------------- //
    EdlibAlignResult edlibResult = edlibAlign(query.c_str(), query.length(), target.c_str(), target.length(),
                                              edlibNewAlignConfig(-1, edlibMode, EDLIB_TASK_LOC));
    // -------------------------------------------------------------- //

    v8::Local<v8::Object> result = Nan::New<v8::Object>();
    result->Set(Nan::New("editDistance").ToLocalChecked(), Nan::New(edlibResult.editDistance));
    if (edlibResult.startLocations || edlibResult.endLocations) {
        v8::Local<v8::Array> locations = Nan::New<v8::Array>(edlibResult.numLocations);
        for (int i = 0; i < edlibResult.numLocations; i++) {
            v8::Local<v8::Object> location = Nan::New<v8::Object>();
            if (edlibResult.startLocations) {
                location->Set(Nan::New("start").ToLocalChecked(), Nan::New(edlibResult.startLocations[i]));
            }
            if (edlibResult.endLocations) {
                location->Set(Nan::New("end").ToLocalChecked(), Nan::New(edlibResult.endLocations[i]));
            }
            locations->Set(i, location);
        }
        result->Set(Nan::New("locations").ToLocalChecked(), locations);
    }

    edlibFreeAlignResult(edlibResult);
    args.GetReturnValue().Set(result);
}

void init(v8::Local<v8::Object> exports) {
    exports->Set(Nan::New("align").ToLocalChecked(),
                 Nan::New<v8::FunctionTemplate>(align)->GetFunction());
}

NODE_MODULE(node_edlib, init)
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file object/list.cc
 ** \brief Creation of the Urbi object list.
 */

#include <libport/bind.hh>

#include <libport/foreach.hh>
#include <libport/lexical-cast.hh>
#include <libport/finally.hh>
#include <libport/ufloat.hh>

#include <kernel/userver.hh>

#include <object/cxx-helper.hh>
#include <object/symbols.hh>

#include <urbi/object/code.hh>
#include <urbi/object/float.hh>
#include <urbi/object/list.hh>
#include <urbi/object/object.hh>

#include <urbi/runner/raise.hh>
#include <runner/runner.hh>
#include <runner/interpreter.hh>

namespace urbi
{
  namespace object
  {
    List::List()
    {
      proto_add(proto ? rObject(proto) : Object::proto);
    }

    List::List(const value_type& value)
      : content_(value)
    {
      proto_add(proto);
    }

    List::List(const rList& model)
      : content_(model->content_)
    {
      proto_add(proto);
    }

    const List::value_type& List::value_get() const
    {
      return content_;
    }

    List::value_type& List::value_get()
    {
      return content_;
    }

#define CHECK_NON_EMPTY(Name)                           \
    do {                                                \
      if (content_.empty())                             \
        RAISE("cannot be applied onto empty list");	\
    } while (0)

    rList
    List::tail() const
    {
      CHECK_NON_EMPTY(tail);
      value_type res = content_;
      libport::pop_front(res);
      return new List(res);
    }

    bool
    List::as_bool() const
    {
      return !empty();
    }

    bool
    List::empty() const
    {
      return content_.empty();
    }

    List::size_type
    List::index(const rFloat& idx) const
    {
      int i = idx->to_int_type("invalid index: %s");
      if (i < 0)
        i += content_.size();
      if (i < 0 || content_.size() <= static_cast<size_type>(i))
        FRAISE("invalid index: %s", idx->value_get());
      return static_cast<size_type>(i);
    }

    rObject List::operator[](const rFloat& idx)
    {
      return content_[index(idx)];
    }

    rObject List::set(const rFloat& idx, const rObject& val)
    {
      content_[index(idx)] = val;
      changed();
      return val;
    }

    List::size_type
    List::size() const
    {
      return content_.size();
    }

    rList List::remove_by_id(const rObject& elt)
    {
      bool mutated = false;
      value_type::iterator it = content_.begin();
      while (it != content_.end())
        if (*it == elt)
        {
          mutated = true;
          it = content_.erase(it);
        }
        else
          ++it;
      if (mutated)
        changed();
      return this;
    }

    rList List::operator+=(const rList& rhs)
    {
      // Copy the list to make a += a work
      value_type other = rhs->value_get();
      if (!other.empty())
      {
        foreach (const rObject& o, other)
          content_.push_back(o);
        changed();
      }
      return this;
    }

    rList List::operator+(const rList& rhs)
    {
      rList res = new List(this);
      *res += rhs;
      return res;
    }

    rList List::operator*(unsigned int times) const
    {
      List::value_type res;
      unsigned int s = content_.size();
      for (unsigned int i = 0; i < times; ++i)
        for (unsigned int j = 0; j < s; ++j)
          res.push_back(content_[j]);

      return new List(res);
    }

    /// Binary predicates used to sort lists.
    static bool
    compareListItems (const rObject& a, const rObject& b)
    {
      return a->call(SYMBOL(LT), b)->as_bool();
    }
    static bool
    compareListItemsLambda (const rObject& f, const rObject& l,
                            const rObject& a, const rObject& b)
    {
      rExecutable fun = f.unsafe_cast<Executable>();
      if (!fun)
      {
        type_check<Code>(f);
        unreachable();
      }
      objects_type args;
      args << l << a << b;
      return (*fun)(args)->as_bool();
    }

    List::value_type List::sort()
    {
      value_type s(content_);
      std::sort(s.begin(), s.end(),
                boost::bind(compareListItems, _1, _2));
      return s;
    }

    List::value_type List::sort(rObject f)
    {
      value_type s(content_);
      std::sort(s.begin(), s.end(),
                boost::bind(compareListItemsLambda, f, this, _1, _2));
      return s;
    }

    void
    List::each_common(const rObject& f, bool yielding, bool idx)
    {
      runner::Runner& r = ::kernel::runner();

      bool must_yield = false;
      int i = 0;
      // Beware of iterations that modify the list in place: make a
      // copy.
      foreach (const rObject& o, value_type(content_))
      {
        if (must_yield)
          r.yield();
        must_yield = yielding;
        objects_type args;
        args << f << o;
        if (idx)
          args << to_urbi(i++);
        r.apply(f, SYMBOL(each), args);
      }
    }

    void
    List::each(const rObject& f)
    {
      each_common(f, true, false);
    }

    void
    List::eachi(const rObject& f)
    {
      each_common(f, true, true);
    }

    void
    List::each_pipe(const rObject& f)
    {
      each_common(f, false, false);
    }

    void
    List::each_and(const rObject& f)
    {
      runner::Runner& r = ::kernel::runner();

      // Beware of iterations that modify the list in place: make a
      // copy.
      value_type l(content_);

      sched::Job::Collector collector(&r, l.size());

      foreach (const rObject& o, l)
      {
        object::objects_type args;
        args.push_back(o);
        sched::rJob job =
          new runner::Interpreter(dynamic_cast<runner::Interpreter&>(r),
                                  f, SYMBOL(each_AMPERSAND), args);
        r.register_child(job, collector);
        job->start_job();
      }

      try
      {
        r.yield_until_terminated(collector);
      }
      catch (const sched::ChildException& ce)
      {
        ce.rethrow_child_exception();
      }
    }

    rList
    List::insertFront(const rObject& o)
    {
      libport::push_front(content_, o);
      changed();
      return this;
    }

    rList
    List::insertBack(const rObject& o)
    {
      content_.push_back(o);
      changed();
      return this;
    }

#define BOUNCE(Name, Bounce, Ret, Check, Mutate)                \
    IF(Ret, rObject, rList)                                     \
    List::Name()                                                \
    {                                                           \
      WHEN(Check, CHECK_NON_EMPTY(Name));                       \
      WHEN(Ret, return) content_.Bounce();                      \
      WHEN(Mutate, changed());                                  \
      return this;                                              \
    }

    BOUNCE(back,          back,           true,  true , false);
    BOUNCE(clear,         clear,          false, false, true);
    BOUNCE(front,         front,          true,  true , false);

#undef BOUNCE

    rList
    List::insert(const rFloat& idx, const rObject& elt)
    {
      content_.insert(boost::next(content_.begin(), index(idx)), elt);
      changed();
      return this;
    }

    // FIXME: Really looks like String::join, we should find a means to
    // factor both.
    std::string
    List::as_string() const
    {
      std::string res = "[";
      bool tail = false;
      foreach (const rObject& o, content_)
      {
        if (tail++)
          res += ", ";
        res += o->call(SYMBOL(asPrintable))->as<String>()->value_get();
      }
      res += "]";
      return res;
    }

    rObject
    List::removeBack()
    {
      CHECK_NON_EMPTY(pop_back);
      rObject res = content_.back();
      content_.pop_back();
      changed();
      return res;
    }

    rObject
    List::removeFront()
    {
      CHECK_NON_EMPTY(pop_front);
      rObject res = content_.front();
      libport::pop_front(content_);
      changed();
      return res;
    }

    rList List::reverse() const
    {
      value_type res;
      rforeach (const rObject& obj, content_)
        res.push_back(obj);
      return new List(res);
    }

    OVERLOAD_2(sort_bouncer, 1,
               (List::value_type (List::*) ()) &List::sort,
               (List::value_type (List::*) (rObject f)) &List::sort)

    void List::initialize(CxxObject::Binder<List>& bind)
    {
#define DECLARE(Name, Function)                 \
      bind(SYMBOL(Name), &List::Function)

      DECLARE(asBool,         as_bool         );
      DECLARE(asString,       as_string       );
      DECLARE(back,           back            );
      DECLARE(clear,          clear           );
      DECLARE(each,           each            );
      DECLARE(each_AMPERSAND, each_and        );
      DECLARE(each_PIPE,      each_pipe       );
      DECLARE(eachi,          eachi           );
      DECLARE(empty,          empty           );
      DECLARE(front,          front           );
      DECLARE(SBL_SBR,        operator[]      );
      DECLARE(SBL_SBR_EQ,     set             );
      DECLARE(PLUS,           operator+       );
      DECLARE(PLUS_EQ,        operator+=      );
      DECLARE(insert,         insert          );
      DECLARE(insertBack,     insertBack      );
      DECLARE(insertFront,    insertFront     );
      DECLARE(removeBack,     removeBack      );
      DECLARE(removeFront,    removeFront     );
      DECLARE(removeById,     remove_by_id    );
      DECLARE(reverse,        reverse         );
      DECLARE(size,           size            );
      DECLARE(STAR,           operator*       );
      DECLARE(tail,           tail            );

#undef DECLARE
      bind(SYMBOL(sort),      &sort_bouncer          );
    }

    URBI_CXX_OBJECT_REGISTER(List)
    {}

  } // namespace object
}
<commit_msg>When cloning a list instance, use it as prototype, not List.<commit_after>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/**
 ** \file object/list.cc
 ** \brief Creation of the Urbi object list.
 */

#include <libport/bind.hh>

#include <libport/foreach.hh>
#include <libport/lexical-cast.hh>
#include <libport/finally.hh>
#include <libport/ufloat.hh>

#include <kernel/userver.hh>

#include <object/cxx-helper.hh>
#include <object/symbols.hh>

#include <urbi/object/code.hh>
#include <urbi/object/float.hh>
#include <urbi/object/list.hh>
#include <urbi/object/object.hh>

#include <urbi/runner/raise.hh>
#include <runner/runner.hh>
#include <runner/interpreter.hh>

namespace urbi
{
  namespace object
  {
    List::List()
    {
      proto_add(proto ? rObject(proto) : Object::proto);
    }

    List::List(const value_type& value)
      : content_(value)
    {
      proto_add(proto);
    }

    List::List(const rList& model)
      : content_(model->content_)
    {
      proto_add(model);
    }

    const List::value_type& List::value_get() const
    {
      return content_;
    }

    List::value_type& List::value_get()
    {
      return content_;
    }

#define CHECK_NON_EMPTY(Name)                           \
    do {                                                \
      if (content_.empty())                             \
        RAISE("cannot be applied onto empty list");	\
    } while (0)

    rList
    List::tail() const
    {
      CHECK_NON_EMPTY(tail);
      value_type res = content_;
      libport::pop_front(res);
      return new List(res);
    }

    bool
    List::as_bool() const
    {
      return !empty();
    }

    bool
    List::empty() const
    {
      return content_.empty();
    }

    List::size_type
    List::index(const rFloat& idx) const
    {
      int i = idx->to_int_type("invalid index: %s");
      if (i < 0)
        i += content_.size();
      if (i < 0 || content_.size() <= static_cast<size_type>(i))
        FRAISE("invalid index: %s", idx->value_get());
      return static_cast<size_type>(i);
    }

    rObject List::operator[](const rFloat& idx)
    {
      return content_[index(idx)];
    }

    rObject List::set(const rFloat& idx, const rObject& val)
    {
      content_[index(idx)] = val;
      changed();
      return val;
    }

    List::size_type
    List::size() const
    {
      return content_.size();
    }

    rList List::remove_by_id(const rObject& elt)
    {
      bool mutated = false;
      value_type::iterator it = content_.begin();
      while (it != content_.end())
        if (*it == elt)
        {
          mutated = true;
          it = content_.erase(it);
        }
        else
          ++it;
      if (mutated)
        changed();
      return this;
    }

    rList List::operator+=(const rList& rhs)
    {
      // Copy the list to make a += a work
      value_type other = rhs->value_get();
      if (!other.empty())
      {
        foreach (const rObject& o, other)
          content_.push_back(o);
        changed();
      }
      return this;
    }

    rList List::operator+(const rList& rhs)
    {
      rList res = new List(this);
      *res += rhs;
      return res;
    }

    rList List::operator*(unsigned int times) const
    {
      List::value_type res;
      unsigned int s = content_.size();
      for (unsigned int i = 0; i < times; ++i)
        for (unsigned int j = 0; j < s; ++j)
          res.push_back(content_[j]);

      return new List(res);
    }

    /// Binary predicates used to sort lists.
    static bool
    compareListItems (const rObject& a, const rObject& b)
    {
      return a->call(SYMBOL(LT), b)->as_bool();
    }
    static bool
    compareListItemsLambda (const rObject& f, const rObject& l,
                            const rObject& a, const rObject& b)
    {
      rExecutable fun = f.unsafe_cast<Executable>();
      if (!fun)
      {
        type_check<Code>(f);
        unreachable();
      }
      objects_type args;
      args << l << a << b;
      return (*fun)(args)->as_bool();
    }

    List::value_type List::sort()
    {
      value_type s(content_);
      std::sort(s.begin(), s.end(),
                boost::bind(compareListItems, _1, _2));
      return s;
    }

    List::value_type List::sort(rObject f)
    {
      value_type s(content_);
      std::sort(s.begin(), s.end(),
                boost::bind(compareListItemsLambda, f, this, _1, _2));
      return s;
    }

    void
    List::each_common(const rObject& f, bool yielding, bool idx)
    {
      runner::Runner& r = ::kernel::runner();

      bool must_yield = false;
      int i = 0;
      // Beware of iterations that modify the list in place: make a
      // copy.
      foreach (const rObject& o, value_type(content_))
      {
        if (must_yield)
          r.yield();
        must_yield = yielding;
        objects_type args;
        args << f << o;
        if (idx)
          args << to_urbi(i++);
        r.apply(f, SYMBOL(each), args);
      }
    }

    void
    List::each(const rObject& f)
    {
      each_common(f, true, false);
    }

    void
    List::eachi(const rObject& f)
    {
      each_common(f, true, true);
    }

    void
    List::each_pipe(const rObject& f)
    {
      each_common(f, false, false);
    }

    void
    List::each_and(const rObject& f)
    {
      runner::Runner& r = ::kernel::runner();

      // Beware of iterations that modify the list in place: make a
      // copy.
      value_type l(content_);

      sched::Job::Collector collector(&r, l.size());

      foreach (const rObject& o, l)
      {
        object::objects_type args;
        args.push_back(o);
        sched::rJob job =
          new runner::Interpreter(dynamic_cast<runner::Interpreter&>(r),
                                  f, SYMBOL(each_AMPERSAND), args);
        r.register_child(job, collector);
        job->start_job();
      }

      try
      {
        r.yield_until_terminated(collector);
      }
      catch (const sched::ChildException& ce)
      {
        ce.rethrow_child_exception();
      }
    }

    rList
    List::insertFront(const rObject& o)
    {
      libport::push_front(content_, o);
      changed();
      return this;
    }

    rList
    List::insertBack(const rObject& o)
    {
      content_.push_back(o);
      changed();
      return this;
    }

#define BOUNCE(Name, Bounce, Ret, Check, Mutate)                \
    IF(Ret, rObject, rList)                                     \
    List::Name()                                                \
    {                                                           \
      WHEN(Check, CHECK_NON_EMPTY(Name));                       \
      WHEN(Ret, return) content_.Bounce();                      \
      WHEN(Mutate, changed());                                  \
      return this;                                              \
    }

    BOUNCE(back,          back,           true,  true , false);
    BOUNCE(clear,         clear,          false, false, true);
    BOUNCE(front,         front,          true,  true , false);

#undef BOUNCE

    rList
    List::insert(const rFloat& idx, const rObject& elt)
    {
      content_.insert(boost::next(content_.begin(), index(idx)), elt);
      changed();
      return this;
    }

    // FIXME: Really looks like String::join, we should find a means to
    // factor both.
    std::string
    List::as_string() const
    {
      std::string res = "[";
      bool tail = false;
      foreach (const rObject& o, content_)
      {
        if (tail++)
          res += ", ";
        res += o->call(SYMBOL(asPrintable))->as<String>()->value_get();
      }
      res += "]";
      return res;
    }

    rObject
    List::removeBack()
    {
      CHECK_NON_EMPTY(pop_back);
      rObject res = content_.back();
      content_.pop_back();
      changed();
      return res;
    }

    rObject
    List::removeFront()
    {
      CHECK_NON_EMPTY(pop_front);
      rObject res = content_.front();
      libport::pop_front(content_);
      changed();
      return res;
    }

    rList List::reverse() const
    {
      value_type res;
      rforeach (const rObject& obj, content_)
        res.push_back(obj);
      return new List(res);
    }

    OVERLOAD_2(sort_bouncer, 1,
               (List::value_type (List::*) ()) &List::sort,
               (List::value_type (List::*) (rObject f)) &List::sort)

    void List::initialize(CxxObject::Binder<List>& bind)
    {
#define DECLARE(Name, Function)                 \
      bind(SYMBOL(Name), &List::Function)

      DECLARE(asBool,         as_bool         );
      DECLARE(asString,       as_string       );
      DECLARE(back,           back            );
      DECLARE(clear,          clear           );
      DECLARE(each,           each            );
      DECLARE(each_AMPERSAND, each_and        );
      DECLARE(each_PIPE,      each_pipe       );
      DECLARE(eachi,          eachi           );
      DECLARE(empty,          empty           );
      DECLARE(front,          front           );
      DECLARE(SBL_SBR,        operator[]      );
      DECLARE(SBL_SBR_EQ,     set             );
      DECLARE(PLUS,           operator+       );
      DECLARE(PLUS_EQ,        operator+=      );
      DECLARE(insert,         insert          );
      DECLARE(insertBack,     insertBack      );
      DECLARE(insertFront,    insertFront     );
      DECLARE(removeBack,     removeBack      );
      DECLARE(removeFront,    removeFront     );
      DECLARE(removeById,     remove_by_id    );
      DECLARE(reverse,        reverse         );
      DECLARE(size,           size            );
      DECLARE(STAR,           operator*       );
      DECLARE(tail,           tail            );

#undef DECLARE
      bind(SYMBOL(sort),      &sort_bouncer          );
    }

    URBI_CXX_OBJECT_REGISTER(List)
    {}

  } // namespace object
}
<|endoftext|>