<commit_before>// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/overviewpage.h>
#include <qt/forms/ui_overviewpage.h>

#include <qt/bitcoinunits.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/transactionfilterproxy.h>
#include <qt/transactionoverviewwidget.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>

#include <QAbstractItemDelegate>
#include <QApplication>
#include <QPainter>
#include <QStatusTipEvent>

#include <algorithm>
#include <map>

#define DECORATION_SIZE 54
#define NUM_ITEMS 5

Q_DECLARE_METATYPE(interfaces::WalletBalances)

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
        QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
        platformStyle(_platformStyle)
    {
        connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged);
    }

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
                      const QModelIndex &index ) const override
    {
        painter->save();

        QIcon icon = qvariant_cast<QIcon>(index.data(TransactionTableModel::RawDecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
        int xspace = DECORATION_SIZE + 8;
        int ypad = 6;
        int halfheight = (mainRect.height() - 2*ypad)/2;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
        icon = platformStyle->SingleColorIcon(icon);
        icon.paint(painter, decorationRect);

        QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
        QString address = index.data(Qt::DisplayRole).toString();
        qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
        bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
        QVariant value = index.data(Qt::ForegroundRole);
        QColor foreground = option.palette.color(QPalette::Text);
        if(value.canConvert<QBrush>())
        {
            QBrush brush = qvariant_cast<QBrush>(value);
            foreground = brush.color();
        }

        painter->setPen(foreground);
        QRect boundingRect;
        painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect);

        if (index.data(TransactionTableModel::WatchonlyRole).toBool())
        {
            QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
            QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
            iconWatchonly.paint(painter, watchonlyRect);
        }

        if(amount < 0)
        {
            foreground = COLOR_NEGATIVE;
        }
        else if(!confirmed)
        {
            foreground = COLOR_UNCONFIRMED;
        }
        else
        {
            foreground = option.palette.color(QPalette::Text);
        }
        painter->setPen(foreground);
        QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::SeparatorStyle::ALWAYS);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }

        QRect amount_bounding_rect;
        painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText, &amount_bounding_rect);

        painter->setPen(option.palette.color(QPalette::Text));
        QRect date_bounding_rect;
        painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date), &date_bounding_rect);

        // 0.4*date_bounding_rect.width() is used to visually distinguish a date from an amount.
        const int minimum_width = 1.4 * date_bounding_rect.width() + amount_bounding_rect.width();
        const auto search = m_minimum_width.find(index.row());
        if (search == m_minimum_width.end() || search->second != minimum_width) {
            m_minimum_width[index.row()] = minimum_width;
            Q_EMIT width_changed(index);
        }

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        const auto search = m_minimum_width.find(index.row());
        const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second;
        return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE};
    }

    int unit;

Q_SIGNALS:
    //! An intermediate signal for emitting from the `paint() const` member function.
    void width_changed(const QModelIndex& index) const;

private:
    const PlatformStyle* platformStyle;
    mutable std::map<int, int> m_minimum_width;
};

#include <qt/overviewpage.moc>

OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    clientModel(nullptr),
    walletModel(nullptr),
    txdelegate(new TxViewDelegate(platformStyle, this))
{
    ui->setupUi(this);

    m_balances.balance = -1;

    // use a SingleColorIcon for the "out of sync warning" icon
    QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
    icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
    ui->labelTransactionsStatus->setIcon(icon);
    ui->labelWalletStatus->setIcon(icon);

    // Recent transactions
    ui->listTransactions->setItemDelegate(txdelegate);
    ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
    ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
    ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);

    connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked);

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
    connect(ui->labelWalletStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks);
    connect(ui->labelTransactionsStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks);
}

void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
    if(filter)
        Q_EMIT transactionClicked(filter->mapToSource(index));
}

void OverviewPage::handleOutOfSyncWarningClicks()
{
    Q_EMIT outOfSyncWarningClicked();
}

void OverviewPage::setPrivacy(bool privacy)
{
    m_privacy = privacy;
    if (m_balances.balance != -1) {
        setBalance(m_balances);
    }

    ui->listTransactions->setVisible(!m_privacy);

    const QString status_tip = m_privacy ? tr("Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.") : "";
    setStatusTip(status_tip);
    QStatusTipEvent event(status_tip);
    QApplication::sendEvent(this, &event);
}

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

void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
{
    int unit = walletModel->getOptionsModel()->getDisplayUnit();
    m_balances = balances;
    if (walletModel->wallet().isLegacy()) {
        if (walletModel->wallet().privateKeysDisabled()) {
            ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        } else {
            ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchAvailable->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchPending->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        }
    } else {
        ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
    }
    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = balances.immature_balance != 0;
    bool showWatchOnlyImmature = balances.immature_watch_only_balance != 0;

    // for symmetry reasons also show immature label when the watch-only one is shown
    ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
    ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
    ui->labelWatchImmature->setVisible(!walletModel->wallet().privateKeysDisabled() && showWatchOnlyImmature); // show watch-only immature balance
}

// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
{
    ui->labelSpendable->setVisible(showWatchOnly);      // show spendable label (only when watch-only is active)
    ui->labelWatchonly->setVisible(showWatchOnly);      // show watch-only label
    ui->lineWatchBalance->setVisible(showWatchOnly);    // show watch-only balance separator line
    ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance
    ui->labelWatchPending->setVisible(showWatchOnly);   // show watch-only pending balance
    ui->labelWatchTotal->setVisible(showWatchOnly);     // show watch-only total balance

    if (!showWatchOnly)
        ui->labelWatchImmature->hide();
}

void OverviewPage::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if (model) {
        // Show warning, for example if this is a prerelease version
        connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts);
        updateAlerts(model->getStatusBarWarnings());
    }
}

void OverviewPage::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter.reset(new TransactionFilterProxy());
        filter->setSourceModel(model->getTransactionTableModel());
        filter->setLimit(NUM_ITEMS);
        filter->setDynamicSortFilter(true);
        filter->setSortRole(Qt::EditRole);
        filter->setShowInactive(false);
        filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);

        ui->listTransactions->setModel(filter.get());
        ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        interfaces::Wallet& wallet = model->wallet();
        interfaces::WalletBalances balances = wallet.getBalances();
        setBalance(balances);
        connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance);

        connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit);

        updateWatchOnlyLabels(wallet.haveWatchOnly() && !model->wallet().privateKeysDisabled());
        connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) {
            updateWatchOnlyLabels(showWatchOnly && !walletModel->wallet().privateKeysDisabled());
        });
    }

    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void OverviewPage::updateDisplayUnit()
{
    if(walletModel && walletModel->getOptionsModel())
    {
        if (m_balances.balance != -1) {
            setBalance(m_balances);
        }

        // Update txdelegate->unit with the current unit
        txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();

        ui->listTransactions->update();
    }
}

void OverviewPage::updateAlerts(const QString &warnings)
{
    this->ui->labelAlerts->setVisible(!warnings.isEmpty());
    this->ui->labelAlerts->setText(warnings);
}

void OverviewPage::showOutOfSyncWarning(bool fShow)
{
    ui->labelWalletStatus->setVisible(fShow);
    ui->labelTransactionsStatus->setVisible(fShow);
}
<commit_msg>qt: Draw "eye" sign at the beginning of watch-only addresses<commit_after>// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/overviewpage.h>
#include <qt/forms/ui_overviewpage.h>

#include <qt/bitcoinunits.h>
#include <qt/clientmodel.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/transactionfilterproxy.h>
#include <qt/transactionoverviewwidget.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>

#include <QAbstractItemDelegate>
#include <QApplication>
#include <QPainter>
#include <QStatusTipEvent>

#include <algorithm>
#include <map>

#define DECORATION_SIZE 54
#define NUM_ITEMS 5

Q_DECLARE_METATYPE(interfaces::WalletBalances)

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
        QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
        platformStyle(_platformStyle)
    {
        connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged);
    }

    inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
                      const QModelIndex &index ) const override
    {
        painter->save();

        QIcon icon = qvariant_cast<QIcon>(index.data(TransactionTableModel::RawDecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
        int xspace = DECORATION_SIZE + 8;
        int ypad = 6;
        int halfheight = (mainRect.height() - 2*ypad)/2;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
        icon = platformStyle->SingleColorIcon(icon);
        icon.paint(painter, decorationRect);

        QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
        QString address = index.data(Qt::DisplayRole).toString();
        qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
        bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
        QVariant value = index.data(Qt::ForegroundRole);
        QColor foreground = option.palette.color(QPalette::Text);
        if(value.canConvert<QBrush>())
        {
            QBrush brush = qvariant_cast<QBrush>(value);
            foreground = brush.color();
        }

        if (index.data(TransactionTableModel::WatchonlyRole).toBool()) {
            QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
            QRect watchonlyRect(addressRect.left(), addressRect.top(), 16, addressRect.height());
            iconWatchonly.paint(painter, watchonlyRect);
            addressRect.setLeft(addressRect.left() + watchonlyRect.width() + 5);
        }

        painter->setPen(foreground);
        QRect boundingRect;
        painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect);

        if(amount < 0)
        {
            foreground = COLOR_NEGATIVE;
        }
        else if(!confirmed)
        {
            foreground = COLOR_UNCONFIRMED;
        }
        else
        {
            foreground = option.palette.color(QPalette::Text);
        }
        painter->setPen(foreground);
        QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::SeparatorStyle::ALWAYS);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }

        QRect amount_bounding_rect;
        painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText, &amount_bounding_rect);

        painter->setPen(option.palette.color(QPalette::Text));
        QRect date_bounding_rect;
        painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date), &date_bounding_rect);

        // 0.4*date_bounding_rect.width() is used to visually distinguish a date from an amount.
        const int minimum_width = 1.4 * date_bounding_rect.width() + amount_bounding_rect.width();
        const auto search = m_minimum_width.find(index.row());
        if (search == m_minimum_width.end() || search->second != minimum_width) {
            m_minimum_width[index.row()] = minimum_width;
            Q_EMIT width_changed(index);
        }

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        const auto search = m_minimum_width.find(index.row());
        const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second;
        return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE};
    }

    int unit;

