<commit_before>#include "masternodelist.h"
#include "ui_masternodelist.h"

#include "activemasternode.h"
#include "clientmodel.h"
#include "guiutil.h"
#include "init.h"
#include "masternode-sync.h"
#include "masternodeconfig.h"
#include "masternodeman.h"
#include "sync.h"
#include "wallet.h"
#include "walletmodel.h"

#include <QMessageBox>
#include <QTimer>

CCriticalSection cs_masternodes;

MasternodeList::MasternodeList(QWidget* parent) : QWidget(parent),
                                                  ui(new Ui::MasternodeList),
                                                  clientModel(0),
                                                  walletModel(0)
{
    ui->setupUi(this);

    ui->startButton->setEnabled(false);

    int columnAliasWidth = 100;
    int columnAddressWidth = 200;
    int columnProtocolWidth = 60;
    int columnStatusWidth = 80;
    int columnActiveWidth = 130;
    int columnLastSeenWidth = 130;

    ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(2, columnProtocolWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(3, columnStatusWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(4, columnActiveWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(5, columnLastSeenWidth);

    ui->tableWidgetMyMasternodes->setContextMenuPolicy(Qt::CustomContextMenu);

    QAction* startAliasAction = new QAction(tr("Start alias"), this);
    contextMenu = new QMenu();
    contextMenu->addAction(startAliasAction);
    connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
    connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked()));

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList()));
    timer->start(1000);

    // Fill MN list
    fFilterUpdated = true;
    nTimeFilterUpdated = GetTime();
}

MasternodeList::~MasternodeList()
{
    delete ui;
}

void MasternodeList::setClientModel(ClientModel* model)
{
    this->clientModel = model;
}

void MasternodeList::setWalletModel(WalletModel* model)
{
    this->walletModel = model;
}

void MasternodeList::showContextMenu(const QPoint& point)
{
    QTableWidgetItem* item = ui->tableWidgetMyMasternodes->itemAt(point);
    if (item) contextMenu->exec(QCursor::pos());
}

void MasternodeList::StartAlias(std::string strAlias)
{
    std::string strStatusHtml;
    strStatusHtml += "Alias: " + strAlias;

    BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
        if (mne.getAlias() == strAlias) {
            std::string strError;
            CMasternodeBroadcast mnb;

            bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);

            if (fSuccess) {
                strStatusHtml += "
Successfully started masternode.";
                mnodeman.UpdateMasternodeList(mnb);
                mnb.Relay();
            } else {
                strStatusHtml += "
Failed to start masternode.
Error: " + strError;
            }
            break;
        }
    }
    strStatusHtml += "";

    QMessageBox msg;
    msg.setText(QString::fromStdString(strStatusHtml));
    msg.exec();

    updateMyNodeList(true);
}

void MasternodeList::StartAll(std::string strCommand)
{
    int nCountSuccessful = 0;
    int nCountFailed = 0;
    std::string strFailedHtml;

    BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
        std::string strError;
        CMasternodeBroadcast mnb;

        int nIndex;
        if(!mne.castOutputIndex(nIndex))
            continue;

        CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
        CMasternode* pmn = mnodeman.Find(txin);

        if (strCommand == "start-missing" && pmn) continue;

        bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);

        if (fSuccess) {
            nCountSuccessful++;
            mnodeman.UpdateMasternodeList(mnb);
            mnb.Relay();
        } else {
            nCountFailed++;
            strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError;
        }
    }
    pwalletMain->Lock();

    std::string returnObj;
    returnObj = strprintf("Successfully started %d masternodes, failed to start %d, total %d", nCountSuccessful, nCountFailed, nCountFailed + nCountSuccessful);
    if (nCountFailed > 0) {
        returnObj += strFailedHtml;
    }

    QMessageBox msg;
    msg.setText(QString::fromStdString(returnObj));
    msg.exec();

    updateMyNodeList(true);
}

void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, CMasternode* pmn)
{
    LOCK(cs_mnlistupdate);
    bool fOldRowFound = false;
    int nNewRow = 0;

    for (int i = 0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) {
        if (ui->tableWidgetMyMasternodes->item(i, 0)->text() == strAlias) {
            fOldRowFound = true;
            nNewRow = i;
            break;
        }
    }

    if (nNewRow == 0 && !fOldRowFound) {
        nNewRow = ui->tableWidgetMyMasternodes->rowCount();
        ui->tableWidgetMyMasternodes->insertRow(nNewRow);
    }

    QTableWidgetItem* aliasItem = new QTableWidgetItem(strAlias);
    QTableWidgetItem* addrItem = new QTableWidgetItem(pmn ? QString::fromStdString(pmn->addr.ToString()) : strAddr);
    QTableWidgetItem* protocolItem = new QTableWidgetItem(QString::number(pmn ? pmn->protocolVersion : -1));
    QTableWidgetItem* statusItem = new QTableWidgetItem(QString::fromStdString(pmn ? pmn->GetStatus() : "MISSING"));
    GUIUtil::DHMSTableWidgetItem* activeSecondsItem = new GUIUtil::DHMSTableWidgetItem(pmn ? (pmn->lastPing.sigTime - pmn->sigTime) : 0);
    QTableWidgetItem* lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M", pmn ? pmn->lastPing.sigTime : 0)));
    QTableWidgetItem* pubkeyItem = new QTableWidgetItem(QString::fromStdString(pmn ? CBitcoinAddress(pmn->pubKeyCollateralAddress.GetID()).ToString() : ""));

    ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 2, protocolItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 3, statusItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 4, activeSecondsItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 5, lastSeenItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 6, pubkeyItem);
}

void MasternodeList::updateMyNodeList(bool fForce)
{
    static int64_t nTimeMyListUpdated = 0;

    // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds,
    // this update still can be triggered manually at any time via button click
    int64_t nSecondsTillUpdate = nTimeMyListUpdated + MY_MASTERNODELIST_UPDATE_SECONDS - GetTime();
    ui->secondsLabel->setText(QString::number(nSecondsTillUpdate));

    if (nSecondsTillUpdate > 0 && !fForce) return;
    nTimeMyListUpdated = GetTime();

    ui->tableWidgetMyMasternodes->setSortingEnabled(false);
    BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
        int nIndex;
        if(!mne.castOutputIndex(nIndex))
            continue;

        CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
        CMasternode* pmn = mnodeman.Find(txin);
        if (pmn != NULL)
            updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), pmn);
    }
    ui->tableWidgetMyMasternodes->setSortingEnabled(true);

    // reset "timer"
    ui->secondsLabel->setText("0");
}

void MasternodeList::on_startButton_clicked()
{
    // Find selected node alias
    QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();

    if (selected.count() == 0) return;

    QModelIndex index = selected.at(0);
    int nSelectedRow = index.row();
    std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString();

    // Display message box
    QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"),
        tr("Are you sure you want to start masternode %1?").arg(QString::fromStdString(strAlias)),
        QMessageBox::Yes | QMessageBox::Cancel,
        QMessageBox::Cancel);

    if (retval != QMessageBox::Yes) return;

    WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();

    if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) {
        WalletModel::UnlockContext ctx(walletModel->requestUnlock());

        if (!ctx.isValid()) return; // Unlock wallet was cancelled

        StartAlias(strAlias);
        return;
    }

    StartAlias(strAlias);
}

void MasternodeList::on_startAllButton_clicked()
{
    // Display message box
    QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm all masternodes start"),
        tr("Are you sure you want to start ALL masternodes?"),
        QMessageBox::Yes | QMessageBox::Cancel,
        QMessageBox::Cancel);

    if (retval != QMessageBox::Yes) return;

    WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();

    if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) {
        WalletModel::UnlockContext ctx(walletModel->requestUnlock());

        if (!ctx.isValid()) return; // Unlock wallet was cancelled

        StartAll();
        return;
    }

    StartAll();
}

void MasternodeList::on_startMissingButton_clicked()
{
    if (!masternodeSync.IsMasternodeListSynced()) {
        QMessageBox::critical(this, tr("Command is not available right now"),
            tr("You can't use this command until masternode list is synced"));
        return;
    }

    // Display message box
    QMessageBox::StandardButton retval = QMessageBox::question(this,
        tr("Confirm missing masternodes start"),
        tr("Are you sure you want to start MISSING masternodes?"),
        QMessageBox::Yes | QMessageBox::Cancel,
        QMessageBox::Cancel);

    if (retval != QMessageBox::Yes) return;

    WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();

    if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) {
        WalletModel::UnlockContext ctx(walletModel->requestUnlock());

        if (!ctx.isValid()) return; // Unlock wallet was cancelled

        StartAll("start-missing");
        return;
    }

    StartAll("start-missing");
}

void MasternodeList::on_tableWidgetMyMasternodes_itemSelectionChanged()
{
    if (ui->tableWidgetMyMasternodes->selectedItems().count() > 0) {
        ui->startButton->setEnabled(true);
    }
}

void MasternodeList::on_UpdateButton_clicked()
{
    updateMyNodeList(true);
}
<commit_msg>PR 241 correction<commit_after>#include "masternodelist.h"
#include "ui_masternodelist.h"

#include "activemasternode.h"
#include "clientmodel.h"
#include "guiutil.h"
#include "init.h"
#include "masternode-sync.h"
#include "masternodeconfig.h"
#include "masternodeman.h"
#include "sync.h"
#include "wallet.h"
#include "walletmodel.h"

#include <QMessageBox>
#include <QTimer>

CCriticalSection cs_masternodes;

MasternodeList::MasternodeList(QWidget* parent) : QWidget(parent),
                                                  ui(new Ui::MasternodeList),
                                                  clientModel(0),
                                                  walletModel(0)
{
    ui->setupUi(this);

    ui->startButton->setEnabled(false);

    int columnAliasWidth = 100;
    int columnAddressWidth = 200;
    int columnProtocolWidth = 60;
    int columnStatusWidth = 80;
    int columnActiveWidth = 130;
    int columnLastSeenWidth = 130;

    ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(2, columnProtocolWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(3, columnStatusWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(4, columnActiveWidth);
    ui->tableWidgetMyMasternodes->setColumnWidth(5, columnLastSeenWidth);

    ui->tableWidgetMyMasternodes->setContextMenuPolicy(Qt::CustomContextMenu);

    QAction* startAliasAction = new QAction(tr("Start alias"), this);
    contextMenu = new QMenu();
    contextMenu->addAction(startAliasAction);
    connect(ui->tableWidgetMyMasternodes, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
    connect(startAliasAction, SIGNAL(triggered()), this, SLOT(on_startButton_clicked()));

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList()));
    timer->start(1000);

    // Fill MN list
    fFilterUpdated = true;
    nTimeFilterUpdated = GetTime();
}

MasternodeList::~MasternodeList()
{
    delete ui;
}

void MasternodeList::setClientModel(ClientModel* model)
{
    this->clientModel = model;
}

void MasternodeList::setWalletModel(WalletModel* model)
{
    this->walletModel = model;
}

void MasternodeList::showContextMenu(const QPoint& point)
{
    QTableWidgetItem* item = ui->tableWidgetMyMasternodes->itemAt(point);
    if (item) contextMenu->exec(QCursor::pos());
}

void MasternodeList::StartAlias(std::string strAlias)
{
    std::string strStatusHtml;
    strStatusHtml += "Alias: " + strAlias;

    BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
        if (mne.getAlias() == strAlias) {
            std::string strError;
            CMasternodeBroadcast mnb;

            bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);

            if (fSuccess) {
                strStatusHtml += "
Successfully started masternode.";
                mnodeman.UpdateMasternodeList(mnb);
                mnb.Relay();
            } else {
                strStatusHtml += "
Failed to start masternode.
Error: " + strError;
            }
            break;
        }
    }
    strStatusHtml += "";

    QMessageBox msg;
    msg.setText(QString::fromStdString(strStatusHtml));
    msg.exec();

    updateMyNodeList(true);
}

