<commit_before>// Copyright (c) 2011-2015 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 "overviewpage.h"
#include "ui_overviewpage.h"
#include "skinize.h"

#include "navcoinunits.h"
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "platformstyle.h"
#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"
#include "walletmodel.h"
#include "walletframe.h"
#include "askpassphrasedialog.h"
#include "util.h"

#include <QAbstractItemDelegate>
#include <QPainter>

#define DECORATION_SIZE 17
#define NUM_ITEMS 5

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    TxViewDelegate(const PlatformStyle *platformStyle):
        QAbstractItemDelegate(), unit(NavCoinUnits::NAV),
        platformStyle(platformStyle)
    {

    }

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

        QIcon icon = qvariant_cast<QIcon>(index.data(TransactionTableModel::RawDecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.left(), mainRect.top()+DECORATION_SIZE, DECORATION_SIZE, DECORATION_SIZE);
        int xspace = DECORATION_SIZE + 6;
        int ypad = 1;
        int halfheight = (mainRect.height() - 3*ypad - 4)/3 ;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, 150, DECORATION_SIZE);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad, 300, DECORATION_SIZE);
        QRect dateRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight*2, 150, DECORATION_SIZE);
        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);

        painter->setPen(QColor(60,60,60));
        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 = COLOR_POSITIVE;
        }
        painter->setPen(foreground);
        QString amountText = NavCoinUnits::formatWithUnit(unit, amount, true, NavCoinUnits::separatorAlways);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }
        painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, amountText);

        painter->setPen(COLOR_BAREADDRESS);
        painter->drawText(dateRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        return QSize(DECORATION_SIZE, DECORATION_SIZE*2.9 + 4);
    }

    int unit;
    const PlatformStyle *platformStyle;

};
#include "overviewpage.moc"

OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    clientModel(0),
    walletModel(0),
    currentBalance(-1),
    currentUnconfirmedBalance(-1),
    currentStakingBalance(-1),
    currentImmatureBalance(-1),
    currentWatchOnlyBalance(-1),
    currentWatchUnconfBalance(-1),
    currentWatchImmatureBalance(-1),
    txdelegate(new TxViewDelegate(platformStyle)),
    filter(0)
{
    ui->setupUi(this);

    // 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->labelWalletStatus->setIcon(icon);

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

    connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
    connect(ui->unlockStakingButton, SIGNAL(clicked()), this, SLOT(unlockWalletStaking()));

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
    updateStakeReportNow();
}

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

void OverviewPage::showLockStaking(bool status)
{
    ui->unlockStakingButton->setVisible(status);
}

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

void OverviewPage::setStakingStats(QString day, QString week, QString month)
{
    ui->label24hStakingStats->setText(day);
    ui->label7dStakingStats->setText(week);
    ui->label30dStakingStats->setText(month);
}

void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& stakingBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance)
{
    int unit = walletModel->getOptionsModel()->getDisplayUnit();
    currentBalance = balance;
    currentUnconfirmedBalance = unconfirmedBalance;
    currentStakingBalance = stakingBalance;
    currentImmatureBalance = immatureBalance;
    currentWatchOnlyBalance = watchOnlyBalance;
    currentWatchUnconfBalance = watchUnconfBalance;
    currentWatchImmatureBalance = watchImmatureBalance;
    ui->labelBalance->setText(NavCoinUnits::formatWithUnit(unit, balance, false, NavCoinUnits::separatorAlways));
    ui->labelUnconfirmed->setText(NavCoinUnits::formatWithUnit(unit, unconfirmedBalance, false, NavCoinUnits::separatorAlways));
    ui->labelStaking->setText(NavCoinUnits::formatWithUnit(unit, stakingBalance, false, NavCoinUnits::separatorAlways));
    ui->labelImmature->setText(NavCoinUnits::formatWithUnit(unit, immatureBalance, false, NavCoinUnits::separatorAlways));
    ui->labelTotal->setText(NavCoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + stakingBalance + immatureBalance, false, NavCoinUnits::separatorAlways));

    bool showStaking = immatureBalance != 0;

    ui->labelStaking->setVisible(showStaking);
    ui->labelStakingText->setVisible(showStaking);

    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = immatureBalance != 0;
    bool showWatchOnlyImmature = watchImmatureBalance != 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);
}

// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
{

}

void OverviewPage::setStakingStatus(QString text)
{
    ui->stakingStatusLabel->setText(text);
};

void OverviewPage::setStatusTitleBlocks(QString text)
{
    ui->statusTitleBlocks->setText(text);
}

void OverviewPage::setStatusTitleConnections(QString text)
{
    ui->statusTitleConnections->setText(text);

}

void OverviewPage::setStatusTitle(QString text)
{
    ui->statusTitle->setText(text);
}

void OverviewPage::showStatusTitleConnections(){
    ui->statusTitleConnections->show();
};
void OverviewPage::hideStatusTitleConnections(){
    ui->statusTitleConnections->hide();
};
void OverviewPage::showStatusTitleBlocks(){
    ui->statusTitleBlocks->show();
};
void OverviewPage::hideStatusTitleBlocks(){
    ui->statusTitleBlocks->hide();
};

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

void OverviewPage::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter = 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);
        ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getStake(), model->getImmatureBalance(),
                   model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
        connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
        connect(model, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount,CAmount,CAmount,CAmount)), this, SLOT(updateStakeReportbalanceChanged(CAmount, CAmount, CAmount,CAmount, CAmount,CAmount,CAmount)));

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

        updateWatchOnlyLabels(model->haveWatchOnly());
        connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
    }

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

void OverviewPage::updateDisplayUnit()
{
    if(walletModel && walletModel->getOptionsModel())
    {
        if(currentBalance != -1)
            setBalance(currentBalance, currentUnconfirmedBalance, currentStakingBalance, currentImmatureBalance,
                       currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance);

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

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

void OverviewPage::unlockWalletStaking()
{
    if(!walletModel)
        return;
    // Unlock wallet when requested by wallet model
    if (walletModel->getEncryptionStatus() == WalletModel::Locked)
    {
        AskPassphraseDialog dlg(AskPassphraseDialog::UnlockStaking, this);
        dlg.setModel(walletModel);
        dlg.exec();
    }
}

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);
}

using namespace boost;
using namespace std;

struct StakePeriodRange_T {
    int64_t Start;
    int64_t End;
    int64_t Total;
    int Count;
    string Name;
};

typedef vector<StakePeriodRange_T> vStakePeriodRange_T;

extern vStakePeriodRange_T PrepareRangeForStakeReport();
extern int GetsStakeSubTotal(vStakePeriodRange_T& aRange);

void OverviewPage::updateStakeReport(bool fImmediate=false)
{
    static vStakePeriodRange_T aRange;
    int nItemCounted=0;

    if (fImmediate) nLastReportUpdate = 0;

    if (this->isHidden())
        return;

    int64_t nTook = GetTimeMillis();

    // Skip report recalc if not immediate or before 5 minutes from last
    if (GetTime() - nLastReportUpdate > 300)
    {

        aRange = PrepareRangeForStakeReport();

        // get subtotal calc
        nItemCounted = GetsStakeSubTotal(aRange);

        nLastReportUpdate = GetTime();

        nTook = GetTimeMillis() - nTook;

    }

    int64_t nTook2 = GetTimeMillis();

    int i=30;

    int unit = walletModel->getOptionsModel()->getDisplayUnit();

    ui->label24hStakingStats->setText(NavCoinUnits::formatWithUnit(unit, aRange[i++].Total, false, NavCoinUnits::separatorAlways));
    ui->label7dStakingStats->setText(NavCoinUnits::formatWithUnit(unit, aRange[i++].Total, false, NavCoinUnits::separatorAlways));
    ui->label30dStakingStats->setText(NavCoinUnits::formatWithUnit(unit, aRange[i++].Total, false, NavCoinUnits::separatorAlways));

}

void OverviewPage::updateStakeReportbalanceChanged(qint64, qint64, qint64, qint64, qint64, qint64, qint64)
{
    OverviewPage::updateStakeReportNow();
}

void OverviewPage::updateStakeReportNow()
{
    updateStakeReport(true);
}
<commit_msg>gui: fixed balance amount<commit_after>// Copyright (c) 2011-2015 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 "overviewpage.h"
#include "ui_overviewpage.h"
#include "skinize.h"

#include "navcoinunits.h"
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "platformstyle.h"
#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"
#include "walletmodel.h"
#include "walletframe.h"
#include "askpassphrasedialog.h"
#include "util.h"

#include <QAbstractItemDelegate>
#include <QPainter>

#define DECORATION_SIZE 17
#define NUM_ITEMS 5

class TxViewDelegate : public QAbstractItemDelegate
{
    Q_OBJECT
public:
    TxViewDelegate(const PlatformStyle *platformStyle):
        QAbstractItemDelegate(), unit(NavCoinUnits::NAV),
        platformStyle(platformStyle)
    {

    }

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

        QIcon icon = qvariant_cast<QIcon>(index.data(TransactionTableModel::RawDecorationRole));
        QRect mainRect = option.rect;
        QRect decorationRect(mainRect.left(), mainRect.top()+DECORATION_SIZE, DECORATION_SIZE, DECORATION_SIZE);
        int xspace = DECORATION_SIZE + 6;
        int ypad = 1;
        int halfheight = (mainRect.height() - 3*ypad - 4)/3 ;
        QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, 150, DECORATION_SIZE);
        QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad, 300, DECORATION_SIZE);
        QRect dateRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight*2, 150, DECORATION_SIZE);
        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);

        painter->setPen(QColor(60,60,60));
        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 = COLOR_POSITIVE;
        }
        painter->setPen(foreground);
        QString amountText = NavCoinUnits::formatWithUnit(unit, amount, true, NavCoinUnits::separatorAlways);
        if(!confirmed)
        {
            amountText = QString("[") + amountText + QString("]");
        }
        painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, amountText);

        painter->setPen(COLOR_BAREADDRESS);
        painter->drawText(dateRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));

        painter->restore();
    }

    inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        return QSize(DECORATION_SIZE, DECORATION_SIZE*2.9 + 4);
    }

    int unit;
    const PlatformStyle *platformStyle;

};
#include "overviewpage.moc"

OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::OverviewPage),
    clientModel(0),
    walletModel(0),
    currentBalance(-1),
    currentUnconfirmedBalance(-1),
    currentStakingBalance(-1),
    currentImmatureBalance(-1),
    currentWatchOnlyBalance(-1),
    currentWatchUnconfBalance(-1),
    currentWatchImmatureBalance(-1),
    txdelegate(new TxViewDelegate(platformStyle)),
    filter(0)
{
    ui->setupUi(this);

    // 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->labelWalletStatus->setIcon(icon);

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

    connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
    connect(ui->unlockStakingButton, SIGNAL(clicked()), this, SLOT(unlockWalletStaking()));

    // start with displaying the "out of sync" warnings
    showOutOfSyncWarning(true);
    updateStakeReportNow();
}

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

void OverviewPage::showLockStaking(bool status)
{
    ui->unlockStakingButton->setVisible(status);
}

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

void OverviewPage::setStakingStats(QString day, QString week, QString month)
{
    ui->label24hStakingStats->setText(day);
    ui->label7dStakingStats->setText(week);
    ui->label30dStakingStats->setText(month);
}

void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& stakingBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance)
{
    int unit = walletModel->getOptionsModel()->getDisplayUnit();
    currentBalance = balance;
    currentUnconfirmedBalance = unconfirmedBalance;
    currentStakingBalance = stakingBalance;
    currentImmatureBalance = immatureBalance;
    currentWatchOnlyBalance = watchOnlyBalance;
    currentWatchUnconfBalance = watchUnconfBalance;
    currentWatchImmatureBalance = watchImmatureBalance;
    ui->labelBalance->setText(NavCoinUnits::formatWithUnit(unit, balance, false, NavCoinUnits::separatorAlways));
    ui->labelUnconfirmed->setText(NavCoinUnits::formatWithUnit(unit, unconfirmedBalance, false, NavCoinUnits::separatorAlways));
    ui->labelStaking->setText(NavCoinUnits::formatWithUnit(unit, stakingBalance, false, NavCoinUnits::separatorAlways));
    ui->labelImmature->setText(NavCoinUnits::formatWithUnit(unit, immatureBalance, false, NavCoinUnits::separatorAlways));
    ui->labelTotal->setText(NavCoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + stakingBalance, false, NavCoinUnits::separatorAlways));

    bool showStaking = stakingBalance != 0;

    ui->labelStaking->setVisible(showStaking);
    ui->labelStakingText->setVisible(showStaking);

    // only show immature (newly mined) balance if it's non-zero, so as not to complicate things
    // for the non-mining users
    bool showImmature = false;
    bool showWatchOnlyImmature = watchImmatureBalance != 0;

    // for symmetry reasons also show immature label when the watch-only one is shown
    ui->labelImmature->setVisible(false);
    ui->labelImmatureText->setVisible(false);
}

// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
{

}

void OverviewPage::setStakingStatus(QString text)
{
    ui->stakingStatusLabel->setText(text);
};

void OverviewPage::setStatusTitleBlocks(QString text)
{
    ui->statusTitleBlocks->setText(text);
}

void OverviewPage::setStatusTitleConnections(QString text)
{
    ui->statusTitleConnections->setText(text);

}

void OverviewPage::setStatusTitle(QString text)
{
    ui->statusTitle->setText(text);
}

void OverviewPage::showStatusTitleConnections(){
    ui->statusTitleConnections->show();
};
void OverviewPage::hideStatusTitleConnections(){
    ui->statusTitleConnections->hide();
};
void OverviewPage::showStatusTitleBlocks(){
    ui->statusTitleBlocks->show();
};
void OverviewPage::hideStatusTitleBlocks(){
    ui->statusTitleBlocks->hide();
};

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

void OverviewPage::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model && model->getOptionsModel())
    {
        // Set up transaction list
        filter = 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);
        ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);

        // Keep up to date with wallet
        setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getStake(), model->getImmatureBalance(),
                   model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
        connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
        connect(model, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount,CAmount,CAmount,CAmount)), this, SLOT(updateStakeReportbalanceChanged(CAmount, CAmount, CAmount,CAmount, CAmount,CAmount,CAmount)));

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

        updateWatchOnlyLabels(model->haveWatchOnly());
        connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
    }

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

void OverviewPage::updateDisplayUnit()
{
    if(walletModel && walletModel->getOptionsModel())
    {
        if(currentBalance != -1)
            setBalance(currentBalance, currentUnconfirmedBalance, currentStakingBalance, currentImmatureBalance,
                       currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance);

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

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

void OverviewPage::unlockWalletStaking()
{
    if(!walletModel)
        return;
    // Unlock wallet when requested by wallet model
    if (walletModel->getEncryptionStatus() == WalletModel::Locked)
    {
        AskPassphraseDialog dlg(AskPassphraseDialog::UnlockStaking, this);
        dlg.setModel(walletModel);
        dlg.exec();
    }
}

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);
}

using namespace boost;
using namespace std;

struct StakePeriodRange_T {
    int64_t Start;
    int64_t End;
    int64_t Total;
    int Count;
    string Name;
};

typedef vector<StakePeriodRange_T> vStakePeriodRange_T;

extern vStakePeriodRange_T PrepareRangeForStakeReport();
extern int GetsStakeSubTotal(vStakePeriodRange_T& aRange);

void OverviewPage::updateStakeReport(bool fImmediate=false)
{
    static vStakePeriodRange_T aRange;
    int nItemCounted=0;

    if (fImmediate) nLastReportUpdate = 0;

    if (this->isHidden())
        return;

    int64_t nTook = GetTimeMillis();

    // Skip report recalc if not immediate or before 5 minutes from last
    if (GetTime() - nLastReportUpdate > 300)
    {

        aRange = PrepareRangeForStakeReport();

        // get subtotal calc
        nItemCounted = GetsStakeSubTotal(aRange);

        nLastReportUpdate = GetTime();

        nTook = GetTimeMillis() - nTook;

    }

    int64_t nTook2 = GetTimeMillis();

    int i=30;

    int unit = walletModel->getOptionsModel()->getDisplayUnit();

    ui->label24hStakingStats->setText(NavCoinUnits::formatWithUnit(unit, aRange[i++].Total, false, NavCoinUnits::separatorAlways));
    ui->label7dStakingStats->setText(NavCoinUnits::formatWithUnit(unit, aRange[i++].Total, false, NavCoinUnits::separatorAlways));
    ui->label30dStakingStats->setText(NavCoinUnits::formatWithUnit(unit, aRange[i++].Total, false, NavCoinUnits::separatorAlways));

}

void OverviewPage::updateStakeReportbalanceChanged(qint64, qint64, qint64, qint64, qint64, qint64, qint64)
{
    OverviewPage::updateStakeReportNow();
}

void OverviewPage::updateStakeReportNow()
{
    updateStakeReport(true);
}
<|endoftext|>


<commit_before>#include "splashscreen.h"
#include "clientversion.h"
#include "util.h"

#include <QPainter>
#undef loop /* ugh, remove this when the #define loop is gone from util.h */
#include <QApplication>

SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) :
    QSplashScreen(pixmap, f)
{
    // set reference point, paddings
    int paddingLeftCol2         = 130;
    int paddingTopCol2          = 376;
    int line1 = 0;
    int line2 = 13;
    int line3 = 26;

    float fontFactor            = 1.0;

    // define text to place
    QString titleText       = QString(QApplication::applicationName()).replace(QString("-testnet"), QString(""), Qt::CaseSensitive); // cut of testnet, place it as single object further down
    QString versionText     = QString("Version %1 ").arg(QString::fromStdString(FormatFullVersion()));
    QString copyrightText1   = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin developers"));
    QString copyrightText2   = QChar(0xA9)+QString(" %1 ").arg(COPYRIGHT_YEAR) + QString(tr("The FlappyCoin developers"));

    QString font            = "Arial";

    // load the bitmap for writing some text over it
    QPixmap newPixmap;
    if(GetBoolArg("-testnet")) {
        newPixmap     = QPixmap(":/images/splash_testnet");
    }
    else {
        newPixmap     = QPixmap(":/images/splash");
    }

    QPainter pixPaint(&newPixmap);
    pixPaint.setPen(QColor(70,70,70));

    pixPaint.setFont(QFont(font, 9*fontFactor));
    pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line3,versionText);

    // draw copyright stuff
    pixPaint.setFont(QFont(font, 9*fontFactor));
    pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line1,copyrightText1);
    pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line2,copyrightText2);

    pixPaint.end();

    this->setPixmap(newPixmap);
}
<commit_msg>Update splashscreen.cpp<commit_after>#include "splashscreen.h"
#include "clientversion.h"
#include "util.h"

#include <QPainter>
#undef loop /* ugh, remove this when the #define loop is gone from util.h */
#include <QApplication>

SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f) :
    QSplashScreen(pixmap, f)
{
    // set reference point, paddings
    int paddingLeftCol2         = 130;
    int paddingTopCol2          = 376;
    int line1 = 0;
    int line2 = 13;
    int line3 = 26;

    float fontFactor            = 1.0;

    // define text to place
    QString titleText       = QString(QApplication::applicationName()).replace(QString("-testnet"), QString(""), Qt::CaseSensitive); // cut of testnet, place it as single object further down
    QString versionText     = QString("Version %1 ").arg(QString::fromStdString(FormatFullVersion()));
    QString copyrightText1   = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("Bitcoin Developers"));
    QString copyrightText2   = QChar(0xA9)+QString(" %1 ").arg(COPYRIGHT_YEAR) + QString(tr("FlappyCoin Developers"));

    QString font            = "Arial";

    // load the bitmap for writing some text over it
    QPixmap newPixmap;
    if(GetBoolArg("-testnet")) {
        newPixmap     = QPixmap(":/images/splash_testnet");
    }
    else {
        newPixmap     = QPixmap(":/images/splash");
    }

    QPainter pixPaint(&newPixmap);
    pixPaint.setPen(QColor(70,70,70));

    pixPaint.setFont(QFont(font, 9*fontFactor));
    pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line3,versionText);

    // draw copyright stuff
    pixPaint.setFont(QFont(font, 9*fontFactor));
    pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line1,copyrightText1);
    pixPaint.drawText(paddingLeftCol2,paddingTopCol2+line2,copyrightText2);

    pixPaint.end();

    this->setPixmap(newPixmap);
}
<|endoftext|>


<commit_before>/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, Robert Bosch LLC.
 *  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 the Robert Bosch 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.
 *
 *********************************************************************/

//\Author Kai Franke

#include "raspi_interface/raspi_interface.hpp"

/**********************************************************************/
// Constructor
/**********************************************************************/
RaspiInterface::RaspiInterface():
  is_initialized_( false )
{
}

/**********************************************************************/
// Destructor
/**********************************************************************/
RaspiInterface::~RaspiInterface()
{
  // close all serial connections
  for (std::map<std::string,int>::iterator it=serial_devices_.begin(); it!=serial_devices_.end(); ++it)
  {
    serialClose(it->second);
  }
}

/**********************************************************************/
// Initialize:
/**********************************************************************/
bool RaspiInterface::initialize()
{
  // Prevent Double-initialization!
  if( is_initialized_ == true )
  {
    ROS_INFO( "RaspiInterface::initialize(): WiringPi already initialized." );
    return true;
  }

  // Setup WiringPi
  int init_reply = wiringPiSetup ();

  // Set all SPI channels not to use by default
  for( ssize_t i = 0; i < MAX_SPI_CHANNELS; ++i )
  {
    use_spi[i] = false;
  }

  if( init_reply != 0 )
  {
    ROS_ERROR( "WiringPi not initialized properly. Returned %i", init_reply);
    return false;
  }

  is_initialized_ = true;
  ROS_INFO( "RaspiInterface::initialize(): WiringPi initialized." );
  return true;
}

/**********************************************************************/
// Read
/**********************************************************************/
ssize_t RaspiInterface::read( int device_address, interface_protocol protocol, int frequency, int* flags, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  int error_code = 0;

  // Check initialization:
  if( is_initialized_ == false )
  {
    return -1;
  }

  switch( protocol )
  {
    case GPIO:
    {
      error_code = raspiGpioRead( (uint8_t)flags[0], reg_address, data );
      break;
    }
    case SPI:
    {
      error_code = raspiSpi( frequency, (uint8_t)flags[0], reg_address, data, num_bytes );
      break;
    }
    case I2C:
    {
      error_code = raspiI2cRead( device_address, frequency, reg_address, data, num_bytes );
    } break;
    case RS232:
    {
      error_code = raspiRs232Read( frequency, flags[0], data, num_bytes );
    } break;
    default:
    {
      ROS_ERROR("Raspberry Pi does not support reading through this protocol.");
      return -1;
    }
  }
  return error_code;
}

/**********************************************************************/
// Write
/**********************************************************************/
ssize_t RaspiInterface::write( int device_address, interface_protocol protocol, int frequency, int* flags, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  int error_code = 0;

  // Check initialization:
  if( is_initialized_ == false )
  {
    return -1;
  }

  switch( protocol )
  {
    case GPIO:
    {
      error_code = raspiGpioWrite( reg_address, (bool)data[0] );
      break;
    }
    case SPI:
    {
      error_code = raspiSpi( frequency, (uint8_t)flags[0], reg_address, data, num_bytes );
      break;
    }
    case RS232:
    {
      error_code = raspiRs232Write( frequency, data, num_bytes );
    } break;
    case I2C:
    {
      error_code = raspiI2cWrite( device_address, frequency, reg_address, data, num_bytes );
    } break;
    default:
    {
      ROS_ERROR( "Raspberry Pi does not support writing through this protocol." );
      error_code = -1;
    }
  }

  return error_code; // bytes written, or error.
}

/**********************************************************************/
// supportedProtocol
/**********************************************************************/
bool RaspiInterface::supportedProtocol( interface_protocol protocol )
{
  switch( protocol )
  {
  case GPIO:
  case SPI:
  case RS232:
  case I2C:
    return true;
  default:
    return false;
  }
}