Q_SIGNALS:
    //! An intermediate signal for emitting from the `paint() const` member function.
    void width_changed(const QModelIndex& index) const;

private:
    const PlatformStyle* platformStyle;
    mutable std::map<int, int> m_minimum_width;
};

#include <qt/overviewpage.moc>

OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    clientModel(nullptr),
    walletModel(nullptr),
    txdelegate(new TxViewDelegate(platformStyle, this))
{
    ui->setupUi(this);

    m_balances.balance = -1;

    // use a SingleColorIcon for the "out of sync warning" icon
    QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
    icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
    ui->labelTransactionsStatus->setIcon(icon);
    ui->labelWalletStatus->setIcon(icon);

    // Recent transactions
    ui->listTransactions->setItemDelegate(txdelegate);
    ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
    ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
    ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);

    connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked);

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
    connect(ui->labelWalletStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks);
    connect(ui->labelTransactionsStatus, &QPushButton::clicked, this, &OverviewPage::handleOutOfSyncWarningClicks);
}

void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
    if(filter)
        Q_EMIT transactionClicked(filter->mapToSource(index));
}

void OverviewPage::handleOutOfSyncWarningClicks()
{
    Q_EMIT outOfSyncWarningClicked();
}

void OverviewPage::setPrivacy(bool privacy)
{
    m_privacy = privacy;
    if (m_balances.balance != -1) {
        setBalance(m_balances);
    }

    ui->listTransactions->setVisible(!m_privacy);

    const QString status_tip = m_privacy ? tr("Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.") : "";
    setStatusTip(status_tip);
    QStatusTipEvent event(status_tip);
    QApplication::sendEvent(this, &event);
}

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

void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
{
    int unit = walletModel->getOptionsModel()->getDisplayUnit();
    m_balances = balances;
    if (walletModel->wallet().isLegacy()) {
        if (walletModel->wallet().privateKeysDisabled()) {
            ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        } else {
            ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchAvailable->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchPending->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
            ui->labelWatchTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        }
    } else {
        ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
        ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
    }
    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = balances.immature_balance != 0;
    bool showWatchOnlyImmature = balances.immature_watch_only_balance != 0;

    // for symmetry reasons also show immature label when the watch-only one is shown
    ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
    ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
    ui->labelWatchImmature->setVisible(!walletModel->wallet().privateKeysDisabled() && showWatchOnlyImmature); // show watch-only immature balance
}

// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
{
    ui->labelSpendable->setVisible(showWatchOnly);      // show spendable label (only when watch-only is active)
    ui->labelWatchonly->setVisible(showWatchOnly);      // show watch-only label
    ui->lineWatchBalance->setVisible(showWatchOnly);    // show watch-only balance separator line
    ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance
    ui->labelWatchPending->setVisible(showWatchOnly);   // show watch-only pending balance
    ui->labelWatchTotal->setVisible(showWatchOnly);     // show watch-only total balance

    if (!showWatchOnly)
        ui->labelWatchImmature->hide();
}

void OverviewPage::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if (model) {
        // Show warning, for example if this is a prerelease version
        connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts);
        updateAlerts(model->getStatusBarWarnings());
    }
}

void OverviewPage::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter.reset(new TransactionFilterProxy());
        filter->setSourceModel(model->getTransactionTableModel());
        filter->setLimit(NUM_ITEMS);
        filter->setDynamicSortFilter(true);
        filter->setSortRole(Qt::EditRole);
        filter->setShowInactive(false);
        filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);

        ui->listTransactions->setModel(filter.get());
        ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        interfaces::Wallet& wallet = model->wallet();
        interfaces::WalletBalances balances = wallet.getBalances();
        setBalance(balances);
        connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance);

        connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit);

        updateWatchOnlyLabels(wallet.haveWatchOnly() && !model->wallet().privateKeysDisabled());
        connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) {
            updateWatchOnlyLabels(showWatchOnly && !walletModel->wallet().privateKeysDisabled());
        });
    }

    // update the display unit, to not use the default ("BTC")
    updateDisplayUnit();
}

void OverviewPage::updateDisplayUnit()
{
    if(walletModel && walletModel->getOptionsModel())
    {
        if (m_balances.balance != -1) {
            setBalance(m_balances);
        }

        // Update txdelegate->unit with the current unit
        txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();

        ui->listTransactions->update();
    }
}

void OverviewPage::updateAlerts(const QString &warnings)
{
    this->ui->labelAlerts->setVisible(!warnings.isEmpty());
    this->ui->labelAlerts->setText(warnings);
}

void OverviewPage::showOutOfSyncWarning(bool fShow)
{
    ui->labelWalletStatus->setVisible(fShow);
    ui->labelTransactionsStatus->setVisible(fShow);
}
<|endoftext|>


<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "rdb_protocol/env.hpp"

#include "rdb_protocol/counted_term.hpp"
#include "rdb_protocol/func.hpp"
#include "rdb_protocol/pb_utils.hpp"
#include "rdb_protocol/term_walker.hpp"
#include "extproc/js_runner.hpp"

#pragma GCC diagnostic ignored "-Wshadow"