void MasternodeList::StartAll(std::string strCommand)
{
    int nCountSuccessful = 0;
    int nCountFailed = 0;
    std::string strFailedHtml;

    BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
        std::string strError;
        CMasternodeBroadcast mnb;

        int nIndex;
        if(!mne.castOutputIndex(nIndex))
            continue;

        CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
        CMasternode* pmn = mnodeman.Find(txin);

        if (strCommand == "start-missing" && pmn) continue;

        bool fSuccess = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb);

        if (fSuccess) {
            nCountSuccessful++;
            mnodeman.UpdateMasternodeList(mnb);
            mnb.Relay();
        } else {
            nCountFailed++;
            strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError;
        }
    }
    pwalletMain->Lock();

    std::string returnObj;
    returnObj = strprintf("Successfully started %d masternodes, failed to start %d, total %d", nCountSuccessful, nCountFailed, nCountFailed + nCountSuccessful);
    if (nCountFailed > 0) {
        returnObj += strFailedHtml;
    }

    QMessageBox msg;
    msg.setText(QString::fromStdString(returnObj));
    msg.exec();

    updateMyNodeList(true);
}

void MasternodeList::updateMyMasternodeInfo(QString strAlias, QString strAddr, CMasternode* pmn)
{
    LOCK(cs_mnlistupdate);
    bool fOldRowFound = false;
    int nNewRow = 0;

    for (int i = 0; i < ui->tableWidgetMyMasternodes->rowCount(); i++) {
        if (ui->tableWidgetMyMasternodes->item(i, 0)->text() == strAlias) {
            fOldRowFound = true;
            nNewRow = i;
            break;
        }
    }

    if (nNewRow == 0 && !fOldRowFound) {
        nNewRow = ui->tableWidgetMyMasternodes->rowCount();
        ui->tableWidgetMyMasternodes->insertRow(nNewRow);
    }

    QTableWidgetItem* aliasItem = new QTableWidgetItem(strAlias);
    QTableWidgetItem* addrItem = new QTableWidgetItem(pmn ? QString::fromStdString(pmn->addr.ToString()) : strAddr);
    QTableWidgetItem* protocolItem = new QTableWidgetItem(QString::number(pmn ? pmn->protocolVersion : -1));
    QTableWidgetItem* statusItem = new QTableWidgetItem(QString::fromStdString(pmn ? pmn->GetStatus() : "MISSING"));
    GUIUtil::DHMSTableWidgetItem* activeSecondsItem = new GUIUtil::DHMSTableWidgetItem(pmn ? (pmn->lastPing.sigTime - pmn->sigTime) : 0);
    QTableWidgetItem* lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M", pmn ? pmn->lastPing.sigTime : 0)));
    QTableWidgetItem* pubkeyItem = new QTableWidgetItem(QString::fromStdString(pmn ? CBitcoinAddress(pmn->pubKeyCollateralAddress.GetID()).ToString() : ""));

    ui->tableWidgetMyMasternodes->setItem(nNewRow, 0, aliasItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 1, addrItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 2, protocolItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 3, statusItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 4, activeSecondsItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 5, lastSeenItem);
    ui->tableWidgetMyMasternodes->setItem(nNewRow, 6, pubkeyItem);
}

void MasternodeList::updateMyNodeList(bool fForce)
{
    static int64_t nTimeMyListUpdated = 0;

    // automatically update my masternode list only once in MY_MASTERNODELIST_UPDATE_SECONDS seconds,
    // this update still can be triggered manually at any time via button click
    int64_t nSecondsTillUpdate = nTimeMyListUpdated + MY_MASTERNODELIST_UPDATE_SECONDS - GetTime();
    ui->secondsLabel->setText(QString::number(nSecondsTillUpdate));

    if (nSecondsTillUpdate > 0 && !fForce) return;
    nTimeMyListUpdated = GetTime();

    ui->tableWidgetMyMasternodes->setSortingEnabled(false);
    BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
        int nIndex;
        if(!mne.castOutputIndex(nIndex))
            continue;

        CTxIn txin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
        CMasternode* pmn = mnodeman.Find(txin);
        updateMyMasternodeInfo(QString::fromStdString(mne.getAlias()), QString::fromStdString(mne.getIp()), pmn);
    }
    ui->tableWidgetMyMasternodes->setSortingEnabled(true);

    // reset "timer"
    ui->secondsLabel->setText("0");
}

void MasternodeList::on_startButton_clicked()
{
    // Find selected node alias
    QItemSelectionModel* selectionModel = ui->tableWidgetMyMasternodes->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();

    if (selected.count() == 0) return;

    QModelIndex index = selected.at(0);
    int nSelectedRow = index.row();
    std::string strAlias = ui->tableWidgetMyMasternodes->item(nSelectedRow, 0)->text().toStdString();

    // Display message box
    QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm masternode start"),
        tr("Are you sure you want to start masternode %1?").arg(QString::fromStdString(strAlias)),
        QMessageBox::Yes | QMessageBox::Cancel,
        QMessageBox::Cancel);

    if (retval != QMessageBox::Yes) return;

    WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();

    if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) {
        WalletModel::UnlockContext ctx(walletModel->requestUnlock());

        if (!ctx.isValid()) return; // Unlock wallet was cancelled

        StartAlias(strAlias);
        return;
    }

    StartAlias(strAlias);
}

void MasternodeList::on_startAllButton_clicked()
{
    // Display message box
    QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm all masternodes start"),
        tr("Are you sure you want to start ALL masternodes?"),
        QMessageBox::Yes | QMessageBox::Cancel,
        QMessageBox::Cancel);

    if (retval != QMessageBox::Yes) return;

    WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();

    if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) {
        WalletModel::UnlockContext ctx(walletModel->requestUnlock());

        if (!ctx.isValid()) return; // Unlock wallet was cancelled

        StartAll();
        return;
    }

    StartAll();
}

void MasternodeList::on_startMissingButton_clicked()
{
    if (!masternodeSync.IsMasternodeListSynced()) {
        QMessageBox::critical(this, tr("Command is not available right now"),
            tr("You can't use this command until masternode list is synced"));
        return;
    }

    // Display message box
    QMessageBox::StandardButton retval = QMessageBox::question(this,
        tr("Confirm missing masternodes start"),
        tr("Are you sure you want to start MISSING masternodes?"),
        QMessageBox::Yes | QMessageBox::Cancel,
        QMessageBox::Cancel);

    if (retval != QMessageBox::Yes) return;

    WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus();

    if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) {
        WalletModel::UnlockContext ctx(walletModel->requestUnlock());

        if (!ctx.isValid()) return; // Unlock wallet was cancelled

        StartAll("start-missing");
        return;
    }

    StartAll("start-missing");
}

void MasternodeList::on_tableWidgetMyMasternodes_itemSelectionChanged()
{
    if (ui->tableWidgetMyMasternodes->selectedItems().count() > 0) {
        ui->startButton->setEnabled(true);
    }
}

void MasternodeList::on_UpdateButton_clicked()
{
    updateMyNodeList(true);
}
<|endoftext|>