/**********************************************************************/
std::string RaspiInterface::getID()
/**********************************************************************/
{
  return "Raspberry Pi";
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiGpioWrite( uint8_t pin, bool value )
{

  // check if selected pin is valid for Raspberry Pi
  if( pin > 16 )
  {
    ROS_ERROR("The selected Pin number is not available for GPIO");
    ROS_ERROR("Select Pins 0 through 16 instead");
    return -1;
  }

  pinMode (pin, OUTPUT);
  digitalWrite (pin, value);

  return 1;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiGpioRead( uint8_t flags, uint8_t pin, uint8_t* value )
{

  // check if selected pin is valid for Raspberry Pi
  if( pin > 16 )
  {
    ROS_ERROR("The selected Pin number is not available for GPIO");
    ROS_ERROR("Select Pins 0 through 16 instead");
    return -1;
  }

  pinMode( pin, INPUT );

  switch ((gpio_input_mode) flags )
  {
    case FLOATING:
    {
      pullUpDnControl( pin, PUD_OFF );
    } break;
    case PULLUP:
    {
      pullUpDnControl( pin, PUD_UP );
    } break;
    case PULLDOWN:
    {
      pullUpDnControl( pin, PUD_DOWN );
    } break;
    default:
    {
      ROS_ERROR("ArduinoInterface::arduinoGpioRead The selected input mode is not known");
      return -1;
    }
  }

  value[0] = digitalRead( pin );

  return 1;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiSpi( int frequency, uint8_t flags, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  //  Decrypt flags:
  uint8_t spi_slave_select = (flags >> 4);
  uint8_t bit_order = (flags>>2) & 0x01;
  uint8_t mode = flags & 0x03;

  // Sanity check for decrypted flags
  if( mode != bosch_drivers_common::SPI_MODE_0 )
  {
    ROS_ERROR( "Only mode 0 is implemented in wiringPi at this point" );
    return -1;
  }
  if( bit_order != 0 )
  {
    ROS_ERROR( "Only MSB first is implemented in wiringPi at this point" );
    return -1;
  }
  if( spi_slave_select == bosch_drivers_common::NULL_DEVICE )
  {
    ROS_ERROR( "NULL_DEVICE functionality not implemented yet" );
    return -1;
  }
  if( spi_slave_select >= MAX_SPI_CHANNELS )
  {
    ROS_ERROR( "Maximum SPI channel is %i, you asked for channel %i", MAX_SPI_CHANNELS-1, spi_slave_select );
    return -1;
  }
  if( frequency < MIN_SPI_FREQUENCY || frequency > MAX_SPI_FREQUENCY )
  {
    ROS_WARN( "The requested frequency of %i is out of bounds. Setting frequency to 1MHz", frequency );
    frequency = 1e6;
  }

  // setup SPI channel if it has not been setup yet
  if( use_spi[spi_slave_select] == false )
  {
    if( wiringPiSPISetup (spi_slave_select, frequency) == -1 )
    {
      ROS_ERROR( "RaspiInterface::initializeSPI(): SPI channel 0 not initialized properly.");
      return -1;
    }
    use_spi[spi_slave_select] = true;
    ROS_INFO( "SPI channel %u initialized.", spi_slave_select );
  }

  // transfer the address register:
  wiringPiSPIDataRW( spi_slave_select, &reg_address, 1 );

  // read/write from/to SPI bus
  wiringPiSPIDataRW( spi_slave_select, data, num_bytes );

  return num_bytes;
}

ssize_t RaspiInterface::raspiRs232Write( int frequency, uint8_t* data, size_t num_bytes )
{
  // convert uint8_t* to string
  std::string complete( data, data + num_bytes );
  // split string at first colon
  size_t delimiter = complete.find_first_of( ':' );
  if( delimiter == std::string::npos )
  {
    ROS_ERROR( "No colon found in data string! Example: /dev/ttyUSB0:helloWorld" );
    return -1;
  }
  std::string device  = complete.substr( 0, delimiter );
  std::string command = complete.substr( delimiter + 1 );
  char* cdevice = reinterpret_cast<char*>(&device[0]);
  char* ccommand= reinterpret_cast<char*>(&command[0]);

  // open new serial device if not opened yet
  if( serial_devices_.count(device) != 1 )
  {
    // open serial interface using wiringPi
    ROS_INFO("Opening serial interface %s...", cdevice );
    int file_descriptor = serialOpen( cdevice, frequency );
    // check if serial device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening serial device %s failed :(", cdevice );
      return -1;
    }
    else
    {
      ROS_INFO( "Successfully opened serial port %s", cdevice );
    }
    // create new hash entry
    serial_devices_[device] = file_descriptor;
  }
  // write command to RS232 connection
  serialPuts( serial_devices_[device], ccommand );

  return command.size();
}

ssize_t RaspiInterface::raspiRs232Read( int frequency, int device_name_length, uint8_t* data, size_t num_bytes )
{
  std::string device( data, data + device_name_length );
  char* cdevice = reinterpret_cast<char*>(&device[0]);

  // open new serial device if not opened yet
  if( serial_devices_.count(cdevice) != 1 )
  {
    // open serial interface using wiringPi
    ROS_INFO("Opening serial interface %s...", cdevice );
    int file_descriptor = serialOpen( cdevice, frequency );
    // check if serial device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening serial device %s failed :(", cdevice );
      return -1;
    }
    else
    {
      ROS_INFO( "Successfully opened serial port %s", cdevice );
    }
    // create new hash entry
    serial_devices_[device] = file_descriptor;
  }
  // read from RS232
  unsigned int index = 0;
  int temp = 0;
  while( temp != -1 && num_bytes-- > 0 )
  {
    temp = serialGetchar( serial_devices_[device] );
    data[index++] = static_cast<uint8_t>(temp);
  }

  if( index != num_bytes )
  {
    ROS_WARN( "You asked for %zd bytes but I only read %i due to error or timeout", num_bytes, index );
  }

  return index;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiI2cWrite( uint8_t device_address, uint32_t frequency, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
ROS_INFO("raspiI2cWrite %u %u %u %u %i", device_address, frequency, reg_address, data[0], num_bytes);
  switch( frequency )
  {
    case 100000: break;
    default:
    {
      ROS_WARN_ONCE("Default frequency 100k. Use 'gpio load i2c XXXX' to set the frequency");
    }
  }

  // open new i2c device if not opened yet
  if( i2c_devices_.count(device_address) != 1 )
  {
    // open i2c interface using wiringPi
    int file_descriptor = wiringPiI2CSetup( device_address );
    // check if i2c device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening i2c device %i failed :(", device_address );
      return -1;
    }
    // create new hash entry
    i2c_devices_[device_address] = file_descriptor;
    ROS_INFO( "Successfully opened i2c device %i", device_address);
  }

  int error_code = -1;
  switch( num_bytes )
  {
    case 1:
    {
      error_code = wiringPiI2CWriteReg8 (i2c_devices_[device_address], (int)reg_address, (int)(data[0]));
    } break;
    case 2:
    {
      // compose 16 Bit value to transmit assuming data[1] is the MSB
      int temp = ((int)data[1])*256 + data[0];
      error_code = wiringPiI2CWriteReg16 (i2c_devices_[device_address], reg_address, temp);
    } break;
    default:
    {
      ROS_ERROR("Raspberry Pi can only transmit either one or two bytes");
    }
  }

  if( error_code == -1 )
  {
    ROS_ERROR( "I2C Write failed on device %u, register %i and data %i",device_address, (int)reg_address, (int)(data[0]) );
    return error_code;
  }

  return num_bytes;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiI2cRead( uint8_t device_address, uint32_t frequency, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
ROS_INFO("raspiI2cRead %u %u %u %i", device_address, frequency, reg_address, num_bytes);
  switch( frequency )
  {
    case 100000: break;
    default:
    {
      ROS_WARN_ONCE("Default frequency 100k. Use 'gpio load i2c XXXX' to set the frequency");
    }
  }

  // open new i2c device if not opened yet
  if( i2c_devices_.count(device_address) != 1 )
  {
    // open i2c interface using wiringPi
    int file_descriptor = wiringPiI2CSetup( device_address );
    // check if i2c device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening i2c device %i failed :(", device_address );
      return -1;
    }
    // create new hash entry
    i2c_devices_[device_address] = file_descriptor;
    ROS_INFO( "Successfully opened i2c device %i", device_address);
  }

  for( int i = reg_address; i < reg_address + num_bytes; i++)
  {
      data[i-reg_address] = wiringPiI2CReadReg8( i2c_devices_[device_address], i);
  }

  return num_bytes;
}
<commit_msg>remove debug<commit_after>/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2013, Robert Bosch LLC.
 *  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 the Robert Bosch 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.
 *
 *********************************************************************/

//\Author Kai Franke

#include "raspi_interface/raspi_interface.hpp"

/**********************************************************************/
// Constructor
/**********************************************************************/
RaspiInterface::RaspiInterface():
  is_initialized_( false )
{
}

/**********************************************************************/
// Destructor
/**********************************************************************/
RaspiInterface::~RaspiInterface()
{
  // close all serial connections
  for (std::map<std::string,int>::iterator it=serial_devices_.begin(); it!=serial_devices_.end(); ++it)
  {
    serialClose(it->second);
  }
}

/**********************************************************************/
// Initialize:
/**********************************************************************/
bool RaspiInterface::initialize()
{
  // Prevent Double-initialization!
  if( is_initialized_ == true )
  {
    ROS_INFO( "RaspiInterface::initialize(): WiringPi already initialized." );
    return true;
  }

  // Setup WiringPi
  int init_reply = wiringPiSetup ();

  // Set all SPI channels not to use by default
  for( ssize_t i = 0; i < MAX_SPI_CHANNELS; ++i )
  {
    use_spi[i] = false;
  }

  if( init_reply != 0 )
  {
    ROS_ERROR( "WiringPi not initialized properly. Returned %i", init_reply);
    return false;
  }

  is_initialized_ = true;
  ROS_INFO( "RaspiInterface::initialize(): WiringPi initialized." );
  return true;
}

/**********************************************************************/
// Read
/**********************************************************************/
ssize_t RaspiInterface::read( int device_address, interface_protocol protocol, int frequency, int* flags, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  int error_code = 0;

  // Check initialization:
  if( is_initialized_ == false )
  {
    return -1;
  }

  switch( protocol )
  {
    case GPIO:
    {
      error_code = raspiGpioRead( (uint8_t)flags[0], reg_address, data );
      break;
    }
    case SPI:
    {
      error_code = raspiSpi( frequency, (uint8_t)flags[0], reg_address, data, num_bytes );
      break;
    }
    case I2C:
    {
      error_code = raspiI2cRead( device_address, frequency, reg_address, data, num_bytes );
    } break;
    case RS232:
    {
      error_code = raspiRs232Read( frequency, flags[0], data, num_bytes );
    } break;
    default:
    {
      ROS_ERROR("Raspberry Pi does not support reading through this protocol.");
      return -1;
    }
  }
  return error_code;
}

/**********************************************************************/
// Write
/**********************************************************************/
ssize_t RaspiInterface::write( int device_address, interface_protocol protocol, int frequency, int* flags, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  int error_code = 0;

  // Check initialization:
  if( is_initialized_ == false )
  {
    return -1;
  }

  switch( protocol )
  {
    case GPIO:
    {
      error_code = raspiGpioWrite( reg_address, (bool)data[0] );
      break;
    }
    case SPI:
    {
      error_code = raspiSpi( frequency, (uint8_t)flags[0], reg_address, data, num_bytes );
      break;
    }
    case RS232:
    {
      error_code = raspiRs232Write( frequency, data, num_bytes );
    } break;
    case I2C:
    {
      error_code = raspiI2cWrite( device_address, frequency, reg_address, data, num_bytes );
    } break;
    default:
    {
      ROS_ERROR( "Raspberry Pi does not support writing through this protocol." );
      error_code = -1;
    }
  }

  return error_code; // bytes written, or error.
}

/**********************************************************************/
// supportedProtocol
/**********************************************************************/
bool RaspiInterface::supportedProtocol( interface_protocol protocol )
{
  switch( protocol )
  {
  case GPIO:
  case SPI:
  case RS232:
  case I2C:
    return true;
  default:
    return false;
  }
}

/**********************************************************************/
std::string RaspiInterface::getID()
/**********************************************************************/
{
  return "Raspberry Pi";
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiGpioWrite( uint8_t pin, bool value )
{

  // check if selected pin is valid for Raspberry Pi
  if( pin > 16 )
  {
    ROS_ERROR("The selected Pin number is not available for GPIO");
    ROS_ERROR("Select Pins 0 through 16 instead");
    return -1;
  }

  pinMode (pin, OUTPUT);
  digitalWrite (pin, value);

  return 1;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiGpioRead( uint8_t flags, uint8_t pin, uint8_t* value )
{

  // check if selected pin is valid for Raspberry Pi
  if( pin > 16 )
  {
    ROS_ERROR("The selected Pin number is not available for GPIO");
    ROS_ERROR("Select Pins 0 through 16 instead");
    return -1;
  }

  pinMode( pin, INPUT );

  switch ((gpio_input_mode) flags )
  {
    case FLOATING:
    {
      pullUpDnControl( pin, PUD_OFF );
    } break;
    case PULLUP:
    {
      pullUpDnControl( pin, PUD_UP );
    } break;
    case PULLDOWN:
    {
      pullUpDnControl( pin, PUD_DOWN );
    } break;
    default:
    {
      ROS_ERROR("ArduinoInterface::arduinoGpioRead The selected input mode is not known");
      return -1;
    }
  }

  value[0] = digitalRead( pin );

  return 1;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiSpi( int frequency, uint8_t flags, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  //  Decrypt flags:
  uint8_t spi_slave_select = (flags >> 4);
  uint8_t bit_order = (flags>>2) & 0x01;
  uint8_t mode = flags & 0x03;

  // Sanity check for decrypted flags
  if( mode != bosch_drivers_common::SPI_MODE_0 )
  {
    ROS_ERROR( "Only mode 0 is implemented in wiringPi at this point" );
    return -1;
  }
  if( bit_order != 0 )
  {
    ROS_ERROR( "Only MSB first is implemented in wiringPi at this point" );
    return -1;
  }
  if( spi_slave_select == bosch_drivers_common::NULL_DEVICE )
  {
    ROS_ERROR( "NULL_DEVICE functionality not implemented yet" );
    return -1;
  }
  if( spi_slave_select >= MAX_SPI_CHANNELS )
  {
    ROS_ERROR( "Maximum SPI channel is %i, you asked for channel %i", MAX_SPI_CHANNELS-1, spi_slave_select );
    return -1;
  }
  if( frequency < MIN_SPI_FREQUENCY || frequency > MAX_SPI_FREQUENCY )
  {
    ROS_WARN( "The requested frequency of %i is out of bounds. Setting frequency to 1MHz", frequency );
    frequency = 1e6;
  }

  // setup SPI channel if it has not been setup yet
  if( use_spi[spi_slave_select] == false )
  {
    if( wiringPiSPISetup (spi_slave_select, frequency) == -1 )
    {
      ROS_ERROR( "RaspiInterface::initializeSPI(): SPI channel 0 not initialized properly.");
      return -1;
    }
    use_spi[spi_slave_select] = true;
    ROS_INFO( "SPI channel %u initialized.", spi_slave_select );
  }

  // transfer the address register:
  wiringPiSPIDataRW( spi_slave_select, &reg_address, 1 );

  // read/write from/to SPI bus
  wiringPiSPIDataRW( spi_slave_select, data, num_bytes );

  return num_bytes;
}

ssize_t RaspiInterface::raspiRs232Write( int frequency, uint8_t* data, size_t num_bytes )
{
  // convert uint8_t* to string
  std::string complete( data, data + num_bytes );
  // split string at first colon
  size_t delimiter = complete.find_first_of( ':' );
  if( delimiter == std::string::npos )
  {
    ROS_ERROR( "No colon found in data string! Example: /dev/ttyUSB0:helloWorld" );
    return -1;
  }
  std::string device  = complete.substr( 0, delimiter );
  std::string command = complete.substr( delimiter + 1 );
  char* cdevice = reinterpret_cast<char*>(&device[0]);
  char* ccommand= reinterpret_cast<char*>(&command[0]);

  // open new serial device if not opened yet
  if( serial_devices_.count(device) != 1 )
  {
    // open serial interface using wiringPi
    ROS_INFO("Opening serial interface %s...", cdevice );
    int file_descriptor = serialOpen( cdevice, frequency );
    // check if serial device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening serial device %s failed :(", cdevice );
      return -1;
    }
    else
    {
      ROS_INFO( "Successfully opened serial port %s", cdevice );
    }
    // create new hash entry
    serial_devices_[device] = file_descriptor;
  }
  // write command to RS232 connection
  serialPuts( serial_devices_[device], ccommand );

  return command.size();
}

ssize_t RaspiInterface::raspiRs232Read( int frequency, int device_name_length, uint8_t* data, size_t num_bytes )
{
  std::string device( data, data + device_name_length );
  char* cdevice = reinterpret_cast<char*>(&device[0]);

  // open new serial device if not opened yet
  if( serial_devices_.count(cdevice) != 1 )
  {
    // open serial interface using wiringPi
    ROS_INFO("Opening serial interface %s...", cdevice );
    int file_descriptor = serialOpen( cdevice, frequency );
    // check if serial device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening serial device %s failed :(", cdevice );
      return -1;
    }
    else
    {
      ROS_INFO( "Successfully opened serial port %s", cdevice );
    }
    // create new hash entry
    serial_devices_[device] = file_descriptor;
  }
  // read from RS232
  unsigned int index = 0;
  int temp = 0;
  while( temp != -1 && num_bytes-- > 0 )
  {
    temp = serialGetchar( serial_devices_[device] );
    data[index++] = static_cast<uint8_t>(temp);
  }

  if( index != num_bytes )
  {
    ROS_WARN( "You asked for %zd bytes but I only read %i due to error or timeout", num_bytes, index );
  }

  return index;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiI2cWrite( uint8_t device_address, uint32_t frequency, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  switch( frequency )
  {
    case 100000: break;
    default:
    {
      ROS_WARN_ONCE("Default frequency 100k. Use 'gpio load i2c XXXX' to set the frequency");
    }
  }

  // open new i2c device if not opened yet
  if( i2c_devices_.count(device_address) != 1 )
  {
    // open i2c interface using wiringPi
    int file_descriptor = wiringPiI2CSetup( device_address );
    // check if i2c device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening i2c device %i failed :(", device_address );
      return -1;
    }
    // create new hash entry
    i2c_devices_[device_address] = file_descriptor;
    ROS_INFO( "Successfully opened i2c device %i", device_address);
  }

  int error_code = -1;
  switch( num_bytes )
  {
    case 1:
    {
      error_code = wiringPiI2CWriteReg8 (i2c_devices_[device_address], (int)reg_address, (int)(data[0]));
    } break;
    case 2:
    {
      // compose 16 Bit value to transmit assuming data[1] is the MSB
      int temp = ((int)data[1])*256 + data[0];
      error_code = wiringPiI2CWriteReg16 (i2c_devices_[device_address], reg_address, temp);
    } break;
    default:
    {
      ROS_ERROR("Raspberry Pi can only transmit either one or two bytes");
    }
  }

  if( error_code == -1 )
  {
    ROS_ERROR( "I2C Write failed on device %u, register %i and data %i",device_address, (int)reg_address, (int)(data[0]) );
    return error_code;
  }

  return num_bytes;
}

/**********************************************************************/
/**********************************************************************/
ssize_t RaspiInterface::raspiI2cRead( uint8_t device_address, uint32_t frequency, uint8_t reg_address, uint8_t* data, size_t num_bytes )
{
  switch( frequency )
  {
    case 100000: break;
    default:
    {
      ROS_WARN_ONCE("Default frequency 100k. Use 'gpio load i2c XXXX' to set the frequency");
    }
  }

  // open new i2c device if not opened yet
  if( i2c_devices_.count(device_address) != 1 )
  {
    // open i2c interface using wiringPi
    int file_descriptor = wiringPiI2CSetup( device_address );
    // check if i2c device was opened successfully
    if( file_descriptor == -1 )
    {
      ROS_ERROR("Opening i2c device %i failed :(", device_address );
      return -1;
    }
    // create new hash entry
    i2c_devices_[device_address] = file_descriptor;
    ROS_INFO( "Successfully opened i2c device %i", device_address);
  }

  for( int i = reg_address; i < reg_address + num_bytes; i++)
  {
      data[i-reg_address] = wiringPiI2CReadReg8( i2c_devices_[device_address], i);
  }

  return num_bytes;
}
<|endoftext|>


<commit_before>// Copyright 2017 The Ray Authors.
//
// 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.

#include "ray/util/logging.h"

#ifndef _WIN32
#include <execinfo.h>
#endif

#include <signal.h>
#include <stdlib.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>

#ifdef RAY_USE_GLOG
#include <sys/stat.h>
#include "glog/logging.h"
#endif

#include "ray/util/filesystem.h"

namespace ray {

#ifdef RAY_USE_GLOG
struct StdoutLogger : public google::base::Logger {
  virtual void Write(bool /* should flush */, time_t /* timestamp */, const char *message,
                     int length) {
    // note: always flush otherwise it never shows up in raylet.out
    std::cout << std::string(message, length) << std::flush;
  }

  virtual void Flush() { std::cout.flush(); }

  virtual google::uint32 LogSize() { return 0; }
};

static StdoutLogger stdout_logger_singleton;
#endif

// This is the default implementation of ray log,
// which is independent of any libs.
class CerrLog {
 public:
  CerrLog(RayLogLevel severity) : severity_(severity), has_logged_(false) {}

  virtual ~CerrLog() {
    if (has_logged_) {
      std::cerr << std::endl;
    }
    if (severity_ == RayLogLevel::FATAL) {
      PrintBackTrace();
      std::abort();
    }
  }

  std::ostream &Stream() {
    has_logged_ = true;
    return std::cerr;
  }

  template <class T>
  CerrLog &operator<<(const T &t) {
    if (severity_ != RayLogLevel::DEBUG) {
      has_logged_ = true;
      std::cerr << t;
    }
    return *this;
  }

 protected:
  const RayLogLevel severity_;
  bool has_logged_;

  void PrintBackTrace() {
#if defined(_EXECINFO_H) || !defined(_WIN32)
    void *buffer[255];
    const int calls = backtrace(buffer, sizeof(buffer) / sizeof(void *));
    backtrace_symbols_fd(buffer, calls, 1);
#endif
  }
};

#ifdef RAY_USE_GLOG
typedef google::LogMessage LoggingProvider;
#else
typedef ray::CerrLog LoggingProvider;
#endif

RayLogLevel RayLog::severity_threshold_ = RayLogLevel::INFO;
std::string RayLog::app_name_ = "";
std::string RayLog::log_dir_ = "";
bool RayLog::is_failure_signal_handler_installed_ = false;

#ifdef RAY_USE_GLOG
using namespace google;

// Glog's severity map.
static int GetMappedSeverity(RayLogLevel severity) {
  switch (severity) {
  case RayLogLevel::DEBUG:
    return GLOG_INFO;
  case RayLogLevel::INFO:
    return GLOG_INFO;
  case RayLogLevel::WARNING:
    return GLOG_WARNING;
  case RayLogLevel::ERROR:
    return GLOG_ERROR;
  case RayLogLevel::FATAL:
    return GLOG_FATAL;
  default:
    RAY_LOG(FATAL) << "Unsupported logging level: " << static_cast<int>(severity);
    // This return won't be hit but compiler needs it.
    return GLOG_FATAL;
  }
}

#endif

void RayLog::StartRayLog(const std::string &app_name, RayLogLevel severity_threshold,
                         const std::string &log_dir) {
  const char *var_value = getenv("RAY_BACKEND_LOG_LEVEL");
  if (var_value != nullptr) {
    std::string data = var_value;
    std::transform(data.begin(), data.end(), data.begin(), ::tolower);
    if (data == "debug") {
      severity_threshold = RayLogLevel::DEBUG;
    } else if (data == "info") {
      severity_threshold = RayLogLevel::INFO;
    } else if (data == "warning") {
      severity_threshold = RayLogLevel::WARNING;
    } else if (data == "error") {
      severity_threshold = RayLogLevel::ERROR;
    } else if (data == "fatal") {
      severity_threshold = RayLogLevel::FATAL;
    } else {
      RAY_LOG(WARNING) << "Unrecognized setting of RAY_BACKEND_LOG_LEVEL=" << var_value;
    }
    RAY_LOG(INFO) << "Set ray log level from environment variable RAY_BACKEND_LOG_LEVEL"
                  << " to " << static_cast<int>(severity_threshold);
  }
  severity_threshold_ = severity_threshold;
  app_name_ = app_name;
  log_dir_ = log_dir;
#ifdef RAY_USE_GLOG
  google::InitGoogleLogging(app_name_.c_str());
  // Enable log file if log_dir_ is not empty.
  std::string dir_ends_with_slash = log_dir_;
  if (!ray::IsDirSep(log_dir_[log_dir_.length() - 1])) {
    dir_ends_with_slash += ray::GetDirSep();
  }
  if (!log_dir_.empty()) {
    std::string app_name_without_path = app_name;
    if (app_name.empty()) {
      app_name_without_path = "DefaultApp";
    } else {
      // Find the app name without the path.
      std::string app_file_name = ray::GetFileName(app_name);
      if (!app_file_name.empty()) {
        app_name_without_path = app_file_name;
      }
    }
    google::SetLogFilenameExtension(app_name_without_path.c_str());
  }
  for (int lvl = 0; lvl < NUM_SEVERITIES; ++lvl) {
    if (log_dir_.empty()) {
      google::SetStderrLogging(lvl);
      google::base::SetLogger(lvl, &stdout_logger_singleton);
    } else {
      google::SetLogDestination(lvl, dir_ends_with_slash.c_str());
    }
  }
#endif
}

void RayLog::UninstallSignalAction() {
#ifdef RAY_USE_GLOG
  if (!is_failure_signal_handler_installed_) {
    return;
  }
  RAY_LOG(DEBUG) << "Uninstall signal handlers.";
  // This signal list comes from glog's signalhandler.cc.
  // https://github.com/google/glog/blob/master/src/signalhandler.cc#L58-L70
  std::vector<int> installed_signals({SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM});
#ifdef _WIN32  // Do NOT use WIN32 (without the underscore); we want _WIN32 here
  for (int signal_num : installed_signals) {
    RAY_CHECK(signal(signal_num, SIG_DFL) != SIG_ERR);
  }
#else
  struct sigaction sig_action;
  memset(&sig_action, 0, sizeof(sig_action));
  sigemptyset(&sig_action.sa_mask);
  sig_action.sa_handler = SIG_DFL;
  for (int signal_num : installed_signals) {
    RAY_CHECK(sigaction(signal_num, &sig_action, NULL) == 0);
  }
#endif
  is_failure_signal_handler_installed_ = false;
#endif
}

void RayLog::ShutDownRayLog() {
#ifdef RAY_USE_GLOG
  UninstallSignalAction();
  google::ShutdownGoogleLogging();
#endif
}

void RayLog::InstallFailureSignalHandler() {
#ifdef _WIN32
  // If process fails to initialize, don't display an error window.
  SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS);
  // If process crashes, don't display an error window.
  SetErrorMode(GetErrorMode() | SEM_NOGPFAULTERRORBOX);
#endif
#ifdef RAY_USE_GLOG
  if (is_failure_signal_handler_installed_) {
    return;
  }
  google::InstallFailureSignalHandler();
  is_failure_signal_handler_installed_ = true;
#endif
}

bool RayLog::IsLevelEnabled(RayLogLevel log_level) {
  return log_level >= severity_threshold_;
}

RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity)
    // glog does not have DEBUG level, we can handle it using is_enabled_.
    : logging_provider_(nullptr), is_enabled_(severity >= severity_threshold_) {
#ifdef RAY_USE_GLOG
  if (is_enabled_) {
    logging_provider_ =
        new google::LogMessage(file_name, line_number, GetMappedSeverity(severity));
  }
#else
  auto logging_provider = new CerrLog(severity);
  *logging_provider << file_name << ":" << line_number << ": ";
  logging_provider_ = logging_provider;
#endif
}

std::ostream &RayLog::Stream() {
  auto logging_provider = reinterpret_cast<LoggingProvider *>(logging_provider_);
#ifdef RAY_USE_GLOG
  // Before calling this function, user should check IsEnabled.
  // When IsEnabled == false, logging_provider_ will be empty.
  return logging_provider->stream();
#else
  return logging_provider->Stream();
#endif
}

bool RayLog::IsEnabled() const { return is_enabled_; }

RayLog::~RayLog() {
  if (logging_provider_ != nullptr) {
    delete reinterpret_cast<LoggingProvider *>(logging_provider_);
    logging_provider_ = nullptr;
  }
}

}  // namespace ray
<commit_msg>Fix Google log directory again (#9063)<commit_after>// Copyright 2017 The Ray Authors.
//
// 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.

#include "ray/util/logging.h"

#ifndef _WIN32
#include <execinfo.h>
#endif

#include <signal.h>
#include <stdlib.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>

#ifdef RAY_USE_GLOG
#include <sys/stat.h>
#include "glog/logging.h"
#endif

#include "ray/util/filesystem.h"

namespace ray {

#ifdef RAY_USE_GLOG
struct StdoutLogger : public google::base::Logger {
  virtual void Write(bool /* should flush */, time_t /* timestamp */, const char *message,
                     int length) {
    // note: always flush otherwise it never shows up in raylet.out
    std::cout << std::string(message, length) << std::flush;
  }

  virtual void Flush() { std::cout.flush(); }

  virtual google::uint32 LogSize() { return 0; }
};

static StdoutLogger stdout_logger_singleton;
#endif

// This is the default implementation of ray log,
// which is independent of any libs.
class CerrLog {
 public:
  CerrLog(RayLogLevel severity) : severity_(severity), has_logged_(false) {}

  virtual ~CerrLog() {
    if (has_logged_) {
      std::cerr << std::endl;
    }
    if (severity_ == RayLogLevel::FATAL) {
      PrintBackTrace();
      std::abort();
    }
  }

  std::ostream &Stream() {
    has_logged_ = true;
    return std::cerr;
  }

  template <class T>
  CerrLog &operator<<(const T &t) {
    if (severity_ != RayLogLevel::DEBUG) {
      has_logged_ = true;
      std::cerr << t;
    }
    return *this;
  }

 protected:
  const RayLogLevel severity_;
  bool has_logged_;

  void PrintBackTrace() {
#if defined(_EXECINFO_H) || !defined(_WIN32)
    void *buffer[255];
    const int calls = backtrace(buffer, sizeof(buffer) / sizeof(void *));
    backtrace_symbols_fd(buffer, calls, 1);
#endif
  }
};

#ifdef RAY_USE_GLOG
typedef google::LogMessage LoggingProvider;
#else
typedef ray::CerrLog LoggingProvider;
#endif

RayLogLevel RayLog::severity_threshold_ = RayLogLevel::INFO;
std::string RayLog::app_name_ = "";
std::string RayLog::log_dir_ = "";
bool RayLog::is_failure_signal_handler_installed_ = false;

#ifdef RAY_USE_GLOG
using namespace google;

// Glog's severity map.
static int GetMappedSeverity(RayLogLevel severity) {
  switch (severity) {
  case RayLogLevel::DEBUG:
    return GLOG_INFO;
  case RayLogLevel::INFO:
    return GLOG_INFO;
  case RayLogLevel::WARNING:
    return GLOG_WARNING;
  case RayLogLevel::ERROR:
    return GLOG_ERROR;
  case RayLogLevel::FATAL:
    return GLOG_FATAL;
  default:
    RAY_LOG(FATAL) << "Unsupported logging level: " << static_cast<int>(severity);
    // This return won't be hit but compiler needs it.
    return GLOG_FATAL;
  }
}

#endif

void RayLog::StartRayLog(const std::string &app_name, RayLogLevel severity_threshold,
                         const std::string &log_dir) {
  const char *var_value = getenv("RAY_BACKEND_LOG_LEVEL");
  if (var_value != nullptr) {
    std::string data = var_value;
    std::transform(data.begin(), data.end(), data.begin(), ::tolower);
    if (data == "debug") {
      severity_threshold = RayLogLevel::DEBUG;
    } else if (data == "info") {
      severity_threshold = RayLogLevel::INFO;
    } else if (data == "warning") {
      severity_threshold = RayLogLevel::WARNING;
    } else if (data == "error") {
      severity_threshold = RayLogLevel::ERROR;
    } else if (data == "fatal") {
      severity_threshold = RayLogLevel::FATAL;
    } else {
      RAY_LOG(WARNING) << "Unrecognized setting of RAY_BACKEND_LOG_LEVEL=" << var_value;
    }
    RAY_LOG(INFO) << "Set ray log level from environment variable RAY_BACKEND_LOG_LEVEL"
                  << " to " << static_cast<int>(severity_threshold);
  }
  severity_threshold_ = severity_threshold;
  app_name_ = app_name;
  log_dir_ = log_dir;
#ifdef RAY_USE_GLOG
  google::InitGoogleLogging(app_name_.c_str());
  // Enable log file if log_dir_ is not empty.
  std::string dir_ends_with_slash = log_dir_;
  if (!ray::IsDirSep(log_dir_[log_dir_.length() - 1])) {
    dir_ends_with_slash += ray::GetDirSep();
  }
  if (!log_dir_.empty()) {
    std::string app_name_without_path = app_name;
    if (app_name.empty()) {
      app_name_without_path = "DefaultApp";
    } else {
      // Find the app name without the path.
      std::string app_file_name = ray::GetFileName(app_name);
      if (!app_file_name.empty()) {
        app_name_without_path = app_file_name;
      }
    }
    google::SetLogFilenameExtension((app_name_without_path + ".log.").c_str());
  }
  for (int lvl = 0; lvl < NUM_SEVERITIES; ++lvl) {
    if (log_dir_.empty()) {
      google::SetStderrLogging(lvl);
      google::base::SetLogger(lvl, &stdout_logger_singleton);
    } else {
      std::string prefix = dir_ends_with_slash + LogSeverityNames[lvl] + '.';
      google::SetLogDestination(lvl, prefix.c_str());
    }
  }
#endif
}

void RayLog::UninstallSignalAction() {
#ifdef RAY_USE_GLOG
  if (!is_failure_signal_handler_installed_) {
    return;
  }
  RAY_LOG(DEBUG) << "Uninstall signal handlers.";
  // This signal list comes from glog's signalhandler.cc.
  // https://github.com/google/glog/blob/master/src/signalhandler.cc#L58-L70
  std::vector<int> installed_signals({SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM});
#ifdef _WIN32  // Do NOT use WIN32 (without the underscore); we want _WIN32 here
  for (int signal_num : installed_signals) {
    RAY_CHECK(signal(signal_num, SIG_DFL) != SIG_ERR);
  }
#else
  struct sigaction sig_action;
  memset(&sig_action, 0, sizeof(sig_action));
  sigemptyset(&sig_action.sa_mask);
  sig_action.sa_handler = SIG_DFL;
  for (int signal_num : installed_signals) {
    RAY_CHECK(sigaction(signal_num, &sig_action, NULL) == 0);
  }
#endif
  is_failure_signal_handler_installed_ = false;
#endif
}

void RayLog::ShutDownRayLog() {
#ifdef RAY_USE_GLOG
  UninstallSignalAction();
  google::ShutdownGoogleLogging();
#endif
}

void RayLog::InstallFailureSignalHandler() {
#ifdef _WIN32
  // If process fails to initialize, don't display an error window.
  SetErrorMode(GetErrorMode() | SEM_FAILCRITICALERRORS);
  // If process crashes, don't display an error window.
  SetErrorMode(GetErrorMode() | SEM_NOGPFAULTERRORBOX);
#endif
#ifdef RAY_USE_GLOG
  if (is_failure_signal_handler_installed_) {
    return;
  }
  google::InstallFailureSignalHandler();
  is_failure_signal_handler_installed_ = true;
#endif
}

bool RayLog::IsLevelEnabled(RayLogLevel log_level) {
  return log_level >= severity_threshold_;
}

RayLog::RayLog(const char *file_name, int line_number, RayLogLevel severity)
    // glog does not have DEBUG level, we can handle it using is_enabled_.
    : logging_provider_(nullptr), is_enabled_(severity >= severity_threshold_) {
#ifdef RAY_USE_GLOG
  if (is_enabled_) {
    logging_provider_ =
        new google::LogMessage(file_name, line_number, GetMappedSeverity(severity));
  }
#else
  auto logging_provider = new CerrLog(severity);
  *logging_provider << file_name << ":" << line_number << ": ";
  logging_provider_ = logging_provider;
#endif
}

std::ostream &RayLog::Stream() {
  auto logging_provider = reinterpret_cast<LoggingProvider *>(logging_provider_);
#ifdef RAY_USE_GLOG
  // Before calling this function, user should check IsEnabled.
  // When IsEnabled == false, logging_provider_ will be empty.
  return logging_provider->stream();
#else
  return logging_provider->Stream();
#endif
}

bool RayLog::IsEnabled() const { return is_enabled_; }

RayLog::~RayLog() {
  if (logging_provider_ != nullptr) {
    delete reinterpret_cast<LoggingProvider *>(logging_provider_);
    logging_provider_ = nullptr;
  }
}

}  // namespace ray
<|endoftext|>


<commit_before>#include <thread>

#include "reactor.h"

const std::string reactor::KEY_TIMER = "timer";

reactor::reactor(std::shared_ptr<zmq::context_t> context)
	: context_(context), async_handler_socket_(*context, zmq::socket_type::router),
	  unique_id("reactor_" + std::to_string((uintptr_t) this))
{
	async_handler_socket_.bind("inproc://" + unique_id);
}

void reactor::add_socket(const std::string &name, std::shared_ptr<socket_wrapper_base> socket)
{
	sockets_.emplace(name, socket);
}

void reactor::add_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<handler_wrapper>(*this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::add_async_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<asynchronous_handler_wrapper>(*context_, async_handler_socket_, *this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::send_message(const message_container &message)
{
	auto it = sockets_.find(message.key);

	// If there is a matching socket, send the message there. If not, let the reactor handle it
	if (it != std::end(sockets_)) {
		it->second->send_message(message);
	} else {
		process_message(message);
	}
}

void reactor::process_message(const message_container &message)
{
	auto range = handlers_.equal_range(message.key);

	for (auto it = range.first; it != range.second; ++it) {
		(*it->second)(message);
	}
}

void reactor::start_loop()
{
	std::vector<zmq::pollitem_t> pollitems;
	std::vector<std::string> pollitem_names;

	// Poll all registered sockets
	for (auto it : sockets_) {
		it.second->initialize();
		pollitems.push_back(it.second->get_pollitem());
		pollitem_names.push_back(it.first);
	}

	// Also poll the internal socket for asynchronous communication
	pollitems.push_back(
		zmq_pollitem_t{.socket = (void *) async_handler_socket_, .fd = 0, .events = ZMQ_POLLIN, .revents = 0});

	termination_flag_.store(false);

	// Enter the poll loop
	while (!termination_flag_.load()) {
		auto time_before_poll = std::chrono::system_clock::now();
		zmq::poll(pollitems, std::chrono::milliseconds(100));
		auto time_after_poll = std::chrono::system_clock::now();

		auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(time_after_poll - time_before_poll);

		size_t i = 0;
		for (auto item : pollitems) {
			if (item.revents & ZMQ_POLLIN) {
				message_container received_msg;

				if (i < pollitem_names.size()) {
					// message came from a registered socket, fill in its key
					received_msg.key = pollitem_names.at(i);
					sockets_.at(received_msg.key)->receive_message(received_msg);
				} else {
					// message from the asynchronous handler socket
					zmq::message_t zmessage;

					async_handler_socket_.recv(&zmessage);
					received_msg.key = std::string(static_cast<char *>(zmessage.data()), zmessage.size());

					async_handler_socket_.recv(&zmessage);
					received_msg.identity = std::string(static_cast<char *>(zmessage.data()), zmessage.size());

					while (zmessage.more()) {
						received_msg.data.emplace_back(static_cast<char *>(zmessage.data()), zmessage.size());
					}
				}

				process_message(received_msg);
			}

			++i;
		}

		message_container timer_msg;
		timer_msg.key = KEY_TIMER;
		timer_msg.data.push_back(std::to_string(elapsed_time.count()));

		process_message(timer_msg);
	}

	handlers_.clear();
}

void reactor::terminate ()
{
	termination_flag_.store(true);
}

handler_wrapper::handler_wrapper(reactor &reactor_ref, std::shared_ptr<handler_interface> handler)
	: handler_(handler), reactor_(reactor_ref)
{
}

handler_wrapper::~handler_wrapper()
{
}

void handler_wrapper::operator()(const message_container &message)
{
	handler_->on_request(message, [this](const message_container &response) { reactor_.send_message(response); });
}

const std::string asynchronous_handler_wrapper::TERMINATE_MSG = "TERMINATE";

asynchronous_handler_wrapper::asynchronous_handler_wrapper(zmq::context_t &context,
	zmq::socket_t &async_handler_socket,
	reactor &reactor_ref,
	std::shared_ptr<handler_interface> handler)
	: handler_wrapper(reactor_ref, handler), reactor_socket_(async_handler_socket),
	  unique_id_(std::to_string((uintptr_t) this)), handler_thread_socket_(context, zmq::socket_type::dealer)
{
	worker_ = std::thread([this]() { handler_thread(); });
}

asynchronous_handler_wrapper::~asynchronous_handler_wrapper()
{
	// Send a message to terminate the worker thread
	reactor_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	reactor_socket_.send(TERMINATE_MSG.data(), TERMINATE_MSG.size());

	// Join it
	worker_.join();
}

void asynchronous_handler_wrapper::operator()(const message_container &message)
{
	reactor_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	reactor_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		reactor_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}

void asynchronous_handler_wrapper::handler_thread()
{
	handler_thread_socket_.setsockopt(ZMQ_IDENTITY, unique_id_.data(), unique_id_.size());
	handler_thread_socket_.connect("inproc://" + reactor_.unique_id);

	while (true) {
		message_container request;
		zmq::message_t message;

		handler_thread_socket_.recv(&message, 0);
		request.key = std::string(static_cast<char *>(message.data()), message.size());

		if (request.key == TERMINATE_MSG) {
			return;
		}

		if (!message.more()) {
			continue;
		}

		handler_thread_socket_.recv(&message, 0);
		request.identity = std::string(static_cast<char *>(message.data()), message.size());

		while (message.more()) {
			handler_thread_socket_.recv(&message, 0);
			request.data.emplace_back(static_cast<char *>(message.data()), message.size());
		}

		handler_->on_request(request, [this](const message_container &response) { send_response(response); });
	}
}

void asynchronous_handler_wrapper::send_response(const message_container &message)
{
	handler_thread_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		handler_thread_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}
<commit_msg>coding standard<commit_after>#include <thread>

#include "reactor.h"

const std::string reactor::KEY_TIMER = "timer";

reactor::reactor(std::shared_ptr<zmq::context_t> context)
	: context_(context), async_handler_socket_(*context, zmq::socket_type::router),
	  unique_id("reactor_" + std::to_string((uintptr_t) this))
{
	async_handler_socket_.bind("inproc://" + unique_id);
}

void reactor::add_socket(const std::string &name, std::shared_ptr<socket_wrapper_base> socket)
{
	sockets_.emplace(name, socket);
}

void reactor::add_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<handler_wrapper>(*this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::add_async_handler(const std::vector<std::string> &origins, std::shared_ptr<handler_interface> handler)
{
	auto wrapper = std::make_shared<asynchronous_handler_wrapper>(*context_, async_handler_socket_, *this, handler);

	for (auto &origin : origins) {
		handlers_.emplace(origin, wrapper);
	}
}

void reactor::send_message(const message_container &message)
{
	auto it = sockets_.find(message.key);

	// If there is a matching socket, send the message there. If not, let the reactor handle it
	if (it != std::end(sockets_)) {
		it->second->send_message(message);
	} else {
		process_message(message);
	}
}

void reactor::process_message(const message_container &message)
{
	auto range = handlers_.equal_range(message.key);

	for (auto it = range.first; it != range.second; ++it) {
		(*it->second)(message);
	}
}

void reactor::start_loop()
{
	std::vector<zmq::pollitem_t> pollitems;
	std::vector<std::string> pollitem_names;

	// Poll all registered sockets
	for (auto it : sockets_) {
		it.second->initialize();
		pollitems.push_back(it.second->get_pollitem());
		pollitem_names.push_back(it.first);
	}

	// Also poll the internal socket for asynchronous communication
	pollitems.push_back(
		zmq_pollitem_t{.socket = (void *) async_handler_socket_, .fd = 0, .events = ZMQ_POLLIN, .revents = 0});

	termination_flag_.store(false);

	// Enter the poll loop
	while (!termination_flag_.load()) {
		auto time_before_poll = std::chrono::system_clock::now();
		zmq::poll(pollitems, std::chrono::milliseconds(100));
		auto time_after_poll = std::chrono::system_clock::now();

		auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(time_after_poll - time_before_poll);

		size_t i = 0;
		for (auto item : pollitems) {
			if (item.revents & ZMQ_POLLIN) {
				message_container received_msg;

				if (i < pollitem_names.size()) {
					// message came from a registered socket, fill in its key
					received_msg.key = pollitem_names.at(i);
					sockets_.at(received_msg.key)->receive_message(received_msg);
				} else {
					// message from the asynchronous handler socket
					zmq::message_t zmessage;

					async_handler_socket_.recv(&zmessage);
					received_msg.key = std::string(static_cast<char *>(zmessage.data()), zmessage.size());

					async_handler_socket_.recv(&zmessage);
					received_msg.identity = std::string(static_cast<char *>(zmessage.data()), zmessage.size());

					while (zmessage.more()) {
						received_msg.data.emplace_back(static_cast<char *>(zmessage.data()), zmessage.size());
					}
				}

				process_message(received_msg);
			}

			++i;
		}

		message_container timer_msg;
		timer_msg.key = KEY_TIMER;
		timer_msg.data.push_back(std::to_string(elapsed_time.count()));

		process_message(timer_msg);
	}

	handlers_.clear();
}

void reactor::terminate()
{
	termination_flag_.store(true);
}

handler_wrapper::handler_wrapper(reactor &reactor_ref, std::shared_ptr<handler_interface> handler)
	: handler_(handler), reactor_(reactor_ref)
{
}

handler_wrapper::~handler_wrapper()
{
}

void handler_wrapper::operator()(const message_container &message)
{
	handler_->on_request(message, [this](const message_container &response) { reactor_.send_message(response); });
}

const std::string asynchronous_handler_wrapper::TERMINATE_MSG = "TERMINATE";

asynchronous_handler_wrapper::asynchronous_handler_wrapper(zmq::context_t &context,
	zmq::socket_t &async_handler_socket,
	reactor &reactor_ref,
	std::shared_ptr<handler_interface> handler)
	: handler_wrapper(reactor_ref, handler), reactor_socket_(async_handler_socket),
	  unique_id_(std::to_string((uintptr_t) this)), handler_thread_socket_(context, zmq::socket_type::dealer)
{
	worker_ = std::thread([this]() { handler_thread(); });
}

asynchronous_handler_wrapper::~asynchronous_handler_wrapper()
{
	// Send a message to terminate the worker thread
	reactor_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	reactor_socket_.send(TERMINATE_MSG.data(), TERMINATE_MSG.size());

	// Join it
	worker_.join();
}

void asynchronous_handler_wrapper::operator()(const message_container &message)
{
	reactor_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	reactor_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		reactor_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}

void asynchronous_handler_wrapper::handler_thread()
{
	handler_thread_socket_.setsockopt(ZMQ_IDENTITY, unique_id_.data(), unique_id_.size());
	handler_thread_socket_.connect("inproc://" + reactor_.unique_id);

	while (true) {
		message_container request;
		zmq::message_t message;

		handler_thread_socket_.recv(&message, 0);
		request.key = std::string(static_cast<char *>(message.data()), message.size());

		if (request.key == TERMINATE_MSG) {
			return;
		}

		if (!message.more()) {
			continue;
		}

		handler_thread_socket_.recv(&message, 0);
		request.identity = std::string(static_cast<char *>(message.data()), message.size());

		while (message.more()) {
			handler_thread_socket_.recv(&message, 0);
			request.data.emplace_back(static_cast<char *>(message.data()), message.size());
		}

		handler_->on_request(request, [this](const message_container &response) { send_response(response); });
	}
}

void asynchronous_handler_wrapper::send_response(const message_container &message)
{
	handler_thread_socket_.send(unique_id_.data(), unique_id_.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.key.data(), message.key.size(), ZMQ_SNDMORE);
	handler_thread_socket_.send(message.identity.data(), message.identity.size(), ZMQ_SNDMORE);

	for (auto it = std::begin(message.data); it != std::end(message.data); ++it) {
		handler_thread_socket_.send(it->c_str(), it->size(), std::next(it) != std::end(message.data) ? ZMQ_SNDMORE : 0);
	}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_TIMESTAMP_HPP
#define REALM_TIMESTAMP_HPP

#include <stdint.h>
#include <ostream>
#include <realm/util/assert.hpp>

namespace realm {

struct Timestamp {
    Timestamp(int64_t seconds, uint32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false)
    {
        REALM_ASSERT_3(nanoseconds, <, nanoseconds_per_second);
    }
    Timestamp() : m_is_null(true) { }

    bool is_null() const { return m_is_null; }

    int64_t get_seconds() const noexcept
    {
        return m_seconds;
    }

    uint32_t get_nanoseconds() const noexcept
    {
        return m_nanoseconds;
    }

    // Note that these operators do not work if one of the Timestamps are null! Please use realm::Greater, realm::Equal
    // etc instead. This is in order to collect all treatment of null behaviour in a single place for all
    // types (query_conditions.hpp) to ensure that all types sort and compare null vs. non-null in the same manner,
    // especially for int/float where we cannot override operators. This design is open for discussion, though, because
    // it has usability drawbacks
    bool operator==(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator!=(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator>(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator<(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    bool operator<=(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return *this < rhs || *this == rhs; }
    bool operator>=(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return *this > rhs || *this == rhs; }
    Timestamp& operator=(const Timestamp& rhs) = default;

    template<class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out, const Timestamp&);
    static constexpr uint32_t nanoseconds_per_second = 1000000000;

private:
    int64_t m_seconds;
    uint32_t m_nanoseconds;
    bool m_is_null;
};

template<class C, class T>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const Timestamp& d)
{
    out << "Timestamp(" << d.m_seconds << ", " << d.m_nanoseconds << ")";
    return out;
}

} // namespace realm

#endif // REALM_TIMESTAMP_HPP
<commit_msg>Added asserts for only getting seconds and nanoseconds from non-null Timestamps<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_TIMESTAMP_HPP
#define REALM_TIMESTAMP_HPP

#include <stdint.h>
#include <ostream>
#include <realm/util/assert.hpp>

namespace realm {

struct Timestamp {
    Timestamp(int64_t seconds, uint32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false)
    {
        REALM_ASSERT_3(nanoseconds, <, nanoseconds_per_second);
    }
    Timestamp() : m_is_null(true) { }

    bool is_null() const { return m_is_null; }

    int64_t get_seconds() const noexcept
    {
        REALM_ASSERT(!m_is_null);
        return m_seconds;
    }

    uint32_t get_nanoseconds() const noexcept
    {
        REALM_ASSERT(!m_is_null);
        return m_nanoseconds;
    }

    // Note that these operators do not work if one of the Timestamps are null! Please use realm::Greater, realm::Equal
    // etc instead. This is in order to collect all treatment of null behaviour in a single place for all
    // types (query_conditions.hpp) to ensure that all types sort and compare null vs. non-null in the same manner,
    // especially for int/float where we cannot override operators. This design is open for discussion, though, because
    // it has usability drawbacks
    bool operator==(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator!=(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator>(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator<(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    bool operator<=(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return *this < rhs || *this == rhs; }
    bool operator>=(const Timestamp& rhs) const { REALM_ASSERT(!is_null()); REALM_ASSERT(!rhs.is_null()); return *this > rhs || *this == rhs; }
    Timestamp& operator=(const Timestamp& rhs) = default;

    template<class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out, const Timestamp&);
    static constexpr uint32_t nanoseconds_per_second = 1000000000;

private:
    int64_t m_seconds;
    uint32_t m_nanoseconds;
    bool m_is_null;
};

template<class C, class T>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const Timestamp& d)
{
    out << "Timestamp(" << d.m_seconds << ", " << d.m_nanoseconds << ")";
    return out;
}

} // namespace realm

#endif // REALM_TIMESTAMP_HPP
<|endoftext|>