namespace ql {

/* Checks that divisor is indeed a divisor of multiple. */
template <class T>
bool is_joined(const T &multiple, const T &divisor) {
    T cpy = multiple;

    semilattice_join(&cpy, divisor);
    return cpy == multiple;
}

func_cache_t::func_cache_t() { }

counted_t<func_t> func_cache_t::get_or_compile_func(env_t *env, const wire_func_t *wf) {
    env->assert_thread();
    auto it = cached_funcs.find(wf->uuid);
    if (it == cached_funcs.end()) {
        env->scopes.push_scope(&wf->scope);
        try {
            it = cached_funcs.insert(
                std::make_pair(
                    wf->uuid, compile_term(env, wf->source)->eval(env)->as_func(env))).first;
        } catch (const base_exc_t &e) {
            // If we have a non-`base_exc_t` exception, we don't want to pop the
            // scope because we might have corruption, and we might fail a check
            // and try to throw again while this exception is on the stack.  (We
            // only need to pop the scope for a `base_exc_t` exception because
            // that's the only kind of exception that we might recover from in
            // the ReQL layer, which is the only case where the un-popped scope
            // might matter.)
            // RSI: ^^^^ This is retarded, don't do this.
            env->scopes.pop_scope();
            throw;
        }
        env->scopes.pop_scope();
    }
    return it->second;
}

void func_cache_t::precache_func(const wire_func_t *wf, counted_t<func_t> func) {
    cached_funcs[wf->uuid] = func;
}

global_optargs_t::global_optargs_t() { }

global_optargs_t::global_optargs_t(const std::map<std::string, wire_func_t> &_optargs)
    : optargs(_optargs) { }

bool global_optargs_t::add_optarg(env_t *env, const std::string &key, const Term &val) {
    if (optargs.count(key)) {
        return true;
    }
    protob_t<Term> arg = make_counted_term();
    N2(FUNC, N0(MAKE_ARRAY), *arg = val);
    propagate_backtrace(arg.get(), &val.GetExtension(ql2::extension::backtrace));
    optargs[key] = wire_func_t(*arg, std::map<sym_t, Datum>());
    counted_t<func_t> force_compilation = optargs[key].compile(env);
    r_sanity_check(force_compilation.has());
    return false;
}

void global_optargs_t::init_optargs(env_t *env, const std::map<std::string, wire_func_t> &_optargs) {
    r_sanity_check(optargs.size() == 0);
    optargs = _optargs;
    for (auto it = optargs.begin(); it != optargs.end(); ++it) {
        counted_t<func_t> force_compilation = it->second.compile(env);
        r_sanity_check(force_compilation.has());
    }
}
counted_t<val_t> global_optargs_t::get_optarg(env_t *env, const std::string &key){
    if (!optargs.count(key)) {
        return counted_t<val_t>();
    }
    return optargs[key].compile(env)->call();
}
const std::map<std::string, wire_func_t> &global_optargs_t::get_all_optargs() {
    return optargs;
}

static const int min_normal_gensym = -1000000;
sym_t gensym_t::gensym(bool allow_implicit) {
    r_sanity_check(0 > next_gensym_val && next_gensym_val >= min_normal_gensym);
    int64_t ret = next_gensym_val--;
    if (!allow_implicit) {
        ret += min_normal_gensym;
        r_sanity_check(ret < min_normal_gensym);
    }
    return sym_t(ret);
}

bool gensym_t::var_allows_implicit(sym_t varnum) {
    return varnum.value >= min_normal_gensym;
}

implicit_vars_t::implicit_vars_t() { }

void implicit_vars_t::push_implicit(counted_t<const datum_t> *val) {
    implicit_var.push(val);
}
counted_t<const datum_t> *implicit_vars_t::top_implicit(const rcheckable_t *caller) {
    rcheck_target(caller, base_exc_t::GENERIC, !implicit_var.empty(),
                  "r.row is not defined in this context.");
    rcheck_target(caller, base_exc_t::GENERIC, implicit_var.size() == 1,
                  "Cannot use r.row in nested queries.  Use functions instead.");
    return implicit_var.top();
}
void implicit_vars_t::pop_implicit() {
    r_sanity_check(implicit_var.size() > 0);
    implicit_var.pop();
}

scopes_t::scopes_t() { }

void scopes_t::push_var(sym_t var, counted_t<const datum_t> *val) {
    vars[var].push(val);
}

static counted_t<const datum_t> sindex_error_dummy_datum;
// RSI: This is probably terrible ^^^.
void scopes_t::push_special_var(sym_t var, special_var_t special_var) {
    switch (special_var) {
    case SINDEX_ERROR_VAR: {
        vars[var].push(&sindex_error_dummy_datum);
    } break;
    default: unreachable();
    }
}

scopes_t::special_var_shadower_t::special_var_shadower_t(
    scopes_t *scopes, special_var_t special_var) : shadow_scopes(scopes) {
    shadow_scopes->dump_scope(&current_scope);
    for (auto it = current_scope.begin(); it != current_scope.end(); ++it) {
        shadow_scopes->push_special_var(it->first, special_var);
    }
}

scopes_t::special_var_shadower_t::~special_var_shadower_t() {
    for (auto it = current_scope.begin(); it != current_scope.end(); ++it) {
        shadow_scopes->pop_var(it->first);
    }
}

counted_t<const datum_t> *scopes_t::top_var(sym_t var, const rcheckable_t *caller) {
    rcheck_target(caller, base_exc_t::GENERIC, !vars[var].empty(),
                  strprintf("Unrecognized variabled %" PRIi64, var.value));
    counted_t<const datum_t> *var_val = vars[var].top();
    rcheck_target(caller, base_exc_t::GENERIC,
                  var_val != &sindex_error_dummy_datum,
                  "Cannot reference external variables from inside an index.");
    return var_val;
}
void scopes_t::pop_var(sym_t var) {
    vars[var].pop();
}
void scopes_t::dump_scope(std::map<sym_t, counted_t<const datum_t> *> *out) {
    for (auto it = vars.begin(); it != vars.end(); ++it) {
        if (!it->second.empty()) {
            r_sanity_check(it->second.top());
            (*out)[it->first] = it->second.top();
        }
    }
}
void scopes_t::push_scope(const std::map<sym_t, Datum> *in) {
    scope_stack.push(std::vector<std::pair<sym_t, counted_t<const datum_t> > >());

    for (auto it = in->begin(); it != in->end(); ++it) {
        scope_stack.top().push_back(
            std::make_pair(it->first, make_counted<datum_t>(&it->second)));
    }

    for (size_t i = 0; i < scope_stack.top().size(); ++i) {
        push_var(scope_stack.top()[i].first, &scope_stack.top()[i].second);
    }
}
void scopes_t::pop_scope() {
    r_sanity_check(scope_stack.size() > 0);
    for (size_t i = 0; i < scope_stack.top().size(); ++i) {
        pop_var(scope_stack.top()[i].first);
    }
    // DO NOT pop the vector off the scope stack.  You might invalidate a
    // pointer too early.
    // RSI: ^^^ Pointers into a vector???
}

void env_t::set_eval_callback(eval_callback_t *callback) {
    eval_callback = callback;
}

void env_t::do_eval_callback() {
    if (eval_callback != NULL) {
        eval_callback->eval_callback();
    }
}

cluster_env_t::cluster_env_t(
        base_namespace_repo_t<rdb_protocol_t> *_ns_repo,

        clone_ptr_t<watchable_t<cow_ptr_t<ns_metadata_t> > >
            _namespaces_semilattice_metadata,

        clone_ptr_t<watchable_t<databases_semilattice_metadata_t> >
             _databases_semilattice_metadata,
        boost::shared_ptr<semilattice_readwrite_view_t<cluster_semilattice_metadata_t> >
            _semilattice_metadata,
        directory_read_manager_t<cluster_directory_metadata_t> *_directory_read_manager)
    : ns_repo(_ns_repo),
      namespaces_semilattice_metadata(_namespaces_semilattice_metadata),
      databases_semilattice_metadata(_databases_semilattice_metadata),
      semilattice_metadata(_semilattice_metadata),
      directory_read_manager(_directory_read_manager) { }

void cluster_env_t::join_and_wait_to_propagate(
        const cluster_semilattice_metadata_t &metadata_to_join,
        signal_t *interruptor)
    THROWS_ONLY(interrupted_exc_t) {
    cluster_semilattice_metadata_t sl_metadata;
    {
        on_thread_t switcher(semilattice_metadata->home_thread());
        semilattice_metadata->join(metadata_to_join);
        sl_metadata = semilattice_metadata->get();
    }

    boost::function<bool (const cow_ptr_t<ns_metadata_t> s)> p = boost::bind(
        &is_joined<cow_ptr_t<ns_metadata_t > >,
        _1,
        sl_metadata.rdb_namespaces
    );

    {
        on_thread_t switcher(namespaces_semilattice_metadata->home_thread());
        namespaces_semilattice_metadata->run_until_satisfied(p,
                                                             interruptor);
        databases_semilattice_metadata->run_until_satisfied(
            boost::bind(&is_joined<databases_semilattice_metadata_t>,
                        _1,
                        sl_metadata.databases),
            interruptor);
    }
}

js_runner_t *env_t::get_js_runner() {
    assert_thread();
    r_sanity_check(extproc_pool != NULL);
    if (!js_runner.connected()) {
        js_runner.begin(extproc_pool, interruptor);
    }
    return &js_runner;
}

env_t::env_t(
    extproc_pool_t *_extproc_pool,
    base_namespace_repo_t<rdb_protocol_t> *_ns_repo,

    clone_ptr_t<watchable_t<cow_ptr_t<ns_metadata_t> > >
    _namespaces_semilattice_metadata,

    clone_ptr_t<watchable_t<databases_semilattice_metadata_t> >
    _databases_semilattice_metadata,
    boost::shared_ptr<semilattice_readwrite_view_t<cluster_semilattice_metadata_t> >
    _semilattice_metadata,
    directory_read_manager_t<cluster_directory_metadata_t> *_directory_read_manager,
    signal_t *_interruptor,
    uuid_u _this_machine,
    const std::map<std::string, wire_func_t> &_optargs)
  : global_optargs(_optargs),
    extproc_pool(_extproc_pool),
    cluster_env(_ns_repo,
                _namespaces_semilattice_metadata,
                _databases_semilattice_metadata,
                _semilattice_metadata,
                _directory_read_manager),
    DEBUG_ONLY(eval_callback(NULL), )
    interruptor(_interruptor),
    this_machine(_this_machine) { }

// RSI: Do we really want people calling this constructor?
env_t::env_t(signal_t *_interruptor)
  : extproc_pool(NULL),
    cluster_env(NULL,
                clone_ptr_t<watchable_t<cow_ptr_t<ns_metadata_t> > >(),
                clone_ptr_t<watchable_t<databases_semilattice_metadata_t> >(),
                boost::shared_ptr<semilattice_readwrite_view_t<cluster_semilattice_metadata_t> >(),
                NULL),
    DEBUG_ONLY(eval_callback(NULL), )
    interruptor(_interruptor) { }

env_t::~env_t() { }

} // namespace ql
<commit_msg>Added important RSI comment about whether the scope_stack is a stack.<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "rdb_protocol/env.hpp"

#include "rdb_protocol/counted_term.hpp"
#include "rdb_protocol/func.hpp"
#include "rdb_protocol/pb_utils.hpp"
#include "rdb_protocol/term_walker.hpp"
#include "extproc/js_runner.hpp"

#pragma GCC diagnostic ignored "-Wshadow"