<commit_before>/* This file is part of QJson
 *
 * Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QStringList>
#include <QVariant>

#include <json_driver.hh>

int main(int argc, char *argv[]) {
  QCoreApplication app (argc, argv);

  if (app.arguments().size() != 2) {
    qFatal("You have to specify the file containing the json code");
    exit (1);
  }

  QString filename = app.arguments()[1];
  if (!QFile::exists ( filename )) {
    qFatal ("The file you specified doesn't exist!");
    exit (1);
  }

  JSonDriver driver;
  bool status;

  QFile file (filename);
  QVariant data = driver.parse (&file, &status);
  if (status) {
    qFatal("%s:%i - Error: %s", filename.toLatin1().data(), driver.errorLine(), driver.error().toLatin1().data());
    exit (1);
  }
  else {
    qDebug() << "json object successfully converted to:";
    qDebug() << data;
  }

  return 0;
}
<commit_msg>Added a new test program for qjson: it simply loads json objects from a file, converts and dump them on stdout<commit_after>/* This file is part of QJson
 *
 * Copyright (C) 2009 Flavio Castelli <flavio.castelli@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QStringList>
#include <QVariant>

#include <json_driver.hh>

int main(int argc, char *argv[]) {
  QCoreApplication app (argc, argv);

  if (app.arguments().size() != 2) {
    qCritical("You have to specify the file containing the json code");
    exit (1);
  }

  QString filename = app.arguments()[1];
  if (!QFile::exists ( filename )) {
    qCritical ("The file you specified doesn't exist!");
    exit (1);
  }

  JSonDriver driver;
  bool status;

  QFile file (filename);
  QVariant data = driver.parse (&file, &status);
  if (status) {
    qCritical("%s:%i - Error: %s", filename.toLatin1().data(), driver.errorLine(), driver.error().toLatin1().data());
    exit (1);
  }
  else {
    qDebug() << "json object successfully converted to:";
    qDebug() << data;
  }

  return 0;
}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h"

#include <string.h>

#include "webrtc/base/checks.h"

namespace webrtc {

AudioEncoderCopyRed::AudioEncoderCopyRed(const Config& config)
    : speech_encoder_(config.speech_encoder),
      red_payload_type_(config.payload_type),
      secondary_allocated_(0) {
  CHECK(speech_encoder_) << "Speech encoder not provided.";
}

AudioEncoderCopyRed::~AudioEncoderCopyRed() {
}

int AudioEncoderCopyRed::SampleRateHz() const {
  return speech_encoder_->SampleRateHz();
}

int AudioEncoderCopyRed::RtpTimestampRateHz() const {
  return speech_encoder_->RtpTimestampRateHz();
}

int AudioEncoderCopyRed::NumChannels() const {
  return speech_encoder_->NumChannels();
}

int AudioEncoderCopyRed::Num10MsFramesInNextPacket() const {
  return speech_encoder_->Num10MsFramesInNextPacket();
}

int AudioEncoderCopyRed::Max10MsFramesInAPacket() const {
  return speech_encoder_->Max10MsFramesInAPacket();
}

void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) {
  speech_encoder_->SetTargetBitrate(bits_per_second);
}

void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) {
  DCHECK_GE(fraction, 0.0);
  DCHECK_LE(fraction, 1.0);
  speech_encoder_->SetProjectedPacketLossRate(fraction);
}

bool AudioEncoderCopyRed::EncodeInternal(uint32_t rtp_timestamp,
                                         const int16_t* audio,
                                         size_t max_encoded_bytes,
                                         uint8_t* encoded,
                                         EncodedInfo* info) {
  if (!speech_encoder_->Encode(rtp_timestamp, audio,
                               static_cast<size_t>(SampleRateHz() / 100),
                               max_encoded_bytes, encoded, info))
    return false;
  if (max_encoded_bytes < info->encoded_bytes + secondary_info_.encoded_bytes)
    return false;
  CHECK(info->redundant.empty()) << "Cannot use nested redundant encoders.";

  if (info->encoded_bytes > 0) {
    // |info| will be implicitly cast to an EncodedInfoLeaf struct, effectively
    // discarding the (empty) vector of redundant information. This is
    // intentional.
    info->redundant.push_back(*info);
    DCHECK_EQ(info->redundant.size(), 1u);
    if (secondary_info_.encoded_bytes > 0) {
      memcpy(&encoded[info->encoded_bytes], secondary_encoded_.get(),
             secondary_info_.encoded_bytes);
      info->redundant.push_back(secondary_info_);
      DCHECK_EQ(info->redundant.size(), 2u);
    }
    // Save primary to secondary.
    if (secondary_allocated_ < info->encoded_bytes) {
      secondary_encoded_.reset(new uint8_t[info->encoded_bytes]);
      secondary_allocated_ = info->encoded_bytes;
    }
    CHECK(secondary_encoded_);
    memcpy(secondary_encoded_.get(), encoded, info->encoded_bytes);
    secondary_info_ = *info;
  }
  // Update main EncodedInfo.
  info->payload_type = red_payload_type_;
  info->encoded_bytes = 0;
  for (std::vector<EncodedInfoLeaf>::const_iterator it =
           info->redundant.begin();
       it != info->redundant.end(); ++it) {
    info->encoded_bytes += it->encoded_bytes;
  }
  return true;
}

}  // namespace webrtc
<commit_msg>AudioEncoderCopyRed: CHECK that encode call doesn't fail<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h"

#include <string.h>

#include "webrtc/base/checks.h"

namespace webrtc {

AudioEncoderCopyRed::AudioEncoderCopyRed(const Config& config)
    : speech_encoder_(config.speech_encoder),
      red_payload_type_(config.payload_type),
      secondary_allocated_(0) {
  CHECK(speech_encoder_) << "Speech encoder not provided.";
}

AudioEncoderCopyRed::~AudioEncoderCopyRed() {
}

int AudioEncoderCopyRed::SampleRateHz() const {
  return speech_encoder_->SampleRateHz();
}

int AudioEncoderCopyRed::RtpTimestampRateHz() const {
  return speech_encoder_->RtpTimestampRateHz();
}

int AudioEncoderCopyRed::NumChannels() const {
  return speech_encoder_->NumChannels();
}

int AudioEncoderCopyRed::Num10MsFramesInNextPacket() const {
  return speech_encoder_->Num10MsFramesInNextPacket();
}

int AudioEncoderCopyRed::Max10MsFramesInAPacket() const {
  return speech_encoder_->Max10MsFramesInAPacket();
}

void AudioEncoderCopyRed::SetTargetBitrate(int bits_per_second) {
  speech_encoder_->SetTargetBitrate(bits_per_second);
}

void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) {
  DCHECK_GE(fraction, 0.0);
  DCHECK_LE(fraction, 1.0);
  speech_encoder_->SetProjectedPacketLossRate(fraction);
}

bool AudioEncoderCopyRed::EncodeInternal(uint32_t rtp_timestamp,
                                         const int16_t* audio,
                                         size_t max_encoded_bytes,
                                         uint8_t* encoded,
                                         EncodedInfo* info) {
  CHECK(speech_encoder_->Encode(rtp_timestamp, audio,
                                static_cast<size_t>(SampleRateHz() / 100),
                                max_encoded_bytes, encoded, info));
  CHECK_GE(max_encoded_bytes,
           info->encoded_bytes + secondary_info_.encoded_bytes);
  CHECK(info->redundant.empty()) << "Cannot use nested redundant encoders.";

  if (info->encoded_bytes > 0) {
    // |info| will be implicitly cast to an EncodedInfoLeaf struct, effectively
    // discarding the (empty) vector of redundant information. This is
    // intentional.
    info->redundant.push_back(*info);
    DCHECK_EQ(info->redundant.size(), 1u);
    if (secondary_info_.encoded_bytes > 0) {
      memcpy(&encoded[info->encoded_bytes], secondary_encoded_.get(),
             secondary_info_.encoded_bytes);
      info->redundant.push_back(secondary_info_);
      DCHECK_EQ(info->redundant.size(), 2u);
    }
    // Save primary to secondary.
    if (secondary_allocated_ < info->encoded_bytes) {
      secondary_encoded_.reset(new uint8_t[info->encoded_bytes]);
      secondary_allocated_ = info->encoded_bytes;
    }
    CHECK(secondary_encoded_);
    memcpy(secondary_encoded_.get(), encoded, info->encoded_bytes);
    secondary_info_ = *info;
  }
  // Update main EncodedInfo.
  info->payload_type = red_payload_type_;
  info->encoded_bytes = 0;
  for (std::vector<EncodedInfoLeaf>::const_iterator it =
           info->redundant.begin();
       it != info->redundant.end(); ++it) {
    info->encoded_bytes += it->encoded_bytes;
  }
  return true;
}

}  // namespace webrtc
<|endoftext|>


<commit_before>#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"
#include "guiutil.h"
#include "bitcoinunits.h"
#include "addressbookpage.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"

#include <QApplication>
#include <QClipboard>

SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
    QFrame(parent),
    ui(new Ui::SendCoinsEntry),
    model(0)
{
    ui->setupUi(this);

#ifdef Q_OS_MAC
    ui->payToLayout->setSpacing(4);
#endif
#if QT_VERSION >= 0x040700
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
    ui->payTo->setPlaceholderText(tr("Enter a BitBar address (e.g. BZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)"));
#endif
//ui->payAmount->StyleSheet("QComboBox{padding: 2px 10px 2px 10px;background-color:rgb(235,227,181);border:2px solid grey}");

ui->payAmount->setStyleSheet("padding: 2px 25px 2px 2px;background-color:rgb(235,227,181);border:2px solid grey");
    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(ui->payTo);

    GUIUtil::setupAddressWidget(ui->payTo, this);
}

SendCoinsEntry::~SendCoinsEntry()
{
    delete ui;
}

void SendCoinsEntry::on_pasteButton_clicked()
{
    // Paste text from clipboard into recipient field
    ui->payTo->setText(QApplication::clipboard()->text());
}

void SendCoinsEntry::on_addressBookButton_clicked()
{
    if(!model)
        return;
    AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
    dlg.setModel(model->getAddressTableModel());
    if(dlg.exec())
    {
        ui->payTo->setText(dlg.getReturnValue());
        ui->payAmount->setFocus();
    }
}

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    if(!model)
        return;
    // Fill in label from address book, if address has an associated label
    QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
    if(!associatedLabel.isEmpty())
        ui->addAsLabel->setText(associatedLabel);
}

void SendCoinsEntry::setModel(WalletModel *model)
{
    this->model = model;

    if(model && model->getOptionsModel())
        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

    connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
    clear();
}

void SendCoinsEntry::setRemoveEnabled(bool enabled)
{
    ui->deleteButton->setEnabled(enabled);
}

void SendCoinsEntry::clear()
{
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->payTo->setFocus();
    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void SendCoinsEntry::on_deleteButton_clicked()
{
    emit removeEntry(this);
}

bool SendCoinsEntry::validate()
{
    // Check input validity
    bool retval = true;

    if(!ui->payAmount->validate())
    {
        retval = false;
    }
    else
    {
        if(ui->payAmount->value() <= 0)
        {
            // Cannot send 0 coins or less
            ui->payAmount->setValid(false);
            retval = false;
        }
    }

    if(!ui->payTo->hasAcceptableInput() ||
       (model && !model->validateAddress(ui->payTo->text())))
    {
        ui->payTo->setValid(false);
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    SendCoinsRecipient rv;

    rv.address = ui->payTo->text();
    rv.label = ui->addAsLabel->text();
    rv.amount = ui->payAmount->value();

    return rv;
}

QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, ui->payTo);
    QWidget::setTabOrder(ui->payTo, ui->addressBookButton);
    QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
    QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
    QWidget::setTabOrder(ui->deleteButton, ui->addAsLabel);
    return ui->payAmount->setupTabChain(ui->addAsLabel);
}

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    ui->payTo->setText(value.address);
    ui->addAsLabel->setText(value.label);
    ui->payAmount->setValue(value.amount);
}

bool SendCoinsEntry::isClear()
{
    return ui->payTo->text().isEmpty();
}

void SendCoinsEntry::setFocus()
{
    ui->payTo->setFocus();
}

void SendCoinsEntry::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        // Update payAmount with the current unit
        ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}
<commit_msg>edit for themes<commit_after>#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"
#include "guiutil.h"
#include "bitcoinunits.h"
#include "addressbookpage.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"

#include <QApplication>
#include <QClipboard>

SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
    QFrame(parent),
    ui(new Ui::SendCoinsEntry),
    model(0)
{
    ui->setupUi(this);

#ifdef Q_OS_MAC
    ui->payToLayout->setSpacing(4);
#endif
#if QT_VERSION >= 0x040700
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
    ui->payTo->setPlaceholderText(tr("Enter a BitBar address (e.g. BZo1ga6xuKuQ7JV7M9rGDoxdbYwV5zgQJ5)"));
#endif
//ui->payAmount->StyleSheet("QComboBox{padding: 2px 10px 2px 10px;background-color:rgb(235,227,181);border:2px solid grey}");

//ui->payAmount->setStyleSheet("padding: 2px 25px 2px 2px;background-color:rgb(235,227,181);border:2px solid grey");
    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(ui->payTo);

    GUIUtil::setupAddressWidget(ui->payTo, this);
}

SendCoinsEntry::~SendCoinsEntry()
{
    delete ui;
}

void SendCoinsEntry::on_pasteButton_clicked()
{
    // Paste text from clipboard into recipient field
    ui->payTo->setText(QApplication::clipboard()->text());
}

void SendCoinsEntry::on_addressBookButton_clicked()
{
    if(!model)
        return;
    AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
    dlg.setModel(model->getAddressTableModel());
    if(dlg.exec())
    {
        ui->payTo->setText(dlg.getReturnValue());
        ui->payAmount->setFocus();
    }
}

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    if(!model)
        return;
    // Fill in label from address book, if address has an associated label
    QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
    if(!associatedLabel.isEmpty())
        ui->addAsLabel->setText(associatedLabel);
}

void SendCoinsEntry::setModel(WalletModel *model)
{
    this->model = model;

    if(model && model->getOptionsModel())
        connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

    connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
    clear();
}

void SendCoinsEntry::setRemoveEnabled(bool enabled)
{
    ui->deleteButton->setEnabled(enabled);
}

void SendCoinsEntry::clear()
{
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->payTo->setFocus();
    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void SendCoinsEntry::on_deleteButton_clicked()
{
    emit removeEntry(this);
}

bool SendCoinsEntry::validate()
{
    // Check input validity
    bool retval = true;

    if(!ui->payAmount->validate())
    {
        retval = false;
    }
    else
    {
        if(ui->payAmount->value() <= 0)
        {
            // Cannot send 0 coins or less
            ui->payAmount->setValid(false);
            retval = false;
        }
    }

    if(!ui->payTo->hasAcceptableInput() ||
       (model && !model->validateAddress(ui->payTo->text())))
    {
        ui->payTo->setValid(false);
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    SendCoinsRecipient rv;

    rv.address = ui->payTo->text();
    rv.label = ui->addAsLabel->text();
    rv.amount = ui->payAmount->value();

    return rv;
}

QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, ui->payTo);
    QWidget::setTabOrder(ui->payTo, ui->addressBookButton);
    QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
    QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
    QWidget::setTabOrder(ui->deleteButton, ui->addAsLabel);
    return ui->payAmount->setupTabChain(ui->addAsLabel);
}

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    ui->payTo->setText(value.address);
    ui->addAsLabel->setText(value.label);
    ui->payAmount->setValue(value.amount);
}

bool SendCoinsEntry::isClear()
{
    return ui->payTo->text().isEmpty();
}

void SendCoinsEntry::setFocus()
{
    ui->payTo->setFocus();
}

void SendCoinsEntry::updateDisplayUnit()
{
    if(model && model->getOptionsModel())
    {
        // Update payAmount with the current unit
        ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mcbist.C
/// @brief Run and manage the MCBIST engine
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/mcbist/mcbist.H>
#include <lib/utils/dump_regs.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

namespace mss
{
namespace mcbist
{

///
/// @brief Load a set of MCBIST subtests in to the MCBIST registers
/// @tparam T, the fapi2::TargetType - derived
/// @tparam TT, the mcbistTraits associated with T - derived
/// @param[in] the target to effect
/// @param[in] the mcbist::program
/// @return FAPI2_RC_SUCCSS iff ok
/// @note assumes the MCBIST engine has been configured.
///
template<>
fapi2::ReturnCode load_mcbmr( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                              const mcbist::program<TARGET_TYPE_MCBIST>& i_program )
{

    // Leave if there are no subtests.
    if (0 == i_program.iv_subtests.size())
    {
        FAPI_DBG("no subtests, noting to do");
        return fapi2::current_err;
    }

    // List of the 8 MCBIST registers - each holds 4 subtests.
    static const std::vector< uint64_t > l_memory_registers =
    {
        MCBIST_MCBMR0Q, MCBIST_MCBMR1Q, MCBIST_MCBMR2Q, MCBIST_MCBMR3Q,
        MCBIST_MCBMR4Q, MCBIST_MCBMR5Q, MCBIST_MCBMR6Q, MCBIST_MCBMR7Q,
    };

    std::vector< uint64_t > l_memory_register_buffers =
    {
        0, 0, 0, 0, 0, 0, 0, 0,
    };

    static const size_t SUBTEST_PER_REG = 4;
    static const size_t SUBTEST_PER_PROGRAM = 32;

    static const auto BITS_IN_SUBTEST = sizeof(mcbist::subtest_t<TARGET_TYPE_MCBIST>().iv_mcbmr) * 8;
    static const auto LEFT_SHIFT = (sizeof(uint64_t) * 8) - BITS_IN_SUBTEST;

    ssize_t l_bin = -1;
    size_t l_register_shift = 0;

    // We'll shift this in to position to indicate which subtest is the last
    static const uint64_t l_done_bit( 0x8000000000000000 >> MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_DONE );

    // TK: For now limit MCBIST programs to 32 subtests.
    const auto l_program_size = i_program.iv_subtests.size();
    FAPI_ASSERT( l_program_size <= SUBTEST_PER_PROGRAM,
                 fapi2::MSS_MCBIST_PROGRAM_TOO_BIG().set_PROGRAM_LENGTH(l_program_size),
                 "mcbist program of length %d exceeds arbitrary maximum of %d", l_program_size, SUBTEST_PER_PROGRAM );

    // Distribute the program over the 8 MCBIST subtest registers
    // We need the index, so increment thru i_program.iv_subtests.size()
    for (size_t l_index = 0; l_index < l_program_size; ++l_index)
    {
        l_bin = (l_index % SUBTEST_PER_REG) == 0 ? l_bin + 1 : l_bin;
        l_register_shift = (l_index % SUBTEST_PER_REG) * BITS_IN_SUBTEST;

        l_memory_register_buffers[l_bin] |=
            (uint64_t(i_program.iv_subtests[l_index].iv_mcbmr) << LEFT_SHIFT) >> l_register_shift;

        FAPI_DBG("putting subtest %d (0x%x) in MCBMR%dQ shifted %d 0x%016llx",
                 l_index, i_program.iv_subtests[l_index].iv_mcbmr, l_bin,
                 l_register_shift, l_memory_register_buffers[l_bin]);
    }

    // l_bin and l_register_shift are the values for the last subtest we'll tell the MCBIST about.
    // We need to set that subtest's done-bit so the MCBIST knows it's the end of the line
    l_memory_register_buffers[l_bin] |= l_done_bit >> l_register_shift;
    FAPI_DBG("setting MCBMR%dQ subtest %llu as the last subtest 0x%016llx",
             l_bin, l_register_shift, l_memory_register_buffers[l_bin]);

    // ... and slam the values in to the registers.
    // Could just decrement l_bin, but that scoms the subtests in backwards and is confusing
    for (auto l_index = 0; l_index <= l_bin; ++l_index)
    {
        FAPI_TRY( mss::putScom(i_target, l_memory_registers[l_index], l_memory_register_buffers[l_index]) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Execute the mcbist program
/// @param[in] i_target the target to effect
/// @param[in] i_program, the mcbist program to execute
/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff OK
///
template<>
fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                           const program<TARGET_TYPE_MCBIST>& i_program )
{
    typedef mcbistTraits<TARGET_TYPE_MCBIST> TT;

    static const uint64_t l_done = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_DONE>();
    static const uint64_t l_fail = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_FAIL>();
    static const uint64_t l_in_progress = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_IN_PROGRESS>();

    fapi2::buffer<uint64_t> l_status;

    // Slam the subtests in to the mcbist registers
    FAPI_TRY( load_mcbmr(i_target, i_program) );

    // Slam the parameters in to the mcbist parameter register
    FAPI_TRY( load_mcbparm(i_target, i_program) );

    // Slam the address generator config
    FAPI_TRY( load_addr_gen(i_target, i_program) );

    // Slam the configured address maps down
    FAPI_TRY( load_mcbamr( i_target, i_program) );

    // Slam the config register down
    FAPI_TRY( load_config( i_target, i_program) );

    // Slam the control register down
    FAPI_TRY( load_control( i_target, i_program) );

    // Start the engine, and then poll for completion
    // Note: We need to have a bit in the program for 'async' mode where an attention
    // bit is set and we can fire-and-forget BRS
    FAPI_TRY(start_stop(i_target, mss::START));

    mss::poll(i_target, TT::STATQ_REG, i_program.iv_poll,
              [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool
    {
        FAPI_DBG("mcbist statq 0x%llx, remaining: %d", stat_reg, poll_remaining);
        l_status = stat_reg;
        return l_status.getBit<TT::MCBIST_IN_PROGRESS>() != 1;
    });

    // Check to see if we're still in progress - meaning we timed out.
    FAPI_ASSERT((l_status & l_in_progress) != l_in_progress,
                fapi2::MSS_MCBIST_TIMEOUT().set_TARGET_IN_ERROR(i_target),
                "MCBIST timed out %s", mss::c_str(i_target));

    // The control register has a bit for done-and-happy and a bit for done-and-unhappy
    if ( ((l_status & l_done) == l_done) || ((l_status & l_fail) == l_fail) )
    {
        FAPI_INF("MCBIST completed, processing errors");

        // We're done. It doesn't mean that there were no errors.
        FAPI_TRY( i_program.process_errors(i_target) );

        // If we're here there were no errors, but lets report if the fail bit was set anyway.
        FAPI_ASSERT( (l_status & l_fail) != l_fail,
                     fapi2::MSS_MCBIST_UNKNOWN_FAILURE()
                     .set_TARGET_IN_ERROR(i_target)
                     .set_STATUS_REGISTER(l_status),
                     "MCBIST reported a fail, but process_errors didn't find it 0x%016llx", l_status );

        // And if we're here all is good with the world.
        return fapi2::current_err;
    }

    FAPI_ASSERT(false,
                fapi2::MSS_MCBIST_MULTIPLE_FAIL_BITS()
                .set_TARGET_IN_ERROR(i_target)
                .set_STATUS_REGISTER(l_status),
                "MCBIST executed <shrug>. Something's not good 0x%016llx", l_status );

fapi_try_exit:
    return fapi2::current_err;
}

} // namespace

// Note: outside of the mcbist namespace

///
/// @brief Dump the registers of an mcbist
/// @param[in] i_target, the mcbist in question
/// @return fapi2::FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode dump_regs( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    return fapi2::current_err;
}

} // namespace
<commit_msg>Add L2 p9_mss_scrub<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mcbist/mcbist.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mcbist.C
/// @brief Run and manage the MCBIST engine
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Craig Hamilton <cchamilt@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/mcbist/mcbist.H>
#include <lib/utils/dump_regs.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

namespace mss
{
namespace mcbist
{

const std::pair<uint64_t, uint64_t> mcbistTraits<fapi2::TARGET_TYPE_MCBIST>::address_pairs[] =
{
    { START_ADDRESS_0, END_ADDRESS_0 },
    { START_ADDRESS_1, END_ADDRESS_1 },
    { START_ADDRESS_2, END_ADDRESS_2 },
    { START_ADDRESS_3, END_ADDRESS_3 },
};

///
/// @brief Load a set of MCBIST subtests in to the MCBIST registers
/// @tparam T, the fapi2::TargetType - derived
/// @tparam TT, the mcbistTraits associated with T - derived
/// @param[in] the target to effect
/// @param[in] the mcbist::program
/// @return FAPI2_RC_SUCCSS iff ok
/// @note assumes the MCBIST engine has been configured.
///
template<>
fapi2::ReturnCode load_mcbmr( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                              const mcbist::program<TARGET_TYPE_MCBIST>& i_program )
{

    // Leave if there are no subtests.
    if (0 == i_program.iv_subtests.size())
    {
        FAPI_DBG("no subtests, noting to do");
        return fapi2::current_err;
    }

    // List of the 8 MCBIST registers - each holds 4 subtests.
    static const std::vector< uint64_t > l_memory_registers =
    {
        MCBIST_MCBMR0Q, MCBIST_MCBMR1Q, MCBIST_MCBMR2Q, MCBIST_MCBMR3Q,
        MCBIST_MCBMR4Q, MCBIST_MCBMR5Q, MCBIST_MCBMR6Q, MCBIST_MCBMR7Q,
    };

    std::vector< uint64_t > l_memory_register_buffers =
    {
        0, 0, 0, 0, 0, 0, 0, 0,
    };

    static const size_t SUBTEST_PER_REG = 4;
    static const size_t SUBTEST_PER_PROGRAM = 32;

    static const auto BITS_IN_SUBTEST = sizeof(mcbist::subtest_t<TARGET_TYPE_MCBIST>().iv_mcbmr) * 8;
    static const auto LEFT_SHIFT = (sizeof(uint64_t) * 8) - BITS_IN_SUBTEST;

    ssize_t l_bin = -1;
    size_t l_register_shift = 0;

    // We'll shift this in to position to indicate which subtest is the last
    static const uint64_t l_done_bit( 0x8000000000000000 >> MCBIST_MCBMR0Q_MCBIST_CFG_TEST00_DONE );

    // TK: For now limit MCBIST programs to 32 subtests.
    const auto l_program_size = i_program.iv_subtests.size();
    FAPI_ASSERT( l_program_size <= SUBTEST_PER_PROGRAM,
                 fapi2::MSS_MCBIST_PROGRAM_TOO_BIG().set_PROGRAM_LENGTH(l_program_size),
                 "mcbist program of length %d exceeds arbitrary maximum of %d", l_program_size, SUBTEST_PER_PROGRAM );

    // Distribute the program over the 8 MCBIST subtest registers
    // We need the index, so increment thru i_program.iv_subtests.size()
    for (size_t l_index = 0; l_index < l_program_size; ++l_index)
    {
        l_bin = (l_index % SUBTEST_PER_REG) == 0 ? l_bin + 1 : l_bin;
        l_register_shift = (l_index % SUBTEST_PER_REG) * BITS_IN_SUBTEST;

        l_memory_register_buffers[l_bin] |=
            (uint64_t(i_program.iv_subtests[l_index].iv_mcbmr) << LEFT_SHIFT) >> l_register_shift;

        FAPI_DBG("putting subtest %d (0x%x) in MCBMR%dQ shifted %d 0x%016llx",
                 l_index, i_program.iv_subtests[l_index].iv_mcbmr, l_bin,
                 l_register_shift, l_memory_register_buffers[l_bin]);
    }

    // l_bin and l_register_shift are the values for the last subtest we'll tell the MCBIST about.
    // We need to set that subtest's done-bit so the MCBIST knows it's the end of the line
    l_memory_register_buffers[l_bin] |= l_done_bit >> l_register_shift;
    FAPI_DBG("setting MCBMR%dQ subtest %llu as the last subtest 0x%016llx",
             l_bin, l_register_shift, l_memory_register_buffers[l_bin]);

    // ... and slam the values in to the registers.
    // Could just decrement l_bin, but that scoms the subtests in backwards and is confusing
    for (auto l_index = 0; l_index <= l_bin; ++l_index)
    {
        FAPI_TRY( mss::putScom(i_target, l_memory_registers[l_index], l_memory_register_buffers[l_index]) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Execute the mcbist program
/// @param[in] i_target the target to effect
/// @param[in] i_program, the mcbist program to execute
/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff OK
///
template<>
fapi2::ReturnCode execute( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                           const program<TARGET_TYPE_MCBIST>& i_program )
{
    typedef mcbistTraits<TARGET_TYPE_MCBIST> TT;

    static const uint64_t l_done = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_DONE>();
    static const uint64_t l_fail = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_FAIL>();
    static const uint64_t l_in_progress = fapi2::buffer<uint64_t>().setBit<TT::MCBIST_IN_PROGRESS>();

    fapi2::buffer<uint64_t> l_status;

    // A small vector of addresses to poll during the polling loop
    static const std::vector<mss::poll_probe<fapi2::TARGET_TYPE_MCBIST>> l_probes =
    {
        {i_target, "mcbist current address", MCBIST_MCBMCATQ},
    };

    // Slam the subtests in to the mcbist registers
    FAPI_TRY( load_mcbmr(i_target, i_program) );

    // Slam the parameters in to the mcbist parameter register
    FAPI_TRY( load_mcbparm(i_target, i_program) );

    // Slam the address generator config
    FAPI_TRY( load_addr_gen(i_target, i_program) );

    // Slam the configured address maps down
    FAPI_TRY( load_mcbamr( i_target, i_program) );

    // Slam the config register down
    FAPI_TRY( load_config( i_target, i_program) );

    // Slam the control register down
    FAPI_TRY( load_control( i_target, i_program) );

    // Start the engine, and then poll for completion
    // Note: We need to have a bit in the program for 'async' mode where an attention
    // bit is set and we can fire-and-forget BRS
    FAPI_TRY(start_stop(i_target, mss::START));

    mss::poll(i_target, TT::STATQ_REG, i_program.iv_poll,
              [&l_status](const size_t poll_remaining, const fapi2::buffer<uint64_t>& stat_reg) -> bool
    {
        FAPI_DBG("mcbist statq 0x%llx, remaining: %d", stat_reg, poll_remaining);
        l_status = stat_reg;
        return l_status.getBit<TT::MCBIST_IN_PROGRESS>() != 1;
    },
    l_probes);

    // Check to see if we're still in progress - meaning we timed out.
    FAPI_ASSERT((l_status & l_in_progress) != l_in_progress,
                fapi2::MSS_MCBIST_TIMEOUT().set_TARGET_IN_ERROR(i_target),
                "MCBIST timed out %s", mss::c_str(i_target));

    // The control register has a bit for done-and-happy and a bit for done-and-unhappy
    if ( ((l_status & l_done) == l_done) || ((l_status & l_fail) == l_fail) )
    {
        FAPI_INF("MCBIST completed, processing errors");

        // We're done. It doesn't mean that there were no errors.
        FAPI_TRY( i_program.process_errors(i_target) );

        // If we're here there were no errors, but lets report if the fail bit was set anyway.
        FAPI_ASSERT( (l_status & l_fail) != l_fail,
                     fapi2::MSS_MCBIST_UNKNOWN_FAILURE()
                     .set_TARGET_IN_ERROR(i_target)
                     .set_STATUS_REGISTER(l_status),
                     "MCBIST reported a fail, but process_errors didn't find it 0x%016llx", l_status );

        // And if we're here all is good with the world.
        return fapi2::current_err;
    }

    FAPI_ASSERT(false,
                fapi2::MSS_MCBIST_MULTIPLE_FAIL_BITS()
                .set_TARGET_IN_ERROR(i_target)
                .set_STATUS_REGISTER(l_status),
                "MCBIST executed <shrug>. Something's not good 0x%016llx", l_status );

fapi_try_exit:
    return fapi2::current_err;
}

} // namespace

// Note: outside of the mcbist namespace

///
/// @brief Dump the registers of an mcbist
/// @param[in] i_target, the mcbist in question
/// @return fapi2::FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode dump_regs( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    return fapi2::current_err;
}

} // namespace
<|endoftext|>


<commit_before>#include "bitcoin-config.h"
#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif

#ifdef ENABLE_WALLET
#include "paymentservertests.h"
#endif
#include "uritests.h"

#include <QCoreApplication>
#include <QObject>
#include <QTest>

#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
#endif

// This is all you need to run all the tests
int main(int argc, char *argv[])
{
    bool fInvalid = false;

    // Don't remove this, it's needed to access
    // QCoreApplication:: in the tests
    QCoreApplication app(argc, argv);
    app.setApplicationName("Bitcoin-Qt-test");

    URITests test1;
    if (QTest::qExec(&test1) != 0)
        fInvalid = true;
#ifdef ENABLE_WALLET
    PaymentServerTests test2;
    if (QTest::qExec(&test2) != 0)
        fInvalid = true;
#endif

    return fInvalid;
}
<commit_msg>Update test_main.cpp<commit_after>#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif

#ifdef ENABLE_WALLET
#include "paymentservertests.h"
#endif
#include "uritests.h"

#include <QCoreApplication>
#include <QObject>
#include <QTest>

#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
#endif

// This is all you need to run all the tests
int main(int argc, char *argv[])
{
    bool fInvalid = false;

    // Don't remove this, it's needed to access
    // QCoreApplication:: in the tests
    QCoreApplication app(argc, argv);
    app.setApplicationName("Bitcoin-Qt-test");

    URITests test1;
    if (QTest::qExec(&test1) != 0)
        fInvalid = true;
#ifdef ENABLE_WALLET
    PaymentServerTests test2;
    if (QTest::qExec(&test2) != 0)
        fInvalid = true;
#endif

    return fInvalid;
}
<|endoftext|>


<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

EWCModelBase provides some of the functionality of EWCModel for inverse
evaluating.

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

#include "ewc_model_base.hh"

#define DEBUG_FLAG 0

namespace Amanzi {

// ----------------------------------------------------------------------
// Lightweight wrapper to forward-evaluate the model.
// ----------------------------------------------------------------------
int EWCModelBase::Evaluate(double T, double p,
        double& energy, double& wc) {
  AmanziGeometry::Point res(2);
  int ierr = EvaluateEnergyAndWaterContent_(T,p,res);
  energy = res[0];
  wc = res[1];
  return ierr;
};

/* ----------------------------------------------------------------------
Solves a given energy and water content (at a given, fixed porosity), for
temperature and pressure.

Note this cannot really work for a saturated cell, as d_wc / d{T,p} = 0
<
Error codes:

  1 = Singular Jacobian at some point in the evaluation.  Often this is
      because the cell is saturated or becomes saturated and below
      freezing.
  2 = Iteration did not converge in max_steps (hard-coded to be 100 for
      now).
---------------------------------------------------------------------- */
int EWCModelBase::InverseEvaluate(double energy, double wc,
        double& T, double& p, bool verbose) {

  // -- scaling for the norms
  double wc_scale = 10.;
  double e_scale = 10000.;
  double T_corr_cap = 2.;
  double p_corr_cap = 200000.;
  double tol = 1.e-6;
  double max_steps = 100;
  double stepnum = 0;

  // get the initial residual
  AmanziGeometry::Point res(2);
  WhetStone::Tensor jac(2,2);
  int ierr = EvaluateEnergyAndWaterContentAndJacobian_(T,p,res,jac);
  if (ierr) {
    std::cout << "Error in evaluation: " << ierr << std::endl;
    return ierr + 10;
  }

  if (verbose) {
    std::cout << "Inverse Evaluating, e=" << energy << ", wc=" << wc << std::endl;
    std::cout << "   guess T,p (res) = " << T << ", " << p << " (" << res[0] << ", " << res[1] << ")" << std::endl;
  }

  AmanziGeometry::Point f(2);
  f[0] = energy;
  f[1] = wc;
  res = res - f;

  // check convergence
  AmanziGeometry::Point scaled_res(res);
  scaled_res[0] = res[0] / e_scale; scaled_res[1] = res[1] / wc_scale;
  double norm = AmanziGeometry::norm(scaled_res);

  bool converged = norm < tol;

  // workspace
  AmanziGeometry::Point x(2);
  AmanziGeometry::Point x_tmp(2);
  x[0] = T; x[1] = p;
  x_tmp[0] = T; x_tmp[1] = p;

  while (!converged) {
    // calculate the update size
    double detJ = jac.determinant();
    AmanziGeometry::Point correction;

    if (std::abs(detJ) < 1.e-20) {
      std::cout << " Zero determinant of Jacobian:" << std::endl;
      std::cout << "   [" << jac(0,0) << "," << jac(0,1) << "]" << std::endl;
      std::cout << "   [" << jac(1,0) << "," << jac(1,1) << "]" << std::endl;
      std::cout << "  at T,p = " << x_tmp[0] << ", " << x_tmp[1] << std::endl;
      std::cout << "  with res(e,wc) = " << res[0] << ", " << res[1] << std::endl;
      return 1;
    }

    jac.inverse();
    correction = jac * res;

    // cap the correction
    double scale = 1.;
    if (std::abs(correction[0]) > T_corr_cap) {
      scale = T_corr_cap / std::abs(correction[0]);
    }
    if (std::abs(correction[1]) > p_corr_cap) {
      double pscale = p_corr_cap / std::abs(correction[1]);
      scale = std::min(scale,pscale);
    }
    correction *= scale;

    // perform the update
    x_tmp = x - correction;
    ierr = EvaluateEnergyAndWaterContentAndJacobian_(x_tmp[0],x_tmp[1],res,jac);
    if (ierr) {
      std::cout << "Error in evaluation: " << ierr << std::endl;
      return ierr + 10;
    }
    res = res - f;

    // check convergence and damping
    scaled_res[0] = res[0] / e_scale; scaled_res[1] = res[1] / wc_scale;
    double norm_new = AmanziGeometry::norm(scaled_res);

    if (verbose) {
      std::cout << "  Iter: " << stepnum;
      std::cout << " corrected T,p (res) [norm] = " << x_tmp[0] << ", " << x_tmp[1] << " (" << res[0] << ", " << res[1] << ") ["
                << norm_new << "]" << std::endl;
    }

    double damp = 1.;
    bool backtracking_required = false;
    while (norm_new > norm) {
      backtracking_required = true;

      // backtrack
      damp *= 0.5;
      x_tmp = x - (damp * correction);

      // evaluate the damped value
      ierr = EvaluateEnergyAndWaterContent_(x_tmp[0],x_tmp[1],res);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      res = res - f;

      // check the new residual
      scaled_res[0] = res[0] / e_scale; scaled_res[1] = res[1] / wc_scale;
      norm_new = AmanziGeometry::norm(scaled_res);

      if (verbose) {
        std::cout << "    Damping: " << stepnum;
        std::cout << " corrected T,p (res) [norm] = " << x_tmp[0] << ", " << x_tmp[1] << " (" << res[0] << ", " << res[1] << ") ["
                  << norm_new << "]" << std::endl;
      }

    }

    if (backtracking_required) {
      // must recalculate the Jacobian at the new value
      ierr = EvaluateEnergyAndWaterContentAndJacobian_(x_tmp[0],x_tmp[1],res,jac);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      res = res - f;
    }

    // iterate
    x = x_tmp;
    norm = norm_new;

    AmanziGeometry::Point scaled_correction = damp * correction;
    scaled_correction[1] = scaled_correction[1] / 100000.;
    converged = norm < tol || AmanziGeometry::norm(scaled_correction) < 1.e-5;

    stepnum++;
    if (stepnum > max_steps && !converged) {
      std::cout << " Nonconverged after " << max_steps << " steps with norm (tol) "
                << norm << " (" << tol << ")" << std::endl;
      return 2;
    }
  }

  T = x[0];
  p = x[1];
  return 0;
}