namespace ql {

/* Checks that divisor is indeed a divisor of multiple. */
template <class T>
bool is_joined(const T &multiple, const T &divisor) {
    T cpy = multiple;

    semilattice_join(&cpy, divisor);
    return cpy == multiple;
}

func_cache_t::func_cache_t() { }

counted_t<func_t> func_cache_t::get_or_compile_func(env_t *env, const wire_func_t *wf) {
    env->assert_thread();
    auto it = cached_funcs.find(wf->uuid);
    if (it == cached_funcs.end()) {
        env->scopes.push_scope(&wf->scope);
        try {
            it = cached_funcs.insert(
                std::make_pair(
                    wf->uuid, compile_term(env, wf->source)->eval(env)->as_func(env))).first;
        } catch (const base_exc_t &e) {
            // If we have a non-`base_exc_t` exception, we don't want to pop the
            // scope because we might have corruption, and we might fail a check
            // and try to throw again while this exception is on the stack.  (We
            // only need to pop the scope for a `base_exc_t` exception because
            // that's the only kind of exception that we might recover from in
            // the ReQL layer, which is the only case where the un-popped scope
            // might matter.)
            // RSI: ^^^^ This is retarded, don't do this.
            env->scopes.pop_scope();
            throw;
        }
        env->scopes.pop_scope();
    }
    return it->second;
}

void func_cache_t::precache_func(const wire_func_t *wf, counted_t<func_t> func) {
    cached_funcs[wf->uuid] = func;
}

global_optargs_t::global_optargs_t() { }

global_optargs_t::global_optargs_t(const std::map<std::string, wire_func_t> &_optargs)
    : optargs(_optargs) { }

bool global_optargs_t::add_optarg(env_t *env, const std::string &key, const Term &val) {
    if (optargs.count(key)) {
        return true;
    }
    protob_t<Term> arg = make_counted_term();
    N2(FUNC, N0(MAKE_ARRAY), *arg = val);
    propagate_backtrace(arg.get(), &val.GetExtension(ql2::extension::backtrace));
    optargs[key] = wire_func_t(*arg, std::map<sym_t, Datum>());
    counted_t<func_t> force_compilation = optargs[key].compile(env);
    r_sanity_check(force_compilation.has());
    return false;
}

void global_optargs_t::init_optargs(env_t *env, const std::map<std::string, wire_func_t> &_optargs) {
    r_sanity_check(optargs.size() == 0);
    optargs = _optargs;
    for (auto it = optargs.begin(); it != optargs.end(); ++it) {
        counted_t<func_t> force_compilation = it->second.compile(env);
        r_sanity_check(force_compilation.has());
    }
}
counted_t<val_t> global_optargs_t::get_optarg(env_t *env, const std::string &key){
    if (!optargs.count(key)) {
        return counted_t<val_t>();
    }
    return optargs[key].compile(env)->call();
}
const std::map<std::string, wire_func_t> &global_optargs_t::get_all_optargs() {
    return optargs;
}

static const int min_normal_gensym = -1000000;
sym_t gensym_t::gensym(bool allow_implicit) {
    r_sanity_check(0 > next_gensym_val && next_gensym_val >= min_normal_gensym);
    int64_t ret = next_gensym_val--;
    if (!allow_implicit) {
        ret += min_normal_gensym;
        r_sanity_check(ret < min_normal_gensym);
    }
    return sym_t(ret);
}

bool gensym_t::var_allows_implicit(sym_t varnum) {
    return varnum.value >= min_normal_gensym;
}

implicit_vars_t::implicit_vars_t() { }

void implicit_vars_t::push_implicit(counted_t<const datum_t> *val) {
    implicit_var.push(val);
}
counted_t<const datum_t> *implicit_vars_t::top_implicit(const rcheckable_t *caller) {
    rcheck_target(caller, base_exc_t::GENERIC, !implicit_var.empty(),
                  "r.row is not defined in this context.");
    rcheck_target(caller, base_exc_t::GENERIC, implicit_var.size() == 1,
                  "Cannot use r.row in nested queries.  Use functions instead.");
    return implicit_var.top();
}
void implicit_vars_t::pop_implicit() {
    r_sanity_check(implicit_var.size() > 0);
    implicit_var.pop();
}

scopes_t::scopes_t() { }

void scopes_t::push_var(sym_t var, counted_t<const datum_t> *val) {
    vars[var].push(val);
}

static counted_t<const datum_t> sindex_error_dummy_datum;
// RSI: This is probably terrible ^^^.
void scopes_t::push_special_var(sym_t var, special_var_t special_var) {
    switch (special_var) {
    case SINDEX_ERROR_VAR: {
        vars[var].push(&sindex_error_dummy_datum);
    } break;
    default: unreachable();
    }
}

scopes_t::special_var_shadower_t::special_var_shadower_t(
    scopes_t *scopes, special_var_t special_var) : shadow_scopes(scopes) {
    shadow_scopes->dump_scope(&current_scope);
    for (auto it = current_scope.begin(); it != current_scope.end(); ++it) {
        shadow_scopes->push_special_var(it->first, special_var);
    }
}

scopes_t::special_var_shadower_t::~special_var_shadower_t() {
    for (auto it = current_scope.begin(); it != current_scope.end(); ++it) {
        shadow_scopes->pop_var(it->first);
    }
}

counted_t<const datum_t> *scopes_t::top_var(sym_t var, const rcheckable_t *caller) {
    rcheck_target(caller, base_exc_t::GENERIC, !vars[var].empty(),
                  strprintf("Unrecognized variabled %" PRIi64, var.value));
    counted_t<const datum_t> *var_val = vars[var].top();
    rcheck_target(caller, base_exc_t::GENERIC,
                  var_val != &sindex_error_dummy_datum,
                  "Cannot reference external variables from inside an index.");
    return var_val;
}
void scopes_t::pop_var(sym_t var) {
    vars[var].pop();
}
void scopes_t::dump_scope(std::map<sym_t, counted_t<const datum_t> *> *out) {
    for (auto it = vars.begin(); it != vars.end(); ++it) {
        if (!it->second.empty()) {
            r_sanity_check(it->second.top());
            (*out)[it->first] = it->second.top();
        }
    }
}
void scopes_t::push_scope(const std::map<sym_t, Datum> *in) {
    scope_stack.push(std::vector<std::pair<sym_t, counted_t<const datum_t> > >());

    for (auto it = in->begin(); it != in->end(); ++it) {
        scope_stack.top().push_back(
            std::make_pair(it->first, make_counted<datum_t>(&it->second)));
    }

    for (size_t i = 0; i < scope_stack.top().size(); ++i) {
        push_var(scope_stack.top()[i].first, &scope_stack.top()[i].second);
    }
}
void scopes_t::pop_scope() {
    r_sanity_check(scope_stack.size() > 0);
    for (size_t i = 0; i < scope_stack.top().size(); ++i) {
        pop_var(scope_stack.top()[i].first);
    }
    // DO NOT pop the vector off the scope stack.  You might invalidate a
    // pointer too early.
    // RSI: ^^^ Pointers into a vector???
    // RSI: This ain't no stack.
}

void env_t::set_eval_callback(eval_callback_t *callback) {
    eval_callback = callback;
}

void env_t::do_eval_callback() {
    if (eval_callback != NULL) {
        eval_callback->eval_callback();
    }
}

cluster_env_t::cluster_env_t(
        base_namespace_repo_t<rdb_protocol_t> *_ns_repo,

        clone_ptr_t<watchable_t<cow_ptr_t<ns_metadata_t> > >
            _namespaces_semilattice_metadata,

        clone_ptr_t<watchable_t<databases_semilattice_metadata_t> >
             _databases_semilattice_metadata,
        boost::shared_ptr<semilattice_readwrite_view_t<cluster_semilattice_metadata_t> >
            _semilattice_metadata,
        directory_read_manager_t<cluster_directory_metadata_t> *_directory_read_manager)
    : ns_repo(_ns_repo),
      namespaces_semilattice_metadata(_namespaces_semilattice_metadata),
      databases_semilattice_metadata(_databases_semilattice_metadata),
      semilattice_metadata(_semilattice_metadata),
      directory_read_manager(_directory_read_manager) { }

void cluster_env_t::join_and_wait_to_propagate(
        const cluster_semilattice_metadata_t &metadata_to_join,
        signal_t *interruptor)
    THROWS_ONLY(interrupted_exc_t) {
    cluster_semilattice_metadata_t sl_metadata;
    {
        on_thread_t switcher(semilattice_metadata->home_thread());
        semilattice_metadata->join(metadata_to_join);
        sl_metadata = semilattice_metadata->get();
    }

    boost::function<bool (const cow_ptr_t<ns_metadata_t> s)> p = boost::bind(
        &is_joined<cow_ptr_t<ns_metadata_t > >,
        _1,
        sl_metadata.rdb_namespaces
    );

    {
        on_thread_t switcher(namespaces_semilattice_metadata->home_thread());
        namespaces_semilattice_metadata->run_until_satisfied(p,
                                                             interruptor);
        databases_semilattice_metadata->run_until_satisfied(
            boost::bind(&is_joined<databases_semilattice_metadata_t>,
                        _1,
                        sl_metadata.databases),
            interruptor);
    }
}

js_runner_t *env_t::get_js_runner() {
    assert_thread();
    r_sanity_check(extproc_pool != NULL);
    if (!js_runner.connected()) {
        js_runner.begin(extproc_pool, interruptor);
    }
    return &js_runner;
}

env_t::env_t(
    extproc_pool_t *_extproc_pool,
    base_namespace_repo_t<rdb_protocol_t> *_ns_repo,

    clone_ptr_t<watchable_t<cow_ptr_t<ns_metadata_t> > >
    _namespaces_semilattice_metadata,

    clone_ptr_t<watchable_t<databases_semilattice_metadata_t> >
    _databases_semilattice_metadata,
    boost::shared_ptr<semilattice_readwrite_view_t<cluster_semilattice_metadata_t> >
    _semilattice_metadata,
    directory_read_manager_t<cluster_directory_metadata_t> *_directory_read_manager,
    signal_t *_interruptor,
    uuid_u _this_machine,
    const std::map<std::string, wire_func_t> &_optargs)
  : global_optargs(_optargs),
    extproc_pool(_extproc_pool),
    cluster_env(_ns_repo,
                _namespaces_semilattice_metadata,
                _databases_semilattice_metadata,
                _semilattice_metadata,
                _directory_read_manager),
    DEBUG_ONLY(eval_callback(NULL), )
    interruptor(_interruptor),
    this_machine(_this_machine) { }

// RSI: Do we really want people calling this constructor?
env_t::env_t(signal_t *_interruptor)
  : extproc_pool(NULL),
    cluster_env(NULL,
                clone_ptr_t<watchable_t<cow_ptr_t<ns_metadata_t> > >(),
                clone_ptr_t<watchable_t<databases_semilattice_metadata_t> >(),
                boost::shared_ptr<semilattice_readwrite_view_t<cluster_semilattice_metadata_t> >(),
                NULL),
    DEBUG_ONLY(eval_callback(NULL), )
    interruptor(_interruptor) { }

env_t::~env_t() { }

} // namespace ql
<|endoftext|>