/* ----------------------------------------------------------------------
Solves a given energy and water content (at a given, fixed porosity), for
temperature and pressure.

Note this cannot really work for a saturated cell, as d_wc / d{T,p} = 0

Error codes:

  1 = Singular Jacobian at some point in the evaluation.  Often this is
      because the cell is saturated or becomes saturated and below
      freezing.
  2 = Iteration did not converge in max_steps (hard-coded to be 100 for
      now).
---------------------------------------------------------------------- */
int EWCModelBase::InverseEvaluateEnergy(double energy, double p,
        double& T) {

  // -- scaling for the norms
  double e_scale = 10000.;
  double T_corr_cap = 2.;
  double tol = 1.e-6;
  double max_steps = 100;
  double stepnum = 0;

  // get the initial residual
  AmanziGeometry::Point res(2);
  WhetStone::Tensor jac(2,2);
  int ierr = EvaluateEnergyAndWaterContentAndJacobian_(T,p,res,jac);
  if (ierr) {
    std::cout << "Error in evaluation: " << ierr << std::endl;
    return ierr + 10;
  }

#if DEBUG_FLAG
  std::cout << "Inverse Evaluating, e=" << energy << std::endl;
  std::cout << "   guess T,p (res) = " << T << ", " << p << " (" << res[0] << ")" << std::endl;
#endif

  // check convergence
  double f = res[0] - energy;
  double norm = std::abs(f);
  bool converged = norm < tol;

  // workspace
  double T_tmp = T;
  double T_tmp2 = T;

  while (!converged) {
    // calculate the update size
    double detJ = jac(0,0);
    double correction;

    if (std::abs(detJ) < 1.e-20) {
      std::cout << " Zero determinant of Jacobian:" << std::endl;
      std::cout << "   [" << jac(0,0) << "]" << std::endl;
      std::cout << "  at T,p = " << T_tmp2 << ", " << p << std::endl;
      std::cout << "  with res(e) = " << f << std::endl;
      return 1;
    }

    correction = f / detJ;

    // cap the correction
    if (std::abs(correction) > T_corr_cap) {
      correction = correction / std::abs(correction) * T_corr_cap;
    }

    // perform the update
    T_tmp2 = T_tmp - correction;
    ierr = EvaluateEnergyAndWaterContentAndJacobian_(T_tmp2,p,res,jac);
    if (ierr) {
      std::cout << "Error in evaluation: " << ierr << std::endl;
      return ierr + 10;
    }
    f = res[0] - energy;

    // check convergence and damping
    double norm_new = std::abs(f);

#if DEBUG_FLAG
      std::cout << "  Iter: " << stepnum;
      std::cout << " corrected T,p (res) [norm] = " << T_tmp2 << ", " << p << " (" << f << ")" << std::endl;
#endif

    double damp = 1.;
    bool backtracking_required = false;
    while (norm_new > norm) {
      backtracking_required = true;

      // backtrack
      damp *= 0.5;
      T_tmp2 = T_tmp - (damp * correction);

      // evaluate the damped value
      ierr = EvaluateEnergyAndWaterContent_(T_tmp2,p,res);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      f = res[0] - energy;

      // check the new residual
      norm_new = std::abs(f);

#if DEBUG_FLAG
      std::cout << "    Damping: " << stepnum;
      std::cout << " corrected T,p (res) [norm] = " << T_tmp2 << ", " << p << " (" << f << ")" << std::endl;
#endif

    }

    if (backtracking_required) {
      // must recalculate the Jacobian at the new value
      ierr = EvaluateEnergyAndWaterContentAndJacobian_(T_tmp2,p,res,jac);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      f = res[0] - energy;
    }

    // iterate
    T_tmp = T_tmp2;
    norm = norm_new;

    converged = norm < tol || std::abs(correction) < 1.e-3;
    stepnum++;
    if (stepnum > max_steps && !converged) {
      std::cout << " Nonconverged after " << max_steps << " steps with norm (tol) "
                << norm << " (" << tol << ")" << std::endl;
      return 2;
    }
  }

  T = T_tmp;
  return 0;
}

int EWCModelBase::EvaluateEnergyAndWaterContentAndJacobian_(double T, double p,
        AmanziGeometry::Point& result, WhetStone::Tensor& jac) {
  return EvaluateEnergyAndWaterContentAndJacobian_FD_(T, p, result, jac);
}

int EWCModelBase::EvaluateEnergyAndWaterContentAndJacobian_FD_(double T, double p,
        AmanziGeometry::Point& result, WhetStone::Tensor& jac) {
  double eps_T = 1.e-7;
  double eps_p = 1.e-3;

  int ierr = EvaluateEnergyAndWaterContent_(T, p, result);
  if (ierr) return ierr;
  AmanziGeometry::Point test(result);
  AmanziGeometry::Point test2(result);

  // d / dT
  jac(0,0) = 0.;
  jac(1,0) = 0.;

  bool done = false;
  int its = 0;
  while (!done) {
    ierr = EvaluateEnergyAndWaterContent_(T + eps_T, p, test);
    if (ierr) return ierr;

    jac(0,0) = (test[0] - result[0]) / (eps_T);
    jac(1,0) = (test[1] - result[1]) / (eps_T);

    its++;
    done = (std::abs(jac(0,0)) > 1.e-12) || (std::abs(jac(1,0)) > 1.e-12);
    done |= (its > 30);
    eps_T *= 2;
  }

  // d / dp
  jac(0,1) = 0.;
  jac(1,1) = 0.;

  // failure point seems to be d/dp = 0, and p seems to need to be centered
  done = false;
  its = 0;
  while (!done) {
    ierr = EvaluateEnergyAndWaterContent_(T, p + eps_p, test);
    if (ierr) return ierr;
    ierr = EvaluateEnergyAndWaterContent_(T, p - eps_p, test2);
    if (ierr) return ierr;

    jac(0,1) = (test[0] - test2[0]) / (2*eps_p);
    jac(1,1) = (test[1] - test2[1]) / (2*eps_p);

    its++;
    done = (std::abs(jac(0,1)) > 1.e-12) || (std::abs(jac(1,1)) > 1.e-12);
    done |= (its > 30);
    eps_p *= 2;
  }

  return 0;
}

} // namespace
<commit_msg>updates convergence test for allowing to continue with smaller corrections<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