<commit_before>/*
Copyright 2014-2015 Adam Grandquist

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.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#ifndef REQL_REQL_CONNECTION_HPP_
#define REQL_REQL_CONNECTION_HPP_

#include "./reql/pipe.hpp"
#include "./reql/query.hpp"
#include "./reql/stream.hpp"
#include "./reql/types.hpp"

#include <atomic>
#include <map>
#include <mutex>
#include <thread>

#ifdef __MINGW32__
#include <stdint.h>
#include <io.h>

typedef unsigned __LONG32 ULONG;
typedef short SHORT;
typedef unsigned char UCHAR;

#include <nettypes.h>
#include <netprov.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#endif

namespace _ReQL {

static const ReQL_Size VERSION = 0x400c2d20;
static const ReQL_Size PROTOCOL = 0x7e6970c7;

template <class byte_t>
ReQL_Size
get_size(const byte_t *buf) {
  return (static_cast<ReQL_Size>(buf[0])<<0) | (static_cast<ReQL_Size>(buf[1])<<8) | (static_cast<ReQL_Size>(buf[2])<<16) | (static_cast<ReQL_Size>(buf[3])<<24);
}

template <class byte_t>
void
make_size(byte_t *buf, const ReQL_Size magic) {
  buf[0] = (magic >> 0) & 0xFF;
  buf[1] = (magic >> 8) & 0xFF;
  buf[2] = (magic >> 16) & 0xFF;
  buf[3] = (magic >> 24) & 0xFF;
}

template <class byte_t>
void
make_token(byte_t *buf, const ReQL_Token magic) {
  buf[0] = (magic >> 0) & 0xFF;
  buf[1] = (magic >> 8) & 0xFF;
  buf[2] = (magic >> 16) & 0xFF;
  buf[3] = (magic >> 24) & 0xFF;
  buf[4] = (magic >> 32) & 0xFF;
  buf[5] = (magic >> 40) & 0xFF;
  buf[6] = (magic >> 48) & 0xFF;
  buf[7] = (magic >> 56) & 0xFF;
}

template <class byte_t>
ReQL_Token
get_token(const byte_t *buf) {
  return (static_cast<ReQL_Token>(buf[0])<<0) | (static_cast<ReQL_Token>(buf[1])<<8) | (static_cast<ReQL_Token>(buf[2])<<16) | (static_cast<ReQL_Token>(buf[3])<<24) | (static_cast<ReQL_Token>(buf[4])<<32) | (static_cast<ReQL_Token>(buf[5])<<40) | (static_cast<ReQL_Token>(buf[6])<<48) | (static_cast<ReQL_Token>(buf[7])<<56);
}

template <class sock_t>
class Socket_t {
public:
  Socket_t() : p_sock(-1) {}

  template <class str_t>
  Socket_t(str_t &addr, str_t &port) : p_sock(-1) {
    struct addrinfo hints;
    struct addrinfo *result, *rp;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = IPPROTO_TCP;

    if (getaddrinfo(addr.c_str(), port.c_str(), &hints, &result) != 0) {
      throw;
    }

    sock_t sock = -1;

    for (rp = result; rp != nullptr; rp = rp->ai_next) {
      sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);

      if (sock == -1) continue;

      if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;

      ::close(sock);
    }

    if (rp == nullptr) {
      freeaddrinfo(result);
      throw;
    }

    freeaddrinfo(result);

    p_sock.store(sock);
  }

  Socket_t(const sock_t sock) : p_sock(sock) {}

  Socket_t(Socket_t &&other) : p_sock(other.p_sock.exchange(-1)) {}

  ~Socket_t() {
    sock_t sock = p_sock.exchange(-1);
    if (sock >= 0) {
      ::close(sock);
    }
  }

  void set_timeout(unsigned long s, unsigned long us) const {
#ifdef __MINGW32__
    const struct timeval timeout = {static_cast<long>(s), static_cast<long>(us)};

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char *>(&timeout), sizeof(struct timeval))) {
      throw;
    }

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<const char *>(&timeout), sizeof(struct timeval))) {
      throw;
    }
#else
    const struct timeval timeout = {static_cast<__darwin_time_t>(s), static_cast<__darwin_suseconds_t>(us)};

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval))) {
      throw;
    }

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval))) {
      throw;
    }
#endif
  }

  void set_timeout(unsigned long s) const {
    set_timeout(s, 0);
  }

  void set_timeout() const {
    set_timeout(0, 1);
  }

  template <class str_t>
  str_t read() const {
    char buffer[200];
    auto size = recv(p_sock.load(), buffer, 200, 0);
    return str_t(buffer, size);
  }

  template <class str_t>
  str_t read(size_t size) const {
    std::unique_ptr<char> buffer(new char[size]);
    size = recvfrom(p_sock.load(), buffer.get(), size, 0, nullptr, nullptr);
    return str_t(buffer.get(), size);
  }

  template <class str_t>
  void write(const str_t &out) const {
    send(p_sock.load(), out.c_str(), out.size(), 0);
  }

  std::atomic<sock_t> p_sock;
};

template <class sock_t>
class Handshake_t {
public:
  template <class in_func_t, class out_func_t>
  Handshake_t(const sock_t &sock, in_func_t in, out_func_t out) {
  }
};

enum Query_e {
  REQL_CONTINUE = 2,
  REQL_NOREPLY_WAIT = 4,
  REQL_START = 1,
  REQL_STOP = 3
};

template <class str_t>
class Query_t {
  Query_t() {}

  Query_t(const ReQL_Token t, const Query_e type) : token(t) {
    p_stream << "[" << static_cast<int>(type) << "]";
  }

  template <class query_t>
  Query_t(const ReQL_Token t, const query_t &query) : token(t) {
    p_stream << "[" << static_cast<int>(REQL_START) << ",";
    query.toJSON(p_stream);
    p_stream << "]";
  }

  template <class kwargs_t, class query_t>
  Query_t(const ReQL_Token t, const query_t &query, const kwargs_t &kwargs) : token(t) {
    p_stream << "[" << static_cast<int>(REQL_START) << ",";
    query.toJSON(p_stream);
    p_stream << ",";
    kwargs.toJSON(p_stream);
    p_stream << "]";
  }

  str_t str() const {
    return p_stream.str();
  }

  Stream<str_t> p_stream;
  ReQL_Token token;
};

template <class sock_t>
class Protocol_t {
public:
  Protocol_t() {}

  template <class str_t>
  Protocol_t(str_t &addr, str_t &port, str_t &auth) : p_sock(addr, port) {
    Handshake_t<sock_t>(p_sock, auth);
  }

  template <class str_t>
  Protocol_t &operator <<(Query_t<str_t> &query) {
    auto wire_query = query.str();
    auto size = wire_query.size();

    if (size > UINT32_MAX) {
      throw std::exception();
    }

    Stream<str_t> stream;

    ReQL_Byte token_bytes[8];
    make_token(token_bytes, query.token);

    ReQL_Byte size_bytes[4];
    make_size(size_bytes, static_cast<ReQL_Size>(size));

    stream << str_t(token_bytes, 8) << str_t(size_bytes, 4) << wire_query;

    p_sock.write(stream.str());

    return *this;
  }

  template <class str_t>
  Protocol_t &operator >>(str_t &result) {
    return *this;
  }

  void stop(ReQL_Token t) {
    Query_t<ImmutableString> query(t, REQL_STOP);
    (*this) << query;
  }

  void cont(ReQL_Token t) {
    Query_t<ImmutableString> query(t, REQL_CONTINUE);
    (*this) << query;
  }

  sock_t p_sock;
};

template <class conn_t>
void *
conn_loop(void *data) {
  conn_t *conn = reinterpret_cast<conn_t *>(data);
  ReQL_Token token = 0;
  ReQL_Size size = 0;

  std::basic_string<ReQL_Byte> response;

  try {
    while (conn->isOpen()) {
      conn->lock();
      if (conn->p_cursors.size() == 0) {
        conn->unlock();
        sched_yield();
        continue;
      }
      conn->unlock();

      response.append(conn->recv());

      if (size > 0) {
        if (response.length() >= size) {
          conn->lock();
          for (auto &&pair : conn->p_cursors) {
            if (0 == token) {
            }
          }
          conn->unlock();

          response = response.substr(size);
          response.reserve(12);
          size = 0;
        }
      } else if (response.length() >= 12) {
        token = get_token(response.c_str());
        size = get_size(&response.c_str()[8]);
        response = response.substr(12);
        response.reserve(size);
      }
    }
  } catch (std::exception &e) {
    conn->close();
    throw e;
  }

  conn->close();

  return nullptr;
}

template <class cur_t>
class Conn_t {
public:
  template <class conn_t>
  friend void *conn_loop(void *data);

  class Token {
  public:
    Token() {}

    Token(ReQL_Token token, ImmutableString &&json) : p_token(token), p_json(std::move(json)) {}

    ReQL_Token p_token;
    ImmutableString p_json;
  };

  Conn_t(std::string &addr, std::string &port, std::string &auth) : p_protocol(addr, port, auth) {
    p_sink = Pipe<Token>([]() {
    }).sink([](Token &) {
    });
  }

  Conn_t(Conn_t &&other) : p_cursors(std::move(other.p_cursors)), p_protocol(std::move(other.p_protocol)) {}

  ~Conn_t() {
    p_cursors.close();
  }

  Conn_t &operator =(Conn_t &&other) {
    if (this != &other) {
      p_cursors = std::move(other.p_cursors);
      p_protocol = std::move(other.p_protocol);
    }
    return *this;
  }

  bool isOpen() const {
    return p_protocol.p_sock.p_sock.load() >= 0;
  }

  template <class query_t>
  cur_t run(const query_t &query) {
    Query_t<ImmutableString> q(1, query);
    p_protocol << q;
  }

  template <class kwargs_t, class query_t>
  cur_t run(const query_t &query, const kwargs_t &kwargs) {
    Query_t<ImmutableString> q(1, query, kwargs);
    p_protocol << q;
  }

  template <class kwargs_t, class query_t>
  void noReply(const query_t &query, const kwargs_t &kwargs) {
    Query_t<ImmutableString> q(1, query, kwargs);
    p_protocol << q;
  }

  void noReplyWait() {
    Query_t<ImmutableString> query(1, REQL_NOREPLY_WAIT);
    p_protocol << query;
  }

  static ImmutableString constant(const Query_e type) {
    _Stream wire_query;
    wire_query << "[" << static_cast<int>(type) << "]";
    return wire_query.str();
  }

  class BTree {
  public:
    void close() {
    }
    std::mutex p_mutex;
  };

  std::atomic<ReQL_Token> p_max_token;
  BTree p_cursors;
  Protocol_t<Socket_t<int>> p_protocol;
  typename Pipe<ImmutableString>::Sink p_sink;
};

}  // namespace _ReQL

#endif  // REQL_REQL_CONNECTION_HPP_
<commit_msg>Fill in handshake.<commit_after>/*
Copyright 2014-2015 Adam Grandquist

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.
 */