EWCModelBase provides some of the functionality of EWCModel for inverse
evaluating.

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

#include "ewc_model_base.hh"

#define DEBUG_FLAG 0

namespace Amanzi {

// ----------------------------------------------------------------------
// Lightweight wrapper to forward-evaluate the model.
// ----------------------------------------------------------------------
int EWCModelBase::Evaluate(double T, double p,
        double& energy, double& wc) {
  AmanziGeometry::Point res(2);
  int ierr = EvaluateEnergyAndWaterContent_(T,p,res);
  energy = res[0];
  wc = res[1];
  return ierr;
};

/* ----------------------------------------------------------------------
Solves a given energy and water content (at a given, fixed porosity), for
temperature and pressure.

Note this cannot really work for a saturated cell, as d_wc / d{T,p} = 0
<
Error codes:

  1 = Singular Jacobian at some point in the evaluation.  Often this is
      because the cell is saturated or becomes saturated and below
      freezing.
  2 = Iteration did not converge in max_steps (hard-coded to be 100 for
      now).
---------------------------------------------------------------------- */
int EWCModelBase::InverseEvaluate(double energy, double wc,
        double& T, double& p, bool verbose) {

  // -- scaling for the norms
  double wc_scale = 10.;
  double e_scale = 10000.;
  double T_corr_cap = 2.;
  double p_corr_cap = 200000.;
  double tol = 1.e-6;
  double max_steps = 100;
  double stepnum = 0;

  // get the initial residual
  AmanziGeometry::Point res(2);
  WhetStone::Tensor jac(2,2);
  int ierr = EvaluateEnergyAndWaterContentAndJacobian_(T,p,res,jac);
  if (ierr) {
    std::cout << "Error in evaluation: " << ierr << std::endl;
    return ierr + 10;
  }

  if (verbose) {
    std::cout << "Inverse Evaluating, e=" << energy << ", wc=" << wc << std::endl;
    std::cout << "   guess T,p (res) = " << T << ", " << p << " (" << res[0] << ", " << res[1] << ")" << std::endl;
  }

  AmanziGeometry::Point f(2);
  f[0] = energy;
  f[1] = wc;
  res = res - f;

  // check convergence
  AmanziGeometry::Point scaled_res(res);
  scaled_res[0] = res[0] / e_scale; scaled_res[1] = res[1] / wc_scale;
  double norm = AmanziGeometry::norm(scaled_res);

  bool converged = norm < tol;

  // workspace
  AmanziGeometry::Point x(2);
  AmanziGeometry::Point x_tmp(2);
  x[0] = T; x[1] = p;
  x_tmp[0] = T; x_tmp[1] = p;

  while (!converged) {
    // calculate the update size
    double detJ = jac.determinant();
    AmanziGeometry::Point correction;

    if (std::abs(detJ) < 1.e-20) {
      std::cout << " Zero determinant of Jacobian:" << std::endl;
      std::cout << "   [" << jac(0,0) << "," << jac(0,1) << "]" << std::endl;
      std::cout << "   [" << jac(1,0) << "," << jac(1,1) << "]" << std::endl;
      std::cout << "  at T,p = " << x_tmp[0] << ", " << x_tmp[1] << std::endl;
      std::cout << "  with res(e,wc) = " << res[0] << ", " << res[1] << std::endl;
      return 1;
    }

    jac.inverse();
    correction = jac * res;

    // cap the correction
    double scale = 1.;
    if (std::abs(correction[0]) > T_corr_cap) {
      scale = T_corr_cap / std::abs(correction[0]);
    }
    if (std::abs(correction[1]) > p_corr_cap) {
      double pscale = p_corr_cap / std::abs(correction[1]);
      scale = std::min(scale,pscale);
    }
    correction *= scale;

    // perform the update
    x_tmp = x - correction;
    ierr = EvaluateEnergyAndWaterContentAndJacobian_(x_tmp[0],x_tmp[1],res,jac);
    if (ierr) {
      std::cout << "Error in evaluation: " << ierr << std::endl;
      return ierr + 10;
    }
    res = res - f;

    // check convergence and damping
    scaled_res[0] = res[0] / e_scale; scaled_res[1] = res[1] / wc_scale;
    double norm_new = AmanziGeometry::norm(scaled_res);

    if (verbose) {
      std::cout << "  Iter: " << stepnum;
      std::cout << " corrected T,p (res) [norm] = " << x_tmp[0] << ", " << x_tmp[1] << " (" << res[0] << ", " << res[1] << ") ["
                << norm_new << "]" << std::endl;
    }

    double damp = 1.;
    bool backtracking_required = false;
    while (norm_new > norm) {
      backtracking_required = true;

      // backtrack
      damp *= 0.5;
      x_tmp = x - (damp * correction);

      // evaluate the damped value
      ierr = EvaluateEnergyAndWaterContent_(x_tmp[0],x_tmp[1],res);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      res = res - f;

      // check the new residual
      scaled_res[0] = res[0] / e_scale; scaled_res[1] = res[1] / wc_scale;
      norm_new = AmanziGeometry::norm(scaled_res);

      if (verbose) {
        std::cout << "    Damping: " << stepnum;
        std::cout << " corrected T,p (res) [norm] = " << x_tmp[0] << ", " << x_tmp[1] << " (" << res[0] << ", " << res[1] << ") ["
                  << norm_new << "]" << std::endl;
      }

    }

    if (backtracking_required) {
      // must recalculate the Jacobian at the new value
      ierr = EvaluateEnergyAndWaterContentAndJacobian_(x_tmp[0],x_tmp[1],res,jac);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      res = res - f;
    }

    // iterate
    x = x_tmp;
    norm = norm_new;

    AmanziGeometry::Point scaled_correction = damp * correction;
    scaled_correction[1] = scaled_correction[1] / 100000.;
    converged = norm < tol || AmanziGeometry::norm(scaled_correction) < 1.e-10;

    stepnum++;
    if (stepnum > max_steps && !converged) {
      std::cout << " Nonconverged after " << max_steps << " steps with norm (tol) "
                << norm << " (" << tol << ")" << std::endl;
      return 2;
    }
  }

  T = x[0];
  p = x[1];
  return 0;
}

/* ----------------------------------------------------------------------
Solves a given energy and water content (at a given, fixed porosity), for
temperature and pressure.

Note this cannot really work for a saturated cell, as d_wc / d{T,p} = 0

Error codes:

  1 = Singular Jacobian at some point in the evaluation.  Often this is
      because the cell is saturated or becomes saturated and below
      freezing.
  2 = Iteration did not converge in max_steps (hard-coded to be 100 for
      now).
---------------------------------------------------------------------- */
int EWCModelBase::InverseEvaluateEnergy(double energy, double p,
        double& T) {

  // -- scaling for the norms
  double e_scale = 10000.;
  double T_corr_cap = 2.;
  double tol = 1.e-6;
  double max_steps = 100;
  double stepnum = 0;

  // get the initial residual
  AmanziGeometry::Point res(2);
  WhetStone::Tensor jac(2,2);
  int ierr = EvaluateEnergyAndWaterContentAndJacobian_(T,p,res,jac);
  if (ierr) {
    std::cout << "Error in evaluation: " << ierr << std::endl;
    return ierr + 10;
  }

#if DEBUG_FLAG
  std::cout << "Inverse Evaluating, e=" << energy << std::endl;
  std::cout << "   guess T,p (res) = " << T << ", " << p << " (" << res[0] << ")" << std::endl;
#endif

  // check convergence
  double f = res[0] - energy;
  double norm = std::abs(f);
  bool converged = norm < tol;

  // workspace
  double T_tmp = T;
  double T_tmp2 = T;

  while (!converged) {
    // calculate the update size
    double detJ = jac(0,0);
    double correction;

    if (std::abs(detJ) < 1.e-20) {
      std::cout << " Zero determinant of Jacobian:" << std::endl;
      std::cout << "   [" << jac(0,0) << "]" << std::endl;
      std::cout << "  at T,p = " << T_tmp2 << ", " << p << std::endl;
      std::cout << "  with res(e) = " << f << std::endl;
      return 1;
    }

    correction = f / detJ;

    // cap the correction
    if (std::abs(correction) > T_corr_cap) {
      correction = correction / std::abs(correction) * T_corr_cap;
    }

    // perform the update
    T_tmp2 = T_tmp - correction;
    ierr = EvaluateEnergyAndWaterContentAndJacobian_(T_tmp2,p,res,jac);
    if (ierr) {
      std::cout << "Error in evaluation: " << ierr << std::endl;
      return ierr + 10;
    }
    f = res[0] - energy;

    // check convergence and damping
    double norm_new = std::abs(f);

#if DEBUG_FLAG
      std::cout << "  Iter: " << stepnum;
      std::cout << " corrected T,p (res) [norm] = " << T_tmp2 << ", " << p << " (" << f << ")" << std::endl;
#endif

    double damp = 1.;
    bool backtracking_required = false;
    while (norm_new > norm) {
      backtracking_required = true;

      // backtrack
      damp *= 0.5;
      T_tmp2 = T_tmp - (damp * correction);

      // evaluate the damped value
      ierr = EvaluateEnergyAndWaterContent_(T_tmp2,p,res);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      f = res[0] - energy;

      // check the new residual
      norm_new = std::abs(f);

#if DEBUG_FLAG
      std::cout << "    Damping: " << stepnum;
      std::cout << " corrected T,p (res) [norm] = " << T_tmp2 << ", " << p << " (" << f << ")" << std::endl;
#endif

    }

    if (backtracking_required) {
      // must recalculate the Jacobian at the new value
      ierr = EvaluateEnergyAndWaterContentAndJacobian_(T_tmp2,p,res,jac);
      if (ierr) {
        std::cout << "Error in evaluation: " << ierr << std::endl;
        return ierr + 10;
      }
      f = res[0] - energy;
    }

    // iterate
    T_tmp = T_tmp2;
    norm = norm_new;

    converged = norm < tol || std::abs(correction) < 1.e-3;
    stepnum++;
    if (stepnum > max_steps && !converged) {
      std::cout << " Nonconverged after " << max_steps << " steps with norm (tol) "
                << norm << " (" << tol << ")" << std::endl;
      return 2;
    }
  }

  T = T_tmp;
  return 0;
}

int EWCModelBase::EvaluateEnergyAndWaterContentAndJacobian_(double T, double p,
        AmanziGeometry::Point& result, WhetStone::Tensor& jac) {
  return EvaluateEnergyAndWaterContentAndJacobian_FD_(T, p, result, jac);
}

int EWCModelBase::EvaluateEnergyAndWaterContentAndJacobian_FD_(double T, double p,
        AmanziGeometry::Point& result, WhetStone::Tensor& jac) {
  double eps_T = 1.e-7;
  double eps_p = 1.e-3;

  int ierr = EvaluateEnergyAndWaterContent_(T, p, result);
  if (ierr) return ierr;
  AmanziGeometry::Point test(result);
  AmanziGeometry::Point test2(result);

  // d / dT
  jac(0,0) = 0.;
  jac(1,0) = 0.;

  bool done = false;
  int its = 0;
  while (!done) {
    ierr = EvaluateEnergyAndWaterContent_(T + eps_T, p, test);
    if (ierr) return ierr;

    jac(0,0) = (test[0] - result[0]) / (eps_T);
    jac(1,0) = (test[1] - result[1]) / (eps_T);

    its++;
    done = (std::abs(jac(0,0)) > 1.e-12) || (std::abs(jac(1,0)) > 1.e-12);
    done |= (its > 30);
    eps_T *= 2;
  }

  // d / dp
  jac(0,1) = 0.;
  jac(1,1) = 0.;

  // failure point seems to be d/dp = 0, and p seems to need to be centered
  done = false;
  its = 0;
  while (!done) {
    ierr = EvaluateEnergyAndWaterContent_(T, p + eps_p, test);
    if (ierr) return ierr;
    ierr = EvaluateEnergyAndWaterContent_(T, p - eps_p, test2);
    if (ierr) return ierr;

    jac(0,1) = (test[0] - test2[0]) / (2*eps_p);
    jac(1,1) = (test[1] - test2[1]) / (2*eps_p);

    its++;
    done = (std::abs(jac(0,1)) > 1.e-12) || (std::abs(jac(1,1)) > 1.e-12);
    done |= (its > 30);
    eps_p *= 2;
  }

  return 0;
}

} // namespace
<|endoftext|>