/**
 * @author Adam Grandquist
 * @copyright Apache
 */

#ifndef REQL_REQL_CONNECTION_HPP_
#define REQL_REQL_CONNECTION_HPP_

#include "./reql/pipe.hpp"
#include "./reql/query.hpp"
#include "./reql/stream.hpp"
#include "./reql/types.hpp"

#include <atomic>
#include <map>
#include <mutex>
#include <thread>

#ifdef __MINGW32__
#include <stdint.h>
#include <io.h>

typedef unsigned __LONG32 ULONG;
typedef short SHORT;
typedef unsigned char UCHAR;

#include <nettypes.h>
#include <netprov.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#endif

namespace _ReQL {

static const ReQL_Size VERSION = 0x400c2d20;
static const ReQL_Size PROTOCOL = 0x7e6970c7;

template <class byte_t>
ReQL_Size
get_size(const byte_t *buf) {
  return (static_cast<ReQL_Size>(buf[0])<<0) | (static_cast<ReQL_Size>(buf[1])<<8) | (static_cast<ReQL_Size>(buf[2])<<16) | (static_cast<ReQL_Size>(buf[3])<<24);
}

template <class byte_t>
void
make_size(byte_t *buf, const ReQL_Size magic) {
  buf[0] = (magic >> 0) & 0xFF;
  buf[1] = (magic >> 8) & 0xFF;
  buf[2] = (magic >> 16) & 0xFF;
  buf[3] = (magic >> 24) & 0xFF;
}

template <class byte_t>
void
make_token(byte_t *buf, const ReQL_Token magic) {
  buf[0] = (magic >> 0) & 0xFF;
  buf[1] = (magic >> 8) & 0xFF;
  buf[2] = (magic >> 16) & 0xFF;
  buf[3] = (magic >> 24) & 0xFF;
  buf[4] = (magic >> 32) & 0xFF;
  buf[5] = (magic >> 40) & 0xFF;
  buf[6] = (magic >> 48) & 0xFF;
  buf[7] = (magic >> 56) & 0xFF;
}

template <class byte_t>
ReQL_Token
get_token(const byte_t *buf) {
  return (static_cast<ReQL_Token>(buf[0])<<0) | (static_cast<ReQL_Token>(buf[1])<<8) | (static_cast<ReQL_Token>(buf[2])<<16) | (static_cast<ReQL_Token>(buf[3])<<24) | (static_cast<ReQL_Token>(buf[4])<<32) | (static_cast<ReQL_Token>(buf[5])<<40) | (static_cast<ReQL_Token>(buf[6])<<48) | (static_cast<ReQL_Token>(buf[7])<<56);
}

template <class sock_t>
class Socket_t {
public:
  Socket_t() : p_sock(-1) {}

  template <class str_t>
  Socket_t(str_t &addr, str_t &port) : p_sock(-1) {
    struct addrinfo hints;
    struct addrinfo *result, *rp;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = IPPROTO_TCP;

    if (getaddrinfo(addr.c_str(), port.c_str(), &hints, &result) != 0) {
      throw;
    }

    sock_t sock = -1;

    for (rp = result; rp != nullptr; rp = rp->ai_next) {
      sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);

      if (sock == -1) continue;

      if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;

      ::close(sock);
    }

    if (rp == nullptr) {
      freeaddrinfo(result);
      throw;
    }

    freeaddrinfo(result);

    p_sock.store(sock);
  }

  Socket_t(const sock_t sock) : p_sock(sock) {}

  Socket_t(Socket_t &&other) : p_sock(other.p_sock.exchange(-1)) {}

  ~Socket_t() {
    sock_t sock = p_sock.exchange(-1);
    if (sock >= 0) {
      ::close(sock);
    }
  }

  void set_timeout(unsigned long s, unsigned long us) const {
#ifdef __MINGW32__
    const struct timeval timeout = {static_cast<long>(s), static_cast<long>(us)};

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char *>(&timeout), sizeof(struct timeval))) {
      throw;
    }

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<const char *>(&timeout), sizeof(struct timeval))) {
      throw;
    }
#else
    const struct timeval timeout = {static_cast<__darwin_time_t>(s), static_cast<__darwin_suseconds_t>(us)};

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval))) {
      throw;
    }

    if (setsockopt(p_sock.load(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval))) {
      throw;
    }
#endif
  }

  void set_timeout(unsigned long s) const {
    set_timeout(s, 0);
  }

  void set_timeout() const {
    set_timeout(0, 1);
  }

  template <class str_t>
  str_t read() const {
    char buffer[200];
    auto size = recv(p_sock.load(), buffer, 200, 0);
    return str_t(buffer, size);
  }

  template <class str_t>
  str_t read(size_t size) const {
    std::unique_ptr<char> buffer(new char[size]);
    size = recvfrom(p_sock.load(), buffer.get(), size, 0, nullptr, nullptr);
    return str_t(buffer.get(), size);
  }

  template <class str_t>
  void write(const str_t &out) const {
    send(p_sock.load(), out.c_str(), out.size(), 0);
  }

  std::atomic<sock_t> p_sock;
};

template <class sock_t>
class Handshake_t {
public:
  template <class str_t>
  Handshake_t(const sock_t &sock, str_t &auth) {
    sock.set_timeout(20, 0);

    ReQL_Byte magic[3][4];

    make_size(magic[0], VERSION);
    make_size(magic[1], auth.size());
    make_size(magic[2], PROTOCOL);

    Stream<str_t> stream;
    stream << str_t(magic[0], 4)
        << str_t(magic[1], 4)
        << auth
        << str_t(magic[2], 4);

    sock.write(stream.str());

    auto response = sock.read();

    if (response.size() != 8) {
      throw;
    }

    if (response != "SUCCESS") {
      throw;
    }

    sock.set_timeout();
  }
};

enum Query_e {
  REQL_CONTINUE = 2,
  REQL_NOREPLY_WAIT = 4,
  REQL_START = 1,
  REQL_STOP = 3
};

template <class str_t>
class Query_t {
  Query_t() {}

  Query_t(const ReQL_Token t, const Query_e type) : token(t) {
    p_stream << "[" << static_cast<int>(type) << "]";
  }

  template <class query_t>
  Query_t(const ReQL_Token t, const query_t &query) : token(t) {
    p_stream << "[" << static_cast<int>(REQL_START) << ",";
    query.toJSON(p_stream);
    p_stream << "]";
  }

  template <class kwargs_t, class query_t>
  Query_t(const ReQL_Token t, const query_t &query, const kwargs_t &kwargs) : token(t) {
    p_stream << "[" << static_cast<int>(REQL_START) << ",";
    query.toJSON(p_stream);
    p_stream << ",";
    kwargs.toJSON(p_stream);
    p_stream << "]";
  }

  str_t str() const {
    return p_stream.str();
  }

  Stream<str_t> p_stream;
  ReQL_Token token;
};

template <class sock_t>
class Protocol_t {
public:
  Protocol_t() {}

  template <class str_t>
  Protocol_t(str_t &addr, str_t &port, str_t &auth) : p_sock(addr, port) {
    Handshake_t<sock_t>(p_sock, auth);
  }

  template <class str_t>
  Protocol_t &operator <<(Query_t<str_t> &query) {
    auto wire_query = query.str();
    auto size = wire_query.size();

    if (size > UINT32_MAX) {
      throw std::exception();
    }

    Stream<str_t> stream;

    ReQL_Byte token_bytes[8];
    make_token(token_bytes, query.token);

    ReQL_Byte size_bytes[4];
    make_size(size_bytes, static_cast<ReQL_Size>(size));

    stream << str_t(token_bytes, 8) << str_t(size_bytes, 4) << wire_query;

    p_sock.write(stream.str());

    return *this;
  }

  template <class str_t>
  Protocol_t &operator >>(str_t &result) {
    return *this;
  }

  void stop(ReQL_Token t) {
    Query_t<ImmutableString> query(t, REQL_STOP);
    (*this) << query;
  }

  void cont(ReQL_Token t) {
    Query_t<ImmutableString> query(t, REQL_CONTINUE);
    (*this) << query;
  }

  sock_t p_sock;
};

template <class conn_t>
void *
conn_loop(void *data) {
  conn_t *conn = reinterpret_cast<conn_t *>(data);
  ReQL_Token token = 0;
  ReQL_Size size = 0;

  std::basic_string<ReQL_Byte> response;

  try {
    while (conn->isOpen()) {
      conn->lock();
      if (conn->p_cursors.size() == 0) {
        conn->unlock();
        sched_yield();
        continue;
      }
      conn->unlock();

      response.append(conn->recv());

      if (size > 0) {
        if (response.length() >= size) {
          conn->lock();
          for (auto &&pair : conn->p_cursors) {
            if (0 == token) {
            }
          }
          conn->unlock();

          response = response.substr(size);
          response.reserve(12);
          size = 0;
        }
      } else if (response.length() >= 12) {
        token = get_token(response.c_str());
        size = get_size(&response.c_str()[8]);
        response = response.substr(12);
        response.reserve(size);
      }
    }
  } catch (std::exception &e) {
    conn->close();
    throw e;
  }

  conn->close();

  return nullptr;
}

template <class cur_t>
class Conn_t {
public:
  template <class conn_t>
  friend void *conn_loop(void *data);

  class Token {
  public:
    Token() {}

    Token(ReQL_Token token, ImmutableString &&json) : p_token(token), p_json(std::move(json)) {}

    ReQL_Token p_token;
    ImmutableString p_json;
  };

  Conn_t(std::string &addr, std::string &port, std::string &auth) : p_protocol(addr, port, auth) {
    p_sink = Pipe<Token>([]() {
    }).sink([](Token &) {
    });
  }

  Conn_t(Conn_t &&other) : p_cursors(std::move(other.p_cursors)), p_protocol(std::move(other.p_protocol)) {}

  ~Conn_t() {
    p_cursors.close();
  }

  Conn_t &operator =(Conn_t &&other) {
    if (this != &other) {
      p_cursors = std::move(other.p_cursors);
      p_protocol = std::move(other.p_protocol);
    }
    return *this;
  }

  bool isOpen() const {
    return p_protocol.p_sock.p_sock.load() >= 0;
  }

  template <class query_t>
  cur_t run(const query_t &query) {
    Query_t<ImmutableString> q(1, query);
    p_protocol << q;
  }

  template <class kwargs_t, class query_t>
  cur_t run(const query_t &query, const kwargs_t &kwargs) {
    Query_t<ImmutableString> q(1, query, kwargs);
    p_protocol << q;
  }

  template <class kwargs_t, class query_t>
  void noReply(const query_t &query, const kwargs_t &kwargs) {
    Query_t<ImmutableString> q(1, query, kwargs);
    p_protocol << q;
  }

  void noReplyWait() {
    Query_t<ImmutableString> query(1, REQL_NOREPLY_WAIT);
    p_protocol << query;
  }

  static ImmutableString constant(const Query_e type) {
    _Stream wire_query;
    wire_query << "[" << static_cast<int>(type) << "]";
    return wire_query.str();
  }

  class BTree {
  public:
    void close() {
    }
    std::mutex p_mutex;
  };

  std::atomic<ReQL_Token> p_max_token;
  BTree p_cursors;
  Protocol_t<Socket_t<int>> p_protocol;
  typename Pipe<ImmutableString>::Sink p_sink;
};

}  // namespace _ReQL

#endif  // REQL_REQL_CONNECTION_HPP_
<|endoftext|>


<commit_before>//
//  main.cpp
//  ServoInterface
//
//  Created by Neil Ang on 16/09/13.
//  Copyright (c) 2013 Neil Ang. All rights reserved.
//

#include <iostream>
#include "maestro.h"
#include <time.h>

#ifdef __APPLE__
#define NA_DEVICE "/dev/cu.usbmodem00065291"
#else
#define NA_DEVICE "/dev/serial/by-path/platform-bcm2708_usb-usb-0:1.2.2:1.0"
#endif

using namespace std;

void busyWait(Maestro *maestro, unsigned char channel){
    while(maestro->isMoving(channel)){
        usleep(100000);
        cout << "now at " << maestro->getPosition(channel) << endl;
    }
}