<commit_before>#ifndef RDB_PROTOCOL_FUNC_HPP_
#define RDB_PROTOCOL_FUNC_HPP_

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "utils.hpp"

#include "containers/counted.hpp"
#include "protob/protob.hpp"
#include "rdb_protocol/js.hpp"
#include "rdb_protocol/term.hpp"
#include "rpc/serialize_macros.hpp"

namespace ql {

class func_t : public single_threaded_shared_mixin_t<func_t>, public pb_rcheckable_t {
public:
    func_t(env_t *env, js::id_t id, counted_t<term_t> parent);
    func_t(env_t *env, protob_t<const Term> _source);
    // Some queries, like filter, can take a shortcut object instead of a
    // function as their argument.
    static counted_t<func_t> new_identity_func(env_t *env, counted_t<const datum_t> obj,
                                               const pb_rcheckable_t *root);
    counted_t<val_t> call(const std::vector<counted_t<const datum_t> > &args);

    // Prefer these versions of call.
    counted_t<val_t> call();
    counted_t<val_t> call(counted_t<const datum_t> arg);
    counted_t<val_t> call(counted_t<const datum_t> arg1, counted_t<const datum_t> arg2);
    bool filter_call(counted_t<const datum_t> arg);

    void dump_scope(std::map<int64_t, Datum> *out) const;
    bool is_deterministic() const;
    void assert_deterministic(const char *extra_msg) const;

private:
    // Pointers to this function's arguments.
    scoped_array_t<counted_t<const datum_t> > argptrs;
    counted_t<term_t> body; // body to evaluate with functions bound

    // This is what's serialized over the wire.
    friend class wire_func_t;
    protob_t<const Term> source;

    // TODO: make this smarter (it's sort of slow and shitty as-is)
    std::map<int64_t, counted_t<const datum_t> *> scope;

    counted_t<term_t> js_parent;
    env_t *js_env;
    js::id_t js_id;
};

class js_result_visitor_t : public boost::static_visitor<counted_t<val_t> > {
public:
    js_result_visitor_t(env_t *_env, counted_t<term_t> _parent) : env(_env), parent(_parent) { }

    // This JS evaluation resulted in an error
    counted_t<val_t> operator()(const std::string err_val) const;

    // This JS call resulted in a JSON value
    counted_t<val_t> operator()(const boost::shared_ptr<scoped_cJSON_t> json_val) const;

    // This JS evaluation resulted in an id for a js function
    counted_t<val_t> operator()(const id_t id_val) const;

private:
    env_t *env;
    counted_t<term_t> parent;
};

// Used to serialize a function (or gmr) over the wire.
class wire_func_t {
public:
    wire_func_t();
    wire_func_t(env_t *env, counted_t<func_t> _func);
    wire_func_t(const Term &_source, std::map<int64_t, Datum> *_scope);

    counted_t<func_t> compile(env_t *env);

    protob_t<const Backtrace> get_bt() const {
        return source.make_child(&source->GetExtension(ql2::extension::backtrace));
    }

    // Remove all callers of this function, returning a Term by value is absurd.
    Term get_term() const {
        return *source;
    }

    std::string debug_str() const {
        return source->DebugString();
    }

    // They're manually implemented because source is now a protob_t<Term>.
    void rdb_serialize(write_message_t &msg) const;  // NOLINT(runtime/references)
    archive_result_t rdb_deserialize(read_stream_t *stream);

private:
    // We cache a separate function for every environment.
    std::map<uuid_u, counted_t<func_t> > cached_funcs;

    // source is never null, even when wire_func_t is default-constructed.
    protob_t<Term> source;
    std::map<int64_t, Datum> scope;
};

// SAMRSI: Why does this now inherit from wire_func_t?  Make sure this isn't something stupid.
class map_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit map_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class filter_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit filter_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class reduce_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit reduce_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class concatmap_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit concatmap_wire_func_t(Args... args) : wire_func_t(args...) { }
};

// Count is a fake function because we don't need to send anything.
class count_wire_func_t {
public:
    RDB_MAKE_ME_SERIALIZABLE_0()
};

// Grouped Map Reduce
class gmr_wire_func_t {
public:
    gmr_wire_func_t() { }
    gmr_wire_func_t(env_t *env, counted_t<func_t> _group, counted_t<func_t> _map, counted_t<func_t> _reduce)
        : group(env, _group), map(env, _map), reduce(env, _reduce) { }
    counted_t<func_t> compile_group(env_t *env) { return group.compile(env); }
    counted_t<func_t> compile_map(env_t *env) { return map.compile(env); }
    counted_t<func_t> compile_reduce(env_t *env) { return reduce.compile(env); }

    protob_t<const Backtrace> get_bt() const {
        // If this goes wrong at the toplevel, it goes wrong in reduce.
        return reduce.get_bt();
    }

private:
    map_wire_func_t group;
    map_wire_func_t map;
    reduce_wire_func_t reduce;
public:
    RDB_MAKE_ME_SERIALIZABLE_3(group, map, reduce);
};

// Evaluating this returns a `func_t` wrapped in a `val_t`.
class func_term_t : public term_t {
public:
    func_term_t(env_t *env, protob_t<const Term> term);
private:
    virtual bool is_deterministic_impl() const;
    virtual counted_t<val_t> eval_impl();
    virtual const char *name() const { return "func"; }
    counted_t<func_t> func;
};

} // namespace ql
#endif // RDB_PROTOCOL_FUNC_HPP_
<commit_msg>Removed a whiny comment.<commit_after>#ifndef RDB_PROTOCOL_FUNC_HPP_
#define RDB_PROTOCOL_FUNC_HPP_

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "utils.hpp"

#include "containers/counted.hpp"
#include "protob/protob.hpp"
#include "rdb_protocol/js.hpp"
#include "rdb_protocol/term.hpp"
#include "rpc/serialize_macros.hpp"

namespace ql {

class func_t : public single_threaded_shared_mixin_t<func_t>, public pb_rcheckable_t {
public:
    func_t(env_t *env, js::id_t id, counted_t<term_t> parent);
    func_t(env_t *env, protob_t<const Term> _source);
    // Some queries, like filter, can take a shortcut object instead of a
    // function as their argument.
    static counted_t<func_t> new_identity_func(env_t *env, counted_t<const datum_t> obj,
                                               const pb_rcheckable_t *root);
    counted_t<val_t> call(const std::vector<counted_t<const datum_t> > &args);

    // Prefer these versions of call.
    counted_t<val_t> call();
    counted_t<val_t> call(counted_t<const datum_t> arg);
    counted_t<val_t> call(counted_t<const datum_t> arg1, counted_t<const datum_t> arg2);
    bool filter_call(counted_t<const datum_t> arg);

    void dump_scope(std::map<int64_t, Datum> *out) const;
    bool is_deterministic() const;
    void assert_deterministic(const char *extra_msg) const;

private:
    // Pointers to this function's arguments.
    scoped_array_t<counted_t<const datum_t> > argptrs;
    counted_t<term_t> body; // body to evaluate with functions bound

    // This is what's serialized over the wire.
    friend class wire_func_t;
    protob_t<const Term> source;

    // TODO: make this smarter (it's sort of slow and shitty as-is)
    std::map<int64_t, counted_t<const datum_t> *> scope;

    counted_t<term_t> js_parent;
    env_t *js_env;
    js::id_t js_id;
};

class js_result_visitor_t : public boost::static_visitor<counted_t<val_t> > {
public:
    js_result_visitor_t(env_t *_env, counted_t<term_t> _parent) : env(_env), parent(_parent) { }

    // This JS evaluation resulted in an error
    counted_t<val_t> operator()(const std::string err_val) const;

    // This JS call resulted in a JSON value
    counted_t<val_t> operator()(const boost::shared_ptr<scoped_cJSON_t> json_val) const;

    // This JS evaluation resulted in an id for a js function
    counted_t<val_t> operator()(const id_t id_val) const;

private:
    env_t *env;
    counted_t<term_t> parent;
};

// Used to serialize a function (or gmr) over the wire.
class wire_func_t {
public:
    wire_func_t();
    wire_func_t(env_t *env, counted_t<func_t> _func);
    wire_func_t(const Term &_source, std::map<int64_t, Datum> *_scope);

    counted_t<func_t> compile(env_t *env);

    protob_t<const Backtrace> get_bt() const {
        return source.make_child(&source->GetExtension(ql2::extension::backtrace));
    }

    Term get_term() const {
        return *source;
    }

    std::string debug_str() const {
        return source->DebugString();
    }

    // They're manually implemented because source is now a protob_t<Term>.
    void rdb_serialize(write_message_t &msg) const;  // NOLINT(runtime/references)
    archive_result_t rdb_deserialize(read_stream_t *stream);

private:
    // We cache a separate function for every environment.
    std::map<uuid_u, counted_t<func_t> > cached_funcs;

    // source is never null, even when wire_func_t is default-constructed.
    protob_t<Term> source;
    std::map<int64_t, Datum> scope;
};

// SAMRSI: Why does this now inherit from wire_func_t?  Make sure this isn't something stupid.
class map_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit map_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class filter_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit filter_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class reduce_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit reduce_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class concatmap_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    explicit concatmap_wire_func_t(Args... args) : wire_func_t(args...) { }
};

// Count is a fake function because we don't need to send anything.
class count_wire_func_t {
public:
    RDB_MAKE_ME_SERIALIZABLE_0()
};

// Grouped Map Reduce
class gmr_wire_func_t {
public:
    gmr_wire_func_t() { }
    gmr_wire_func_t(env_t *env, counted_t<func_t> _group, counted_t<func_t> _map, counted_t<func_t> _reduce)
        : group(env, _group), map(env, _map), reduce(env, _reduce) { }
    counted_t<func_t> compile_group(env_t *env) { return group.compile(env); }
    counted_t<func_t> compile_map(env_t *env) { return map.compile(env); }
    counted_t<func_t> compile_reduce(env_t *env) { return reduce.compile(env); }

    protob_t<const Backtrace> get_bt() const {
        // If this goes wrong at the toplevel, it goes wrong in reduce.
        return reduce.get_bt();
    }

private:
    map_wire_func_t group;
    map_wire_func_t map;
    reduce_wire_func_t reduce;
public:
    RDB_MAKE_ME_SERIALIZABLE_3(group, map, reduce);
};

// Evaluating this returns a `func_t` wrapped in a `val_t`.
class func_term_t : public term_t {
public:
    func_term_t(env_t *env, protob_t<const Term> term);
private:
    virtual bool is_deterministic_impl() const;
    virtual counted_t<val_t> eval_impl();
    virtual const char *name() const { return "func"; }
    counted_t<func_t> func;
};

} // namespace ql
#endif // RDB_PROTOCOL_FUNC_HPP_
<|endoftext|>