int main(int argc, const char * argv[])
{

    try {
        Maestro maestro(NA_DEVICE);

        maestro.setPosition(0, 3968);
        busyWait(&maestro, 0);
        maestro.setPosition(0, 9216);
        busyWait(&maestro, 0);
        maestro.goHome(0);
        busyWait(&maestro, 1);

        maestro.setPosition(1, 6912);
        busyWait(&maestro, 1);
        maestro.setPosition(1, 9984);
        busyWait(&maestro, 1);
        maestro.goHome(1);

        cout << "Done" << endl;

    } catch (std::exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

<commit_msg>Fix busyWait lock<commit_after>//
//  main.cpp
//  ServoInterface
//
//  Created by Neil Ang on 16/09/13.
//  Copyright (c) 2013 Neil Ang. All rights reserved.
//

#include <iostream>
#include "maestro.h"
#include <time.h>

#ifdef __APPLE__
#define NA_DEVICE "/dev/cu.usbmodem00065291"
#else
#define NA_DEVICE "/dev/serial/by-path/platform-bcm2708_usb-usb-0:1.2.2:1.0"
#endif

using namespace std;

void busyWait(Maestro *maestro, unsigned char channel){
    int pos = maestro->getPosition(channel);
    while(maestro->isMoving(channel)){
        usleep(100000);
        if(maestro->getPosition(channel) == pos){
            break;
        }
        else {
            pos = maestro->getPosition(channel);
        }
    }
}

int main(int argc, const char * argv[])
{

    try {
        Maestro maestro(NA_DEVICE);

        maestro.setPosition(0, 3968);
        busyWait(&maestro, 0);
        maestro.setPosition(0, 9216);
        busyWait(&maestro, 0);
        maestro.goHome(0);
        busyWait(&maestro, 1);

        maestro.setPosition(1, 6912);
        busyWait(&maestro, 1);
        maestro.setPosition(1, 9984);
        busyWait(&maestro, 1);
        maestro.goHome(1);

        cout << "Done" << endl;

    } catch (std::exception& e) {
        cout << e.what() << endl;
    }

    return 0;
}

<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */
#ifndef PCL_TRACKING_IMPL_HSV_COLOR_COHERENCE_H_
#define PCL_TRACKING_IMPL_HSV_COLOR_COHERENCE_H_

#include <Eigen/Dense>

#ifdef BUILD_Maintainer
#  if defined __GNUC__
#      pragma GCC system_header
#  elif defined _MSC_VER
#    pragma warning(push, 1)
#  endif
#endif

namespace pcl
{
  namespace tracking
  {
    // utility
    typedef union
    {
      struct /*anonymous*/
      {
        unsigned char Blue; // Blue channel
        unsigned char Green; // Green channel
        unsigned char Red; // Red channel
      };
      float float_value;
      long long_value;
    } RGBValue;

    /** \brief Convert a RGB tuple to an HSV one.
      * \param[in] r the input Red component
      * \param[in] g the input Green component
      * \param[in] b the input Blue component
      * \param[out] fh the output Hue component
      * \param[out] fs the output Saturation component
      * \param[out] fv the output Value component
      */
    void
    RGB2HSV (int r, int g, int b, float& fh, float& fs, float& fv)
    {
      // mostly copied from opencv-svn/modules/imgproc/src/color.cpp
      // revision is 4351
      const int hsv_shift = 12;

      static const int div_table[] =
      {
        0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211,
        130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632,
        65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412,
        43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693,
        32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782,
        26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223,
        21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991,
        18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579,
        16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711,
        14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221,
        13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006,
        11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995,
        10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141,
        10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410,
        9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777,
        8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224,
        8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737,
        7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304,
        7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917,
        6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569,
        6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254,
        6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968,
        5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708,
        5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468,
        5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249,
        5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046,
        5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858,
        4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684,
        4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522,
        4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370,
        4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229,
        4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096
      };
      int hr = 180, hscale = 15;
      int h, s, v = b;
      int vmin = b, diff;
      int vr, vg;

      v = std::max<int> (v, g);
      v = std::max<int> (v, r);
      vmin = std::min<int> (vmin, g);
      vmin = std::min<int> (vmin, r);

      diff = v - vmin;
      vr = v == r ? -1 : 0;
      vg = v == g ? -1 : 0;

      s = diff * div_table[v] >> hsv_shift;
      h = (vr & (g - b)) +
          (~vr & ((vg & (b - r + 2 * diff))
          + ((~vg) & (r - g + 4 * diff))));
      h = (h * div_table[diff] * hscale +
          (1 << (hsv_shift + 6))) >> (7 + hsv_shift);

      h += h < 0 ? hr : 0;
      fh = static_cast<float> (h) / 180.0f;
      fs = static_cast<float> (s) / 255.0f;
      fv = static_cast<float> (v) / 255.0f;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename PointInT> double
    HSVColorCoherence<PointInT>::computeCoherence (PointInT &source, PointInT &target)
    {
      // convert color space from RGB to HSV
      RGBValue source_rgb, target_rgb;
      source_rgb.float_value = static_cast<float> (source.rgba);
      target_rgb.float_value = static_cast<float> (target.rgba);

      float source_h, source_s, source_v, target_h, target_s, target_v;
      RGB2HSV (source_rgb.Red, source_rgb.Blue, source_rgb.Green,
               source_h, source_s, source_v);
      RGB2HSV (target_rgb.Red, target_rgb.Blue, target_rgb.Green,
               target_h, target_s, target_v);
      // hue value is in 0 ~ 2pi, but circulated.
      const float _h_diff = fabsf (source_h - target_h);
      float h_diff;
      if (_h_diff > 0.5f)
        h_diff = static_cast<float> (h_weight_) * (_h_diff - 0.5f) * (_h_diff - 0.5f);
      else
        h_diff = static_cast<float> (h_weight_) * _h_diff * _h_diff;

      const float s_diff = static_cast<float> (s_weight_) * (source_s - target_s) * (source_s - target_s);
      const float v_diff = static_cast<float> (v_weight_) * (source_v - target_v) * (source_v - target_v);
      const float diff2 = h_diff + s_diff + v_diff;

      return (1.0 / (1.0 + weight_ * diff2));
    }
  }
}

#define PCL_INSTANTIATE_HSVColorCoherence(T) template class PCL_EXPORTS pcl::tracking::HSVColorCoherence<T>;

#ifdef BUILD_Maintainer
#  if defined _MSC_VER
#    pragma warning(pop)
#  endif
#endif

#endif
<commit_msg>avoid casting int to float when dealing with rgb field <commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */
#ifndef PCL_TRACKING_IMPL_HSV_COLOR_COHERENCE_H_
#define PCL_TRACKING_IMPL_HSV_COLOR_COHERENCE_H_

#include <Eigen/Dense>

#ifdef BUILD_Maintainer
#  if defined __GNUC__
#      pragma GCC system_header
#  elif defined _MSC_VER
#    pragma warning(push, 1)
#  endif
#endif

namespace pcl
{
  namespace tracking
  {
    // utility
    typedef union
    {
      struct /*anonymous*/
      {
        unsigned char Blue; // Blue channel
        unsigned char Green; // Green channel
        unsigned char Red; // Red channel
      };
      float float_value;
      int int_value;
    } RGBValue;

    /** \brief Convert a RGB tuple to an HSV one.
      * \param[in] r the input Red component
      * \param[in] g the input Green component
      * \param[in] b the input Blue component
      * \param[out] fh the output Hue component
      * \param[out] fs the output Saturation component
      * \param[out] fv the output Value component
      */
    void
    RGB2HSV (int r, int g, int b, float& fh, float& fs, float& fv)
    {
      // mostly copied from opencv-svn/modules/imgproc/src/color.cpp
      // revision is 4351
      const int hsv_shift = 12;

      static const int div_table[] =
      {
        0, 1044480, 522240, 348160, 261120, 208896, 174080, 149211,
        130560, 116053, 104448, 94953, 87040, 80345, 74606, 69632,
        65280, 61440, 58027, 54973, 52224, 49737, 47476, 45412,
        43520, 41779, 40172, 38684, 37303, 36017, 34816, 33693,
        32640, 31651, 30720, 29842, 29013, 28229, 27486, 26782,
        26112, 25475, 24869, 24290, 23738, 23211, 22706, 22223,
        21760, 21316, 20890, 20480, 20086, 19707, 19342, 18991,
        18651, 18324, 18008, 17703, 17408, 17123, 16846, 16579,
        16320, 16069, 15825, 15589, 15360, 15137, 14921, 14711,
        14507, 14308, 14115, 13926, 13743, 13565, 13391, 13221,
        13056, 12895, 12738, 12584, 12434, 12288, 12145, 12006,
        11869, 11736, 11605, 11478, 11353, 11231, 11111, 10995,
        10880, 10768, 10658, 10550, 10445, 10341, 10240, 10141,
        10043, 9947, 9854, 9761, 9671, 9582, 9495, 9410,
        9326, 9243, 9162, 9082, 9004, 8927, 8852, 8777,
        8704, 8632, 8561, 8492, 8423, 8356, 8290, 8224,
        8160, 8097, 8034, 7973, 7913, 7853, 7795, 7737,
        7680, 7624, 7569, 7514, 7461, 7408, 7355, 7304,
        7253, 7203, 7154, 7105, 7057, 7010, 6963, 6917,
        6872, 6827, 6782, 6739, 6695, 6653, 6611, 6569,
        6528, 6487, 6447, 6408, 6369, 6330, 6292, 6254,
        6217, 6180, 6144, 6108, 6073, 6037, 6003, 5968,
        5935, 5901, 5868, 5835, 5803, 5771, 5739, 5708,
        5677, 5646, 5615, 5585, 5556, 5526, 5497, 5468,
        5440, 5412, 5384, 5356, 5329, 5302, 5275, 5249,
        5222, 5196, 5171, 5145, 5120, 5095, 5070, 5046,
        5022, 4998, 4974, 4950, 4927, 4904, 4881, 4858,
        4836, 4813, 4791, 4769, 4748, 4726, 4705, 4684,
        4663, 4642, 4622, 4601, 4581, 4561, 4541, 4522,
        4502, 4483, 4464, 4445, 4426, 4407, 4389, 4370,
        4352, 4334, 4316, 4298, 4281, 4263, 4246, 4229,
        4212, 4195, 4178, 4161, 4145, 4128, 4112, 4096
      };
      int hr = 180, hscale = 15;
      int h, s, v = b;
      int vmin = b, diff;
      int vr, vg;

      v = std::max<int> (v, g);
      v = std::max<int> (v, r);
      vmin = std::min<int> (vmin, g);
      vmin = std::min<int> (vmin, r);

      diff = v - vmin;
      vr = v == r ? -1 : 0;
      vg = v == g ? -1 : 0;

      s = diff * div_table[v] >> hsv_shift;
      h = (vr & (g - b)) +
          (~vr & ((vg & (b - r + 2 * diff))
          + ((~vg) & (r - g + 4 * diff))));
      h = (h * div_table[diff] * hscale +
          (1 << (hsv_shift + 6))) >> (7 + hsv_shift);

      h += h < 0 ? hr : 0;
      fh = static_cast<float> (h) / 180.0f;
      fs = static_cast<float> (s) / 255.0f;
      fv = static_cast<float> (v) / 255.0f;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    template <typename PointInT> double
    HSVColorCoherence<PointInT>::computeCoherence (PointInT &source, PointInT &target)
    {
      // convert color space from RGB to HSV
      RGBValue source_rgb, target_rgb;
      source_rgb.int_value = source.rgba;
      target_rgb.int_value = target.rgba;

      float source_h, source_s, source_v, target_h, target_s, target_v;
      RGB2HSV (source_rgb.Red, source_rgb.Blue, source_rgb.Green,
               source_h, source_s, source_v);
      RGB2HSV (target_rgb.Red, target_rgb.Blue, target_rgb.Green,
               target_h, target_s, target_v);
      // hue value is in 0 ~ 2pi, but circulated.
      const float _h_diff = fabsf (source_h - target_h);
      float h_diff;
      if (_h_diff > 0.5f)
        h_diff = static_cast<float> (h_weight_) * (_h_diff - 0.5f) * (_h_diff - 0.5f);
      else
        h_diff = static_cast<float> (h_weight_) * _h_diff * _h_diff;

      const float s_diff = static_cast<float> (s_weight_) * (source_s - target_s) * (source_s - target_s);
      const float v_diff = static_cast<float> (v_weight_) * (source_v - target_v) * (source_v - target_v);
      const float diff2 = h_diff + s_diff + v_diff;

      return (1.0 / (1.0 + weight_ * diff2));
    }
  }
}

#define PCL_INSTANTIATE_HSVColorCoherence(T) template class PCL_EXPORTS pcl::tracking::HSVColorCoherence<T>;

#ifdef BUILD_Maintainer
#  if defined _MSC_VER
#    pragma warning(pop)
#  endif
#endif

#endif
<|endoftext|>