<commit_before>#include "../lelantus.h"
#include "../validation.h"
#include "../wallet/wallet.h"

#include "automintmodel.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "lelantusmodel.h"

IncomingFundNotifier::IncomingFundNotifier(
    CWallet *_wallet, QObject *parent) :
    QObject(parent), wallet(_wallet), timer(0)
{
    timer = new QTimer(this);
    timer->setSingleShot(true);

    connect(timer,
        SIGNAL(timeout()),
        this,
        SLOT(check()),
        Qt::QueuedConnection);

    importTransactions();
    subscribeToCoreSignals();
}

IncomingFundNotifier::~IncomingFundNotifier()
{
    unsubscribeFromCoreSignals();

    delete timer;

    timer = nullptr;
}

void IncomingFundNotifier::newBlock()
{
    LOCK(cs);

    if (!txs.empty()) {
        resetTimer();
    }
}

void IncomingFundNotifier::pushTransaction(uint256 const &id)
{
    LOCK(cs);

    txs.push_back(id);
    resetTimer();
}

void IncomingFundNotifier::check()
{
    LOCK(cs);

    if (txs.empty()) {
        return;
    }

    CAmount credit = 0;
    std::vector<uint256> immatures;

    {
        LOCK2(cs_main, wallet->cs_wallet);
        while (!txs.empty()) {
            auto const &tx = txs.back();
            txs.pop_back();

            auto wtx = wallet->mapWallet.find(tx);
            if (wtx == wallet->mapWallet.end()) {
                continue;
            }

            credit += std::max(CAmount(0), wtx->second.GetAvailableCredit() - wtx->second.GetDebit(ISMINE_ALL));

            if (wtx->second.GetImmatureCredit() > 0) {
                immatures.push_back(tx);
            }
        }
    }

    for (auto const &tx : immatures) {
        txs.push_back(tx);
    }

    if (credit > 0) {
        Q_EMIT matureFund(credit);
    }
}

void IncomingFundNotifier::importTransactions()
{
    LOCK(cs);
    LOCK2(cs_main, wallet->cs_wallet);

    for (auto const &tx : wallet->mapWallet) {
        if (tx.second.GetAvailableCredit() > 0 || tx.second.GetImmatureCredit() > 0) {
            txs.push_back(tx.first);
        }
    }

    resetTimer();
}

void IncomingFundNotifier::resetTimer()
{
    timer->stop();
    timer->start(1000);
}

// Handlers for core signals
static void NotifyTransactionChanged(
    IncomingFundNotifier *model, CWallet *wallet, uint256 const &hash, ChangeType status)
{
    Q_UNUSED(wallet);
    Q_UNUSED(status);
    if (status == ChangeType::CT_NEW || status == ChangeType::CT_UPDATED) {
        QMetaObject::invokeMethod(
            model,
            "pushTransaction",
            Qt::QueuedConnection,
            Q_ARG(uint256, hash));
    }
}

static void IncomingFundNotifyBlockTip(
    IncomingFundNotifier *model, bool initialSync, const CBlockIndex *pIndex)
{
    Q_UNUSED(initialSync);
    Q_UNUSED(pIndex);
    QMetaObject::invokeMethod(
        model,
        "newBlock",
        Qt::QueuedConnection);
}

void IncomingFundNotifier::subscribeToCoreSignals()
{
    wallet->NotifyTransactionChanged.connect(boost::bind(
        NotifyTransactionChanged, this, _1, _2, _3));

    uiInterface.NotifyBlockTip.connect(
        boost::bind(IncomingFundNotifyBlockTip, this, _1, _2));
}

void IncomingFundNotifier::unsubscribeFromCoreSignals()
{
    wallet->NotifyTransactionChanged.disconnect(boost::bind(
        NotifyTransactionChanged, this, _1, _2, _3));

    uiInterface.NotifyBlockTip.disconnect(
        boost::bind(IncomingFundNotifyBlockTip, this, _1, _2));
}

AutoMintModel::AutoMintModel(
    LelantusModel *_lelantusModel,
    OptionsModel *_optionsModel,
    CWallet *_wallet,
    QObject *parent) :
    QObject(parent),
    lelantusModel(_lelantusModel),
    optionsModel(_optionsModel),
    wallet(_wallet),
    autoMintState(AutoMintState::Disabled),
    resetSyncingTimer(0),
    autoMintCheckTimer(0),
    syncing(false),
    notifier(0)
{
    resetSyncingTimer = new QTimer(this);
    resetSyncingTimer->setSingleShot(true);

    autoMintCheckTimer = new QTimer(this);
    autoMintCheckTimer->setSingleShot(false);

    connect(resetSyncingTimer, SIGNAL(timeout()), this, SLOT(resetSyncing()));
    connect(autoMintCheckTimer, SIGNAL(timeout()), this, SLOT(checkAutoMint()));

    notifier = new IncomingFundNotifier(wallet, this);

    connect(notifier, SIGNAL(matureFund(CAmount)), this, SLOT(startAutoMint()));

    connect(optionsModel,
        SIGNAL(autoAnonymizeChanged(bool)),
        this,
        SLOT(updateAutoMintOption(bool)));

    subscribeToCoreSignals();
}

AutoMintModel::~AutoMintModel()
{
    unsubscribeFromCoreSignals();

    delete resetSyncingTimer;
    delete autoMintCheckTimer;

    resetSyncingTimer = nullptr;
    autoMintCheckTimer = nullptr;
}

bool AutoMintModel::askingUser() const
{
    return autoMintState == AutoMintState::WaitingForUserResponse;
}

void AutoMintModel::userAskToMint()
{
    autoMintCheckTimer->stop();
    checkAutoMint(true);
}

void AutoMintModel::ackMintAll(AutoMintAck ack, CAmount minted, QString error)
{
    LOCK(lelantusModel->cs);
    if (ack == AutoMintAck::WaitUserToActive) {
        autoMintState = AutoMintState::WaitingUserToActivate;
    } else {
        autoMintState = AutoMintState::WaitingIncomingFund;
        autoMintCheckTimer->stop();
    }

    processAutoMintAck(ack, minted, error);
}

void AutoMintModel::checkAutoMint(bool force)
{
    // if lelantus is not allow or client is in initial syncing state then wait
    // except user force to check
    if (!force) {
        // check syncing first to reduce main locking
        if (syncing) {
            return;
        }

        bool allowed = lelantus::IsLelantusAllowed();
        if (!allowed) {
            return;
        }
    }

    {
        LOCK(lelantusModel->cs);

        if (fReindex) {
            return;
        }

        switch (autoMintState) {
        case AutoMintState::Disabled:
        case AutoMintState::WaitingIncomingFund:
            if (force) {
                break;
            }
            autoMintCheckTimer->stop();
            return;
        case AutoMintState::WaitingUserToActivate:
            break;
        case AutoMintState::WaitingForUserResponse:
            return;
        default:
            throw std::runtime_error("Unknown auto mint state");
        }

        autoMintState = AutoMintState::WaitingForUserResponse;
    }

    lelantusModel->askUserToMint(force);
}

void AutoMintModel::setSyncing()
{
    syncing.store(true);
    resetSyncingTimer->stop();

    // wait 2.5 seconds if there are no new signal then reset flag
    resetSyncingTimer->start(2500);
}

void AutoMintModel::resetSyncing()
{
    syncing.store(false);
}

void AutoMintModel::startAutoMint()
{
    if (autoMintCheckTimer->isActive()) {
        return;
    }

    CAmount mintable = 0;
    {
        LOCK2(cs_main, wallet->cs_wallet);
        mintable = lelantusModel->getMintableAmount();
    }

    if (mintable > 0) {
        autoMintState = AutoMintState::WaitingUserToActivate;

        autoMintCheckTimer->start(MODEL_UPDATE_DELAY);
    } else {
        autoMintState = AutoMintState::WaitingIncomingFund;
    }
}

void AutoMintModel::updateAutoMintOption(bool enabled)
{
    LOCK2(cs_main, wallet->cs_wallet);
    LOCK(lelantusModel->cs);

    if (enabled) {
        if (autoMintState == AutoMintState::Disabled) {
            startAutoMint();
        }
    } else {
        if (autoMintCheckTimer->isActive()) {
            autoMintCheckTimer->stop();
        }

        // stop mint
        autoMintState = AutoMintState::Disabled;
    }
}

// Handlers for core signals
static void NotifyBlockTip(AutoMintModel *model, bool initialSync, const CBlockIndex *pIndex)
{
    Q_UNUSED(pIndex);
    Q_UNUSED(initialSync);
    QMetaObject::invokeMethod(
        model,
        "setSyncing",
        Qt::QueuedConnection);
}

void AutoMintModel::subscribeToCoreSignals()
{
    uiInterface.NotifyBlockTip.connect(
        boost::bind(NotifyBlockTip, this, _1, _2));
}

void AutoMintModel::unsubscribeFromCoreSignals()
{
    uiInterface.NotifyBlockTip.disconnect(
        boost::bind(NotifyBlockTip, this, _1, _2));
}

void AutoMintModel::processAutoMintAck(AutoMintAck ack, CAmount minted, QString error)
{
    QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
    msgParams.second = CClientUIInterface::MSG_WARNING;

    switch (ack)
    {
    case AutoMintAck::Success:
        msgParams.first = tr("Success to anonymize, %1")
            .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), minted));
        msgParams.second = CClientUIInterface::MSG_INFORMATION;
        break;
    case AutoMintAck::WaitUserToActive:
    case AutoMintAck::NotEnoughFund:
        return;
    case AutoMintAck::FailToMint:
        msgParams.first = tr("Fail to mint, %1").arg(error);
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    case AutoMintAck::FailToUnlock:
        msgParams.first = tr("Fail to unlock wallet");
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    default:
        return;
    };

    Q_EMIT message(tr("Auto Anonymize"), msgParams.first, msgParams.second);
}<commit_msg>Add guard to prevent automint if the flag is not set<commit_after>#include "../lelantus.h"
#include "../validation.h"
#include "../wallet/wallet.h"

#include "automintmodel.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "lelantusmodel.h"

IncomingFundNotifier::IncomingFundNotifier(
    CWallet *_wallet, QObject *parent) :
    QObject(parent), wallet(_wallet), timer(0)
{
    timer = new QTimer(this);
    timer->setSingleShot(true);

    connect(timer,
        SIGNAL(timeout()),
        this,
        SLOT(check()),
        Qt::QueuedConnection);

    importTransactions();
    subscribeToCoreSignals();
}

IncomingFundNotifier::~IncomingFundNotifier()
{
    unsubscribeFromCoreSignals();

    delete timer;

    timer = nullptr;
}

void IncomingFundNotifier::newBlock()
{
    LOCK(cs);

    if (!txs.empty()) {
        resetTimer();
    }
}

void IncomingFundNotifier::pushTransaction(uint256 const &id)
{
    LOCK(cs);

    txs.push_back(id);
    resetTimer();
}

void IncomingFundNotifier::check()
{
    LOCK(cs);

    if (txs.empty()) {
        return;
    }

    CAmount credit = 0;
    std::vector<uint256> immatures;

    {
        LOCK2(cs_main, wallet->cs_wallet);
        while (!txs.empty()) {
            auto const &tx = txs.back();
            txs.pop_back();

            auto wtx = wallet->mapWallet.find(tx);
            if (wtx == wallet->mapWallet.end()) {
                continue;
            }

            credit += std::max(CAmount(0), wtx->second.GetAvailableCredit() - wtx->second.GetDebit(ISMINE_ALL));

            if (wtx->second.GetImmatureCredit() > 0) {
                immatures.push_back(tx);
            }
        }
    }

    for (auto const &tx : immatures) {
        txs.push_back(tx);
    }

    if (credit > 0) {
        Q_EMIT matureFund(credit);
    }
}

void IncomingFundNotifier::importTransactions()
{
    LOCK(cs);
    LOCK2(cs_main, wallet->cs_wallet);

    for (auto const &tx : wallet->mapWallet) {
        if (tx.second.GetAvailableCredit() > 0 || tx.second.GetImmatureCredit() > 0) {
            txs.push_back(tx.first);
        }
    }

    resetTimer();
}

void IncomingFundNotifier::resetTimer()
{
    timer->stop();
    timer->start(1000);
}

// Handlers for core signals
static void NotifyTransactionChanged(
    IncomingFundNotifier *model, CWallet *wallet, uint256 const &hash, ChangeType status)
{
    Q_UNUSED(wallet);
    Q_UNUSED(status);
    if (status == ChangeType::CT_NEW || status == ChangeType::CT_UPDATED) {
        QMetaObject::invokeMethod(
            model,
            "pushTransaction",
            Qt::QueuedConnection,
            Q_ARG(uint256, hash));
    }
}

static void IncomingFundNotifyBlockTip(
    IncomingFundNotifier *model, bool initialSync, const CBlockIndex *pIndex)
{
    Q_UNUSED(initialSync);
    Q_UNUSED(pIndex);
    QMetaObject::invokeMethod(
        model,
        "newBlock",
        Qt::QueuedConnection);
}

void IncomingFundNotifier::subscribeToCoreSignals()
{
    wallet->NotifyTransactionChanged.connect(boost::bind(
        NotifyTransactionChanged, this, _1, _2, _3));

    uiInterface.NotifyBlockTip.connect(
        boost::bind(IncomingFundNotifyBlockTip, this, _1, _2));
}

void IncomingFundNotifier::unsubscribeFromCoreSignals()
{
    wallet->NotifyTransactionChanged.disconnect(boost::bind(
        NotifyTransactionChanged, this, _1, _2, _3));

    uiInterface.NotifyBlockTip.disconnect(
        boost::bind(IncomingFundNotifyBlockTip, this, _1, _2));
}

AutoMintModel::AutoMintModel(
    LelantusModel *_lelantusModel,
    OptionsModel *_optionsModel,
    CWallet *_wallet,
    QObject *parent) :
    QObject(parent),
    lelantusModel(_lelantusModel),
    optionsModel(_optionsModel),
    wallet(_wallet),
    autoMintState(AutoMintState::Disabled),
    resetSyncingTimer(0),
    autoMintCheckTimer(0),
    syncing(false),
    notifier(0)
{
    resetSyncingTimer = new QTimer(this);
    resetSyncingTimer->setSingleShot(true);

    autoMintCheckTimer = new QTimer(this);
    autoMintCheckTimer->setSingleShot(false);

    connect(resetSyncingTimer, SIGNAL(timeout()), this, SLOT(resetSyncing()));
    connect(autoMintCheckTimer, SIGNAL(timeout()), this, SLOT(checkAutoMint()));

    notifier = new IncomingFundNotifier(wallet, this);

    connect(notifier, SIGNAL(matureFund(CAmount)), this, SLOT(startAutoMint()));

    connect(optionsModel,
        SIGNAL(autoAnonymizeChanged(bool)),
        this,
        SLOT(updateAutoMintOption(bool)));

    subscribeToCoreSignals();
}

AutoMintModel::~AutoMintModel()
{
    unsubscribeFromCoreSignals();

    delete resetSyncingTimer;
    delete autoMintCheckTimer;

    resetSyncingTimer = nullptr;
    autoMintCheckTimer = nullptr;
}

bool AutoMintModel::askingUser() const
{
    return autoMintState == AutoMintState::WaitingForUserResponse;
}

void AutoMintModel::userAskToMint()
{
    autoMintCheckTimer->stop();
    checkAutoMint(true);
}

void AutoMintModel::ackMintAll(AutoMintAck ack, CAmount minted, QString error)
{
    LOCK(lelantusModel->cs);
    if (ack == AutoMintAck::WaitUserToActive) {
        autoMintState = AutoMintState::WaitingUserToActivate;
    } else {
        autoMintState = AutoMintState::WaitingIncomingFund;
        autoMintCheckTimer->stop();
    }

    processAutoMintAck(ack, minted, error);
}

void AutoMintModel::checkAutoMint(bool force)
{
    // if lelantus is not allow or client is in initial syncing state then wait
    // except user force to check
    if (!force) {
        // check syncing first to reduce main locking
        if (syncing) {
            return;
        }

        bool allowed = lelantus::IsLelantusAllowed();
        if (!allowed) {
            return;
        }
    }

    {
        LOCK(lelantusModel->cs);

        if (fReindex) {
            return;
        }

        switch (autoMintState) {
        case AutoMintState::Disabled:
        case AutoMintState::WaitingIncomingFund:
            if (force) {
                break;
            }
            autoMintCheckTimer->stop();
            return;
        case AutoMintState::WaitingUserToActivate:
            break;
        case AutoMintState::WaitingForUserResponse:
            return;
        default:
            throw std::runtime_error("Unknown auto mint state");
        }

        autoMintState = AutoMintState::WaitingForUserResponse;
    }

    lelantusModel->askUserToMint(force);
}

void AutoMintModel::setSyncing()
{
    syncing.store(true);
    resetSyncingTimer->stop();

    // wait 2.5 seconds if there are no new signal then reset flag
    resetSyncingTimer->start(2500);
}

void AutoMintModel::resetSyncing()
{
    syncing.store(false);
}

void AutoMintModel::startAutoMint()
{
    if (autoMintCheckTimer->isActive()) {
        return;
    }

    if (!optionsModel->getAutoAnonymize()) {
        return;
    }

    CAmount mintable = 0;
    {
        LOCK2(cs_main, wallet->cs_wallet);
        mintable = lelantusModel->getMintableAmount();
    }

    if (mintable > 0) {
        autoMintState = AutoMintState::WaitingUserToActivate;

        autoMintCheckTimer->start(MODEL_UPDATE_DELAY);
    } else {
        autoMintState = AutoMintState::WaitingIncomingFund;
    }
}

void AutoMintModel::updateAutoMintOption(bool enabled)
{
    LOCK2(cs_main, wallet->cs_wallet);
    LOCK(lelantusModel->cs);

    if (enabled) {
        if (autoMintState == AutoMintState::Disabled) {
            startAutoMint();
        }
    } else {
        if (autoMintCheckTimer->isActive()) {
            autoMintCheckTimer->stop();
        }

        // stop mint
        autoMintState = AutoMintState::Disabled;
    }
}

// Handlers for core signals
static void NotifyBlockTip(AutoMintModel *model, bool initialSync, const CBlockIndex *pIndex)
{
    Q_UNUSED(pIndex);
    Q_UNUSED(initialSync);
    QMetaObject::invokeMethod(
        model,
        "setSyncing",
        Qt::QueuedConnection);
}

void AutoMintModel::subscribeToCoreSignals()
{
    uiInterface.NotifyBlockTip.connect(
        boost::bind(NotifyBlockTip, this, _1, _2));
}

void AutoMintModel::unsubscribeFromCoreSignals()
{
    uiInterface.NotifyBlockTip.disconnect(
        boost::bind(NotifyBlockTip, this, _1, _2));
}

void AutoMintModel::processAutoMintAck(AutoMintAck ack, CAmount minted, QString error)
{
    QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
    msgParams.second = CClientUIInterface::MSG_WARNING;

    switch (ack)
    {
    case AutoMintAck::Success:
        msgParams.first = tr("Success to anonymize, %1")
            .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), minted));
        msgParams.second = CClientUIInterface::MSG_INFORMATION;
        break;
    case AutoMintAck::WaitUserToActive:
    case AutoMintAck::NotEnoughFund:
        return;
    case AutoMintAck::FailToMint:
        msgParams.first = tr("Fail to mint, %1").arg(error);
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    case AutoMintAck::FailToUnlock:
        msgParams.first = tr("Fail to unlock wallet");
        msgParams.second = CClientUIInterface::MSG_ERROR;
        break;
    default:
        return;
    };

    Q_EMIT message(tr("Auto Anonymize"), msgParams.first, msgParams.second);
}<|endoftext|>


<commit_before>#include "Window.h"

#include <QFileDialog>
#include <QKeyEvent>
#include <QKeySequence>
#include <QMenuBar>

#include "GameController.h"
#include "GDBWindow.h"
#include "GDBController.h"

using namespace QGBA;

Window::Window(QWidget* parent)
	: QMainWindow(parent)
#ifdef USE_GDB_STUB
	, m_gdbController(nullptr)
#endif
{
	setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	setMinimumSize(240, 160);

	m_controller = new GameController(this);
	m_display = new Display();
	setCentralWidget(m_display);
	connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*)));
	connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing()));
	connect(m_controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(gameStopped()));
	connect(this, SIGNAL(startDrawing(const uint32_t*, GBAThread*)), m_display, SLOT(startDrawing(const uint32_t*, GBAThread*)), Qt::QueuedConnection);
	connect(this, SIGNAL(shutdown()), m_display, SLOT(stopDrawing()));
	connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int)));

	setupMenu(menuBar());
}

GBAKey Window::mapKey(int qtKey) {
	switch (qtKey) {
	case Qt::Key_Z:
		return GBA_KEY_A;
		break;
	case Qt::Key_X:
		return GBA_KEY_B;
		break;
	case Qt::Key_A:
		return GBA_KEY_L;
		break;
	case Qt::Key_S:
		return GBA_KEY_R;
		break;
	case Qt::Key_Return:
		return GBA_KEY_START;
		break;
	case Qt::Key_Backspace:
		return GBA_KEY_SELECT;
		break;
	case Qt::Key_Up:
		return GBA_KEY_UP;
		break;
	case Qt::Key_Down:
		return GBA_KEY_DOWN;
		break;
	case Qt::Key_Left:
		return GBA_KEY_LEFT;
		break;
	case Qt::Key_Right:
		return GBA_KEY_RIGHT;
		break;
	default:
		return GBA_KEY_NONE;
	}
}

void Window::selectROM() {
	QString filename = QFileDialog::getOpenFileName(this, tr("Select ROM"));
	if (!filename.isEmpty()) {
		m_controller->loadGame(filename);
	}
}

#ifdef USE_GDB_STUB
void Window::gdbOpen() {
	if (!m_gdbController) {
		m_gdbController = new GDBController(m_controller, this);
	}
	GDBWindow* window = new GDBWindow(m_gdbController);
	window->show();
}
#endif

void Window::keyPressEvent(QKeyEvent* event) {
	if (event->isAutoRepeat()) {
		QWidget::keyPressEvent(event);
		return;
	}
	GBAKey key = mapKey(event->key());
	if (key == GBA_KEY_NONE) {
		QWidget::keyPressEvent(event);
		return;
	}
	m_controller->keyPressed(key);
	event->accept();
}

void Window::keyReleaseEvent(QKeyEvent* event) {
	if (event->isAutoRepeat()) {
		QWidget::keyReleaseEvent(event);
		return;
	}
	GBAKey key = mapKey(event->key());
	if (key == GBA_KEY_NONE) {
		QWidget::keyPressEvent(event);
		return;
	}
	m_controller->keyReleased(key);
	event->accept();
}

void Window::closeEvent(QCloseEvent* event) {
	emit shutdown();
	QMainWindow::closeEvent(event);
}

void Window::gameStarted(GBAThread* context) {
	emit startDrawing(m_controller->drawContext(), context);
	foreach (QAction* action, m_gameActions) {
		action->setDisabled(false);
	}
}

void Window::gameStopped() {
	foreach (QAction* action, m_gameActions) {
		action->setDisabled(true);
	}
}

void Window::setBuffers512() {
	emit audioBufferSamplesChanged(512);
}

void Window::setBuffers1024() {
	emit audioBufferSamplesChanged(1024);
}

void Window::setBuffers2048() {
	emit audioBufferSamplesChanged(2048);
}

void Window::setBuffers4096() {
	emit audioBufferSamplesChanged(4096);
}

void Window::setupMenu(QMenuBar* menubar) {
	menubar->clear();
	QMenu* fileMenu = menubar->addMenu(tr("&File"));
	fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open);

	QMenu* emulationMenu = menubar->addMenu(tr("&Emulation"));
	QAction* reset = new QAction(tr("&Reset"), nullptr);
	reset->setShortcut(tr("Ctrl+R"));
	connect(reset, SIGNAL(triggered()), m_controller, SLOT(reset()));
	m_gameActions.append(reset);
	emulationMenu->addAction(reset);

	QAction* shutdown = new QAction(tr("Sh&utdown"), nullptr);
	connect(shutdown, SIGNAL(triggered()), m_controller, SLOT(closeGame()));
	m_gameActions.append(shutdown);
	emulationMenu->addAction(shutdown);
	emulationMenu->addSeparator();

	QAction* pause = new QAction(tr("&Pause"), nullptr);
	pause->setChecked(false);
	pause->setCheckable(true);
	pause->setShortcut(tr("Ctrl+P"));
	connect(pause, SIGNAL(triggered(bool)), m_controller, SLOT(setPaused(bool)));
	m_gameActions.append(pause);
	emulationMenu->addAction(pause);

	QAction* frameAdvance = new QAction(tr("&Next frame"), nullptr);
	frameAdvance->setShortcut(tr("Ctrl+N"));
	connect(frameAdvance, SIGNAL(triggered()), m_controller, SLOT(frameAdvance()));
	m_gameActions.append(frameAdvance);
	emulationMenu->addAction(frameAdvance);

	QMenu* soundMenu = menubar->addMenu(tr("&Sound"));
	QMenu* buffersMenu = soundMenu->addMenu(tr("Buffer &size"));
	buffersMenu->addAction(tr("512"), this, SLOT(setBuffers512()));
	buffersMenu->addAction(tr("1024"), this, SLOT(setBuffers1024()));
	buffersMenu->addAction(tr("2048"), this, SLOT(setBuffers2048()));
	buffersMenu->addAction(tr("4096"), this, SLOT(setBuffers4096()));

	QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
#ifdef USE_GDB_STUB
	QAction* gdbWindow = new QAction(tr("Start &GDB server..."), nullptr);
	connect(gdbWindow, SIGNAL(triggered()), this, SLOT(gdbOpen()));
	debuggingMenu->addAction(gdbWindow);
#endif

	foreach (QAction* action, m_gameActions) {
		action->setDisabled(true);
	}
}
<commit_msg>Sync pause setting with the menu properly<commit_after>#include "Window.h"

#include <QFileDialog>
#include <QKeyEvent>
#include <QKeySequence>
#include <QMenuBar>

#include "GameController.h"
#include "GDBWindow.h"
#include "GDBController.h"

using namespace QGBA;

Window::Window(QWidget* parent)
	: QMainWindow(parent)
#ifdef USE_GDB_STUB
	, m_gdbController(nullptr)
#endif
{
	setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	setMinimumSize(240, 160);

	m_controller = new GameController(this);
	m_display = new Display();
	setCentralWidget(m_display);
	connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*)));
	connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing()));
	connect(m_controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(gameStopped()));
	connect(this, SIGNAL(startDrawing(const uint32_t*, GBAThread*)), m_display, SLOT(startDrawing(const uint32_t*, GBAThread*)), Qt::QueuedConnection);
	connect(this, SIGNAL(shutdown()), m_display, SLOT(stopDrawing()));
	connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int)));

	setupMenu(menuBar());
}

GBAKey Window::mapKey(int qtKey) {
	switch (qtKey) {
	case Qt::Key_Z:
		return GBA_KEY_A;
		break;
	case Qt::Key_X:
		return GBA_KEY_B;
		break;
	case Qt::Key_A:
		return GBA_KEY_L;
		break;
	case Qt::Key_S:
		return GBA_KEY_R;
		break;
	case Qt::Key_Return:
		return GBA_KEY_START;
		break;
	case Qt::Key_Backspace:
		return GBA_KEY_SELECT;
		break;
	case Qt::Key_Up:
		return GBA_KEY_UP;
		break;
	case Qt::Key_Down:
		return GBA_KEY_DOWN;
		break;
	case Qt::Key_Left:
		return GBA_KEY_LEFT;
		break;
	case Qt::Key_Right:
		return GBA_KEY_RIGHT;
		break;
	default:
		return GBA_KEY_NONE;
	}
}

void Window::selectROM() {
	QString filename = QFileDialog::getOpenFileName(this, tr("Select ROM"));
	if (!filename.isEmpty()) {
		m_controller->loadGame(filename);
	}
}

#ifdef USE_GDB_STUB
void Window::gdbOpen() {
	if (!m_gdbController) {
		m_gdbController = new GDBController(m_controller, this);
	}
	GDBWindow* window = new GDBWindow(m_gdbController);
	window->show();
}
#endif

void Window::keyPressEvent(QKeyEvent* event) {
	if (event->isAutoRepeat()) {
		QWidget::keyPressEvent(event);
		return;
	}
	GBAKey key = mapKey(event->key());
	if (key == GBA_KEY_NONE) {
		QWidget::keyPressEvent(event);
		return;
	}
	m_controller->keyPressed(key);
	event->accept();
}

void Window::keyReleaseEvent(QKeyEvent* event) {
	if (event->isAutoRepeat()) {
		QWidget::keyReleaseEvent(event);
		return;
	}
	GBAKey key = mapKey(event->key());
	if (key == GBA_KEY_NONE) {
		QWidget::keyPressEvent(event);
		return;
	}
	m_controller->keyReleased(key);
	event->accept();
}

void Window::closeEvent(QCloseEvent* event) {
	emit shutdown();
	QMainWindow::closeEvent(event);
}

void Window::gameStarted(GBAThread* context) {
	emit startDrawing(m_controller->drawContext(), context);
	foreach (QAction* action, m_gameActions) {
		action->setDisabled(false);
	}
}

void Window::gameStopped() {
	foreach (QAction* action, m_gameActions) {
		action->setDisabled(true);
	}
}

void Window::setBuffers512() {
	emit audioBufferSamplesChanged(512);
}

void Window::setBuffers1024() {
	emit audioBufferSamplesChanged(1024);
}

void Window::setBuffers2048() {
	emit audioBufferSamplesChanged(2048);
}

void Window::setBuffers4096() {
	emit audioBufferSamplesChanged(4096);
}

void Window::setupMenu(QMenuBar* menubar) {
	menubar->clear();
	QMenu* fileMenu = menubar->addMenu(tr("&File"));
	fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open);

	QMenu* emulationMenu = menubar->addMenu(tr("&Emulation"));
	QAction* reset = new QAction(tr("&Reset"), nullptr);
	reset->setShortcut(tr("Ctrl+R"));
	connect(reset, SIGNAL(triggered()), m_controller, SLOT(reset()));
	m_gameActions.append(reset);
	emulationMenu->addAction(reset);

	QAction* shutdown = new QAction(tr("Sh&utdown"), nullptr);
	connect(shutdown, SIGNAL(triggered()), m_controller, SLOT(closeGame()));
	m_gameActions.append(shutdown);
	emulationMenu->addAction(shutdown);
	emulationMenu->addSeparator();

	QAction* pause = new QAction(tr("&Pause"), nullptr);
	pause->setChecked(false);
	pause->setCheckable(true);
	pause->setShortcut(tr("Ctrl+P"));
	connect(pause, SIGNAL(triggered(bool)), m_controller, SLOT(setPaused(bool)));
	connect(m_controller, &GameController::gamePaused, [pause]() { pause->setChecked(true); });
	connect(m_controller, &GameController::gameUnpaused, [pause]() { pause->setChecked(false); });
	m_gameActions.append(pause);
	emulationMenu->addAction(pause);

	QAction* frameAdvance = new QAction(tr("&Next frame"), nullptr);
	frameAdvance->setShortcut(tr("Ctrl+N"));
	connect(frameAdvance, SIGNAL(triggered()), m_controller, SLOT(frameAdvance()));
	m_gameActions.append(frameAdvance);
	emulationMenu->addAction(frameAdvance);

	QMenu* soundMenu = menubar->addMenu(tr("&Sound"));
	QMenu* buffersMenu = soundMenu->addMenu(tr("Buffer &size"));
	buffersMenu->addAction(tr("512"), this, SLOT(setBuffers512()));
	buffersMenu->addAction(tr("1024"), this, SLOT(setBuffers1024()));
	buffersMenu->addAction(tr("2048"), this, SLOT(setBuffers2048()));
	buffersMenu->addAction(tr("4096"), this, SLOT(setBuffers4096()));

	QMenu* debuggingMenu = menubar->addMenu(tr("&Debugging"));
#ifdef USE_GDB_STUB
	QAction* gdbWindow = new QAction(tr("Start &GDB server..."), nullptr);
	connect(gdbWindow, SIGNAL(triggered()), this, SLOT(gdbOpen()));
	debuggingMenu->addAction(gdbWindow);
#endif

	foreach (QAction* action, m_gameActions) {
		action->setDisabled(true);
	}
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VertexArray.h"
#include "../base/Exception.h"

#include <iostream>

using namespace std;

namespace avg {

    VertexArray::VertexArray(int NumQuads)
        : m_NumQuads(NumQuads),
          m_bDataChanged(true)
    {
        glproc::GenBuffers(1, &m_VBOArrayID);
        m_pVertexData = new T2V3Vertex[NumQuads*4];
    }

    VertexArray::~VertexArray()
    {
        delete[] m_pVertexData;
        glproc::DeleteBuffers(1, &m_VBOArrayID);
    }

    void VertexArray::setPos(int QuadIndex, int VertexIndex, const DPoint& Pos,
            const DPoint& TexPos)
    {
        assert(QuadIndex < m_NumQuads);
        T2V3Vertex* pVertex = &(m_pVertexData[QuadIndex*4+VertexIndex]);
        pVertex->m_Pos[0] = Pos.x;
        pVertex->m_Pos[1] = Pos.y;
        pVertex->m_Pos[2] = 0.0;
        pVertex->m_Tex[0] = TexPos.x;
        pVertex->m_Tex[1] = TexPos.y;
        m_bDataChanged = true;
    }

    void VertexArray::draw()
    {
        glproc::BindBuffer(GL_ARRAY_BUFFER, m_VBOArrayID);
        if (m_bDataChanged) {
            glproc::BufferData(GL_ARRAY_BUFFER, m_NumQuads*4*sizeof(T2V3Vertex),
                    m_pVertexData, GL_STREAM_DRAW);
        }
        glVertexPointer(3, GL_FLOAT, sizeof(T2V3Vertex), (void*)8);
//                (void *)(offsetof(T2V3Vertex::m_Pos)));
        glTexCoordPointer(2, GL_FLOAT, sizeof(T2V3Vertex),
                0);

        glDrawArrays(GL_QUADS, 0, 4*m_NumQuads);
        OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "VertexArray::draw()");

        m_bDataChanged = false;
    }

}

<commit_msg>Used offsetof instead of fixed offset for VBO data specification.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VertexArray.h"
#include "../base/Exception.h"

#include <iostream>
#include <stddef.h>

using namespace std;

namespace avg {

    VertexArray::VertexArray(int NumQuads)
        : m_NumQuads(NumQuads),
          m_bDataChanged(true)
    {
        glproc::GenBuffers(1, &m_VBOArrayID);
        m_pVertexData = new T2V3Vertex[NumQuads*4];
    }

    VertexArray::~VertexArray()
    {
        delete[] m_pVertexData;
        glproc::DeleteBuffers(1, &m_VBOArrayID);
    }

    void VertexArray::setPos(int QuadIndex, int VertexIndex, const DPoint& Pos,
            const DPoint& TexPos)
    {
        assert(QuadIndex < m_NumQuads);
        T2V3Vertex* pVertex = &(m_pVertexData[QuadIndex*4+VertexIndex]);
        pVertex->m_Pos[0] = Pos.x;
        pVertex->m_Pos[1] = Pos.y;
        pVertex->m_Pos[2] = 0.0;
        pVertex->m_Tex[0] = TexPos.x;
        pVertex->m_Tex[1] = TexPos.y;
        m_bDataChanged = true;
    }

    void VertexArray::draw()
    {
        glproc::BindBuffer(GL_ARRAY_BUFFER, m_VBOArrayID);
        if (m_bDataChanged) {
            glproc::BufferData(GL_ARRAY_BUFFER, m_NumQuads*4*sizeof(T2V3Vertex),
                    m_pVertexData, GL_STREAM_DRAW);
        }
        glVertexPointer(3, GL_FLOAT, sizeof(T2V3Vertex),
                (void *)(offsetof(T2V3Vertex, m_Pos)));
        glTexCoordPointer(2, GL_FLOAT, sizeof(T2V3Vertex),
                0);

        glDrawArrays(GL_QUADS, 0, 4*m_NumQuads);
        OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "VertexArray::draw()");

        m_bDataChanged = false;
    }

}

<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

/* Implementations of Bounded Depth-First-Search for models and
 * coverages with push() and pop() */

#include "alg_bdfs.hh"
#include "model.hh"
#include "coverage.hh"
#include <algorithm>
#include <cstdlib>
#include "helper.hh"
#include "learn_proxy.hh"

extern int _g_simulation_depth_hint;

AlgBDFS::AlgBDFS(int searchDepth, Learning* learn):
  m_search_depth(searchDepth), m_learn(learn) {
  if (learn != NULL && ((Learn_proxy*)learn)->lt) // TODO: learn knows how to learn exec times
    m_learn_exec_times = true;
  else
    m_learn_exec_times = false;
};

double AlgPathToBestCoverage::search(Model& model, Coverage& coverage, std::vector<int>& path)
{
    m_coverage = &coverage;
    m_model = &model;
    return path_to_best_evaluation(model, path, m_search_depth);
}

double AlgPathToBestCoverage::evaluate()
{
    return m_coverage->getCoverage();
}

void AlgPathToBestCoverage::doExecute(int action)
{
    if (!status) {
        return;
    }

    m_model->push();
    m_coverage->push();

    if (!m_model->execute(action)) { errormsg="Model execute error"; status=false; return;}
    m_coverage->execute(action);
}

void AlgPathToBestCoverage::undoExecute()
{
    if (!status) {
        return;
    }

    m_model->pop();
    m_coverage->pop();
}

double AlgPathToAction::search(Model& model, int find_this_action, std::vector<int> &path)
{
    m_model = &model;
    m_find_this_action = find_this_action;
    return path_to_best_evaluation(model, path, m_search_depth);
}

double AlgPathToAction::evaluate()
{
    int *actions;
    int action_count;
    /* Is action m_find_this_action available in the current state? */
    action_count = m_model->getActions(&actions);

    if (!status) {
        return 0.0;
    }

    for (int i = 0; i < action_count; i++)
    {
        if (actions[i] == m_find_this_action) return 1.0;
    }
    return 0.0;
}

void AlgPathToAction::doExecute(int action)
{
    m_model->push();
    m_model->execute(action);
}

void AlgPathToAction::undoExecute()
{
    m_model->pop();
}

double AlgBDFS::path_to_best_evaluation(Model& model, std::vector<int>& path, int depth)
{
    volatile double current_score = evaluate();
    volatile double best_score = 0;
    std::vector<int> hinted_path;

    if (!model.status || !status) {
        if (!model.status)
	  errormsg = "Model error: "+model.errormsg;
        status=false;
        return 0.0;
    }

    _g_simulation_depth_hint = depth;
    model.push();
    _g_simulation_depth_hint = 0;

    if (path.size() > 0) {
        // Path includes a hint to look at this path at first before
        // considering others.
        //
        // Evaluating the hinted options first has too effects:
        //
        // - If one path has been chosen earlier, it's preferred to
        //   continue execution that way instead of switching it to
        //   another path that seems to be as good as the
        //   original. This prevents oscillation between equally good
        //   paths.
        //
        // - If maximal growth rate is known, search starting with a
        //   good "so far best score" is able to drop unnecessary
        //   lookups. (Not implemented)

        int invalid_step = -1;
        for (unsigned int pos = 0; pos < path.size() && invalid_step == -1; pos++) {
            doExecute(path[pos]);
            if (status == false) {
                invalid_step = pos;
                status = true;
            }
            if (!model.status) {
                status = false;
		errormsg = "Model: " + model.errormsg;
                return 0.0;
            }
        }

        if (invalid_step > -1) {
            // Hinted path is no more valid, throw it away.
            path.resize(0);
            for (int current_step = invalid_step; current_step > -1; current_step--)
                undoExecute();
        } else {
            std::vector<int> additional_path;

            best_score = _path_to_best_evaluation(model, additional_path, depth - path.size(), current_score);

            if (!model.status || !status) {
	      if (!model.status)
		errormsg = "Model error: "+model.errormsg;
	      status=false;
	      return 0.0;
            }

            for (unsigned int i = 0; i < path.size(); i++) undoExecute();

            if (!model.status || !status) {
	      if (!model.status)
		errormsg = "Model error: "+model.errormsg;
	      status=false;
	      return 0.0;
            }

            if (best_score > current_score) {
                hinted_path = path;
                for (int i = additional_path.size() - 1; i >= 0; i--)
                    hinted_path.push_back(additional_path[i]);
                current_score = best_score;
            }
        }
    }

    best_score = _path_to_best_evaluation(model, path, depth, current_score);
    model.pop();

    if (!model.status || !status) {
      if (!model.status)
	errormsg = "Model error: "+model.errormsg;
      status=false;
      return 0.0;
    }

    if (best_score > current_score || (
            best_score == current_score &&
            path.size() < hinted_path.size())) {
        // The real algorithm constructs the best path in the opposite
        // direction to the path vector, this wrapper reverses it.
        std::reverse(path.begin(), path.end());
    } else if (hinted_path.size() > 0) {
        path = hinted_path;
    } else {
        path.resize(0);
    }
    return best_score;
}

bool AlgBDFS::grows_first(std::vector<int>& first_path, int first_path_start,
                          std::vector<int>& second_path, int second_path_start)
{
    if (first_path.size() != second_path.size()) {
      errormsg="first_path.size() != second_path.size()";
      status=false;
      return false;
    }

    volatile double current_score = evaluate();

    first_path.push_back(first_path_start);
    second_path.push_back(second_path_start);

    int first_difference = first_path.size();
    for (int i = first_path.size() - 1; i >= 0; i--) {
        doExecute(first_path[i]);
        volatile double score = evaluate();

        if (!status) {
          return false;
        }

        if (score > current_score) {
            first_difference = i;
            break;
        }
    }
    if (first_difference == (int)first_path.size()) {
      errormsg = "first_difference == (int)first_path.size() "+to_string(first_difference);
      status=false; return false;
    }

    for (int j = first_path.size() - 1; j >= first_difference; j--) undoExecute();

    int second_difference = second_path.size();
    for (int i = second_path.size() - 1; i >= 0; i--) {
        doExecute(second_path[i]);
        volatile double score = evaluate();
        if (score > current_score) {
            second_difference = i;
            break;
        }
    }
    if (second_difference == (int)second_path.size()) {
      errormsg = "second_difference == (int)second_path.size()";
      status=false; return false;
    }

    for (int j = second_path.size() - 1; j >= second_difference; j--) undoExecute();

    first_path.pop_back();
    second_path.pop_back();

    if (first_difference > second_difference) return true;
    else return false;
}

bool AlgBDFS::grows_faster(std::vector<int>& first_path, int first_path_start,
                           std::vector<int>& second_path, int second_path_start)
{
    float first_path_time = m_learn->getE(first_path_start);
    float second_path_time = m_learn->getE(second_path_start);

    for (int i = first_path.size() - 1; i >= 0; i--) {
        first_path_time += m_learn->getE(first_path[i]);
    }
    for (int i = second_path.size() - 1; i >= 0; i--) {
        second_path_time += m_learn->getE(second_path[i]);
    }

    return first_path_time < second_path_time;
}

double AlgPathToAdaptiveCoverage::_path_to_best_evaluation
       (Model& model, std::vector<int>& path, int depth,double best_evaluation)
{
    int *input_actions = NULL;
    int input_action_count = 0;

    if (!status) {
        return 0.0;
    }

    volatile double current_state_evaluation = evaluate();

    if (current_state_evaluation > best_evaluation)
        best_evaluation = current_state_evaluation;

    /* Can we still continue the search? */
    if (depth <= 0)
        return current_state_evaluation;

    /* Recursive search for the best path */
    input_action_count = model.getIActions(&input_actions);

    if (!model.status) {
      errormsg = "Model error: "+model.errormsg;
        status=false;
        return 0.0;
    }

    std::vector<int> action_candidates;
    for (int i = 0; i < input_action_count; i++)
        action_candidates.push_back(input_actions[i]);

    std::vector<int> best_path;
    unsigned int best_path_length = 0;
    int best_action = -1;
    std::vector<double> pre_evaluation;
    std::vector<double> an_evaluation;
    std::vector<std::vector<int> > a_path;

    an_evaluation.resize(input_action_count+1);
    a_path.resize(input_action_count+1);
    pre_evaluation.reserve(input_action_count+1);

    for (int i = 0; i < input_action_count; i++)
    {
      doExecute(action_candidates[i]);

      a_path[i].resize(0);
      pre_evaluation.push_back(_path_to_best_evaluation(model, a_path[i], depth - 1, best_evaluation));
      undoExecute();

      if (!model.status || !status) {
	if (!model.status)
	  errormsg = "Model error: "+model.errormsg;
	status=false;
	return 0.0;
      }
    }

    if (m_learn) {
    for (int i = 0; i < input_action_count; i++)
      {
	float weight_total=0.0;

	for (int j = 0; j < input_action_count; j++)
	  {
	    float weight=m_learn?m_learn->getC(action_candidates[i],action_candidates[j]):0.0;

	    if (i==j) {
	      weight+=1.0;
	    }
	    weight_total+=weight;

	    an_evaluation[i]+=pre_evaluation[j]*weight;
	  }
	if (weight_total>0.0) {
	  an_evaluation[i]=an_evaluation[i]/weight_total;
	} else {
	  an_evaluation[i]=0.0;
	}
      }
    } else {
      an_evaluation.swap(pre_evaluation);
    }

    for (int i = 0; i < input_action_count; i++) {
        if (an_evaluation[i] > current_state_evaluation &&
            (an_evaluation[i] > best_evaluation ||
             (an_evaluation[i] == best_evaluation &&
              (best_action == -1 ||
               (best_action > -1 &&
                ((m_learn_exec_times && grows_faster(a_path[i], action_candidates[i], best_path, best_action)) ||
                 (a_path[i].size() < best_path_length ||
                  (a_path[i].size() == best_path_length &&
                   grows_first(a_path[i], action_candidates[i], best_path, best_action)))))))))
        {
            best_path_length = a_path[i].size();
            best_path = a_path[i];
            best_action = action_candidates[i];
            best_evaluation = an_evaluation[i];
        }
    }

    if ((int)best_action > -1) {
        path = best_path;
        path.push_back(best_action);
        return best_evaluation;
    }
    return current_state_evaluation;
}

double AlgBDFS::_path_to_best_evaluation(Model& model, std::vector<int>& path, int depth,
                                         double best_evaluation)
{
    int *input_actions = NULL;
    int input_action_count = 0;

    if (!status) {
        return 0.0;
    }

    volatile double current_state_evaluation = evaluate();

    if (current_state_evaluation > best_evaluation)
        best_evaluation = current_state_evaluation;

    /* Can we still continue the search? */
    if (depth <= 0)
        return current_state_evaluation;

    /* Recursive search for the best path */
    input_action_count = model.getIActions(&input_actions);

    if (!model.status) {
      errormsg = "Model error:"+model.errormsg;
        status=false;
        return 0.0;
    }

    std::vector<int> action_candidates;
    for (int i = 0; i < input_action_count; i++)
      action_candidates.push_back(input_actions[i]);
    std::vector<int> best_path;
    unsigned int best_path_length = 0;
    int best_action = -1;
    for (int i = 0; i < input_action_count; i++)
    {
        std::vector<int> a_path;
        volatile double an_evaluation;

        doExecute(action_candidates[i]);

        a_path.resize(0);
        an_evaluation = _path_to_best_evaluation(model, a_path, depth - 1, best_evaluation);

        undoExecute();

        if (!model.status || !status) {
          if (!model.status)
            errormsg = "Model error:"+model.errormsg;
          status=false;
          return 0.0;
        }

        if (an_evaluation > current_state_evaluation &&
            (an_evaluation > best_evaluation ||
             (an_evaluation == best_evaluation &&
              (best_action == -1 ||
               (best_action > -1 &&
                (a_path.size() < best_path_length ||
                 (a_path.size() == best_path_length &&
                  grows_first(a_path, action_candidates[i], best_path, best_action))))))))
        {
            best_path_length = a_path.size();
            best_path = a_path;
            best_action = action_candidates[i];
            best_evaluation = an_evaluation;
        }
    }

    if ((int)best_action > -1) {
        path = best_path;
        path.push_back(best_action);
        return best_evaluation;
    }
    return current_state_evaluation;
}
<commit_msg>fix bugs...<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

/* Implementations of Bounded Depth-First-Search for models and
 * coverages with push() and pop() */

#include "alg_bdfs.hh"
#include "model.hh"
#include "coverage.hh"
#include <algorithm>
#include <cstdlib>
#include "helper.hh"
#include "learn_proxy.hh"

extern int _g_simulation_depth_hint;

AlgBDFS::AlgBDFS(int searchDepth, Learning* learn):
  m_search_depth(searchDepth), m_learn(learn) {
  if (learn != NULL && ((Learn_proxy*)learn)->lt!=NULL) // TODO: learn knows how to learn exec times
    m_learn_exec_times = true;
  else
    m_learn_exec_times = false;
}

double AlgPathToBestCoverage::search(Model& model, Coverage& coverage, std::vector<int>& path)
{
    m_coverage = &coverage;
    m_model = &model;
    return path_to_best_evaluation(model, path, m_search_depth);
}

double AlgPathToBestCoverage::evaluate()
{
    return m_coverage->getCoverage();
}

void AlgPathToBestCoverage::doExecute(int action)
{
    if (!status) {
        return;
    }

    m_model->push();
    m_coverage->push();

    if (!m_model->execute(action)) { errormsg="Model execute error"; status=false; return;}
    m_coverage->execute(action);
}

void AlgPathToBestCoverage::undoExecute()
{
    if (!status) {
        return;
    }

    m_model->pop();
    m_coverage->pop();
}

double AlgPathToAction::search(Model& model, int find_this_action, std::vector<int> &path)
{
    m_model = &model;
    m_find_this_action = find_this_action;
    return path_to_best_evaluation(model, path, m_search_depth);
}

double AlgPathToAction::evaluate()
{
    int *actions;
    int action_count;
    /* Is action m_find_this_action available in the current state? */
    action_count = m_model->getActions(&actions);

    if (!status) {
        return 0.0;
    }

    for (int i = 0; i < action_count; i++)
    {
        if (actions[i] == m_find_this_action) return 1.0;
    }
    return 0.0;
}

void AlgPathToAction::doExecute(int action)
{
    m_model->push();
    m_model->execute(action);
}

void AlgPathToAction::undoExecute()
{
    m_model->pop();
}

double AlgBDFS::path_to_best_evaluation(Model& model, std::vector<int>& path, int depth)
{
    volatile double current_score = evaluate();
    volatile double best_score = 0;
    std::vector<int> hinted_path;

    if (!model.status || !status) {
        if (!model.status)
	  errormsg = "Model error: "+model.errormsg;
        status=false;
        return 0.0;
    }

    _g_simulation_depth_hint = depth;
    model.push();
    _g_simulation_depth_hint = 0;

    if (path.size() > 0) {
        // Path includes a hint to look at this path at first before
        // considering others.
        //
        // Evaluating the hinted options first has too effects:
        //
        // - If one path has been chosen earlier, it's preferred to
        //   continue execution that way instead of switching it to
        //   another path that seems to be as good as the
        //   original. This prevents oscillation between equally good
        //   paths.
        //
        // - If maximal growth rate is known, search starting with a
        //   good "so far best score" is able to drop unnecessary
        //   lookups. (Not implemented)

        int invalid_step = -1;
        for (unsigned int pos = 0; pos < path.size() && invalid_step == -1; pos++) {
            doExecute(path[pos]);
            if (status == false) {
                invalid_step = pos;
                status = true;
            }
            if (!model.status) {
                status = false;
		errormsg = "Model: " + model.errormsg;
                return 0.0;
            }
        }

        if (invalid_step > -1) {
            // Hinted path is no more valid, throw it away.
            path.resize(0);
            for (int current_step = invalid_step; current_step > -1; current_step--)
                undoExecute();
        } else {
            std::vector<int> additional_path;

            best_score = _path_to_best_evaluation(model, additional_path, depth - path.size(), current_score);

            if (!model.status || !status) {
	      if (!model.status)
		errormsg = "Model error: "+model.errormsg;
	      status=false;
	      return 0.0;
            }

            for (unsigned int i = 0; i < path.size(); i++) undoExecute();

            if (!model.status || !status) {
	      if (!model.status)
		errormsg = "Model error: "+model.errormsg;
	      status=false;
	      return 0.0;
            }

            if (best_score > current_score) {
                hinted_path = path;
                for (int i = additional_path.size() - 1; i >= 0; i--)
                    hinted_path.push_back(additional_path[i]);
                current_score = best_score;
            }
        }
    }

    best_score = _path_to_best_evaluation(model, path, depth, current_score);
    model.pop();

    if (!model.status || !status) {
      if (!model.status)
	errormsg = "Model error: "+model.errormsg;
      status=false;
      return 0.0;
    }

    if (best_score > current_score || (
            best_score == current_score &&
            path.size() < hinted_path.size())) {
        // The real algorithm constructs the best path in the opposite
        // direction to the path vector, this wrapper reverses it.
        std::reverse(path.begin(), path.end());
    } else if (hinted_path.size() > 0) {
        path = hinted_path;
    } else {
        path.resize(0);
    }
    return best_score;
}

bool AlgBDFS::grows_first(std::vector<int>& first_path, int first_path_start,
                          std::vector<int>& second_path, int second_path_start)
{
    if (first_path.size() != second_path.size()) {
      errormsg="first_path.size() != second_path.size()";
      status=false;
      return false;
    }

    volatile double current_score = evaluate();

    first_path.push_back(first_path_start);
    second_path.push_back(second_path_start);

    int first_difference = first_path.size();
    for (int i = first_path.size() - 1; i >= 0; i--) {
        doExecute(first_path[i]);
        volatile double score = evaluate();

        if (!status) {
          return false;
        }

        if (score > current_score) {
            first_difference = i;
            break;
        }
    }
    if (first_difference == (int)first_path.size()) {
      errormsg = "first_difference == (int)first_path.size() "+to_string(first_difference);
      status=false; return false;
    }

    for (int j = first_path.size() - 1; j >= first_difference; j--) undoExecute();

    int second_difference = second_path.size();
    for (int i = second_path.size() - 1; i >= 0; i--) {
        doExecute(second_path[i]);
        volatile double score = evaluate();
        if (score > current_score) {
            second_difference = i;
            break;
        }
    }
    if (second_difference == (int)second_path.size()) {
      errormsg = "second_difference == (int)second_path.size()";
      status=false; return false;
    }

    for (int j = second_path.size() - 1; j >= second_difference; j--) undoExecute();

    first_path.pop_back();
    second_path.pop_back();

    if (first_difference > second_difference) return true;
    else return false;
}

bool AlgBDFS::grows_faster(std::vector<int>& first_path, int first_path_start,
                           std::vector<int>& second_path, int second_path_start)
{
    float first_path_time = m_learn->getE(first_path_start);
    float second_path_time = m_learn->getE(second_path_start);

    for (int i = first_path.size() - 1; i >= 0; i--) {
        first_path_time += m_learn->getE(first_path[i]);
    }
    for (int i = second_path.size() - 1; i >= 0; i--) {
        second_path_time += m_learn->getE(second_path[i]);
    }

    return first_path_time < second_path_time;
}

double AlgPathToAdaptiveCoverage::_path_to_best_evaluation
       (Model& model, std::vector<int>& path, int depth,double best_evaluation)
{
    int *input_actions = NULL;
    int input_action_count = 0;

    if (!status) {
        return 0.0;
    }

    volatile double current_state_evaluation = evaluate();

    if (current_state_evaluation > best_evaluation)
        best_evaluation = current_state_evaluation;

    /* Can we still continue the search? */
    if (depth <= 0)
        return current_state_evaluation;

    /* Recursive search for the best path */
    input_action_count = model.getIActions(&input_actions);

    if (!model.status) {
      errormsg = "Model error: "+model.errormsg;
        status=false;
        return 0.0;
    }

    std::vector<int> action_candidates;
    for (int i = 0; i < input_action_count; i++)
        action_candidates.push_back(input_actions[i]);

    std::vector<int> best_path;
    unsigned int best_path_length = 0;
    int best_action = -1;
    std::vector<double> pre_evaluation;
    std::vector<double> an_evaluation;
    std::vector<std::vector<int> > a_path;

    an_evaluation.resize(input_action_count+1);
    a_path.resize(input_action_count+1);
    pre_evaluation.reserve(input_action_count+1);

    for (int i = 0; i < input_action_count; i++)
    {
      doExecute(action_candidates[i]);

      a_path[i].resize(0);
      pre_evaluation.push_back(_path_to_best_evaluation(model, a_path[i], depth - 1, best_evaluation));
      undoExecute();

      if (!model.status || !status) {
	if (!model.status)
	  errormsg = "Model error: "+model.errormsg;
	status=false;
	return 0.0;
      }
    }

    if (m_learn) {
    for (int i = 0; i < input_action_count; i++)
      {
	float weight_total=0.0;

	for (int j = 0; j < input_action_count; j++)
	  {
	    float weight=m_learn?m_learn->getC(action_candidates[i],action_candidates[j]):0.0;

	    if (i==j) {
	      weight+=1.0;
	    }
	    weight_total+=weight;

	    an_evaluation[i]+=pre_evaluation[j]*weight;
	  }
	if (weight_total>0.0) {
	  an_evaluation[i]=an_evaluation[i]/weight_total;
	} else {
	  an_evaluation[i]=0.0;
	}
      }
    } else {
      an_evaluation.swap(pre_evaluation);
    }

    for (int i = 0; i < input_action_count; i++) {
        if (an_evaluation[i] > current_state_evaluation &&
            (an_evaluation[i] > best_evaluation ||
             (an_evaluation[i] == best_evaluation &&
              (best_action == -1 ||
               (best_action > -1 &&
                ((m_learn_exec_times && grows_faster(a_path[i], action_candidates[i], best_path, best_action)) ||
                 (a_path[i].size() < best_path_length ||
                  (a_path[i].size() == best_path_length &&
                   grows_first(a_path[i], action_candidates[i], best_path, best_action)))))))))
        {
            best_path_length = a_path[i].size();
            best_path = a_path[i];
            best_action = action_candidates[i];
            best_evaluation = an_evaluation[i];
        }
    }

    if ((int)best_action > -1) {
        path = best_path;
        path.push_back(best_action);
        return best_evaluation;
    }
    return current_state_evaluation;
}

double AlgBDFS::_path_to_best_evaluation(Model& model, std::vector<int>& path, int depth,
                                         double best_evaluation)
{
    int *input_actions = NULL;
    int input_action_count = 0;

    if (!status) {
        return 0.0;
    }

    volatile double current_state_evaluation = evaluate();

    if (current_state_evaluation > best_evaluation)
        best_evaluation = current_state_evaluation;

    /* Can we still continue the search? */
    if (depth <= 0)
        return current_state_evaluation;

    /* Recursive search for the best path */
    input_action_count = model.getIActions(&input_actions);

    if (!model.status) {
        errormsg = "Model error:"+model.errormsg;
	status=false;
	return 0.0;
    }

    std::vector<int> action_candidates;
    for (int i = 0; i < input_action_count; i++)
        action_candidates.push_back(input_actions[i]);
    std::vector<int> best_path;
    unsigned int best_path_length = 0;
    int best_action = -1;
    for (int i = 0; i < input_action_count; i++)
    {
        std::vector<int> a_path;
        volatile double an_evaluation;

        doExecute(action_candidates[i]);

        a_path.resize(0);
        an_evaluation = _path_to_best_evaluation(model, a_path, depth - 1, best_evaluation);

        undoExecute();

        if (!model.status || !status) {
          if (!model.status)
            errormsg = "Model error:"+model.errormsg;
          status=false;
          return 0.0;
        }

        if (an_evaluation > current_state_evaluation &&
            (an_evaluation > best_evaluation ||
             (an_evaluation == best_evaluation &&
              (best_action == -1 ||
               (best_action > -1 &&
                ((m_learn_exec_times && grows_faster(a_path, action_candidates[i], best_path, best_action)) ||
		 (a_path.size() < best_path_length ||
		  (a_path.size() == best_path_length &&
		   grows_first(a_path, action_candidates[i], best_path, best_action)))))))))
        {
            best_path_length = a_path.size();
            best_path = a_path;
            best_action = action_candidates[i];
            best_evaluation = an_evaluation;
        }
    }

    if ((int)best_action > -1) {
        path = best_path;
        path.push_back(best_action);
        return best_evaluation;
    }
    return current_state_evaluation;
}
<|endoftext|>


<commit_before>#include <string.h>
#include <iostream>

#define OPT_TRANSFORM "-o"
#define OPT_PRINT "-p"
#define OPT_STATIC "-a"
#define OPT_EXEC "-e"

using namespace std;

int main(int argc, char* argv[]) {
  bool transformEnabled = false;
  bool printEnabled = false;
  bool staticEnabled = false;
  bool execEnabled = false;
  char* fileName = NULL;

  for(int i = 1; i < argc; i++) {
    char* arg = argv[i];
    if(strcmp(arg, OPT_TRANSFORM)) {
      transformEnabled = true;
    } else if(strcmp(arg, OPT_PRINT)) {
      printEnabled = true;
    } else if(strcmp(arg, OPT_STATIC)) {
      staticEnabled = true;
    } else if(strcmp(arg, OPT_EXEC)) {
      execEnabled = true;
    } else {
      fileName = arg;
    }
  }

  if(fileName == NULL) {
    cerr << "No input file provided";
    return 1;
  }

  // LEXER
  // PARSER
  if(transformEnabled) {
    // TRANSFORM
  }
  if(printEnabled) {
    // PRINT
  }
  if(staticEnabled) {
    // STATIC
  }
  if(execEnabled) {
    // EXEC
  }

  return 0;
}
<commit_msg>Use cpp string<commit_after>#include <iostream>
#include <string>

#define OPT_TRANSFORM "-o"
#define OPT_PRINT "-p"
#define OPT_STATIC "-a"
#define OPT_EXEC "-e"

using namespace std;

int main(int argc, char* argv[]) {
  bool transformEnabled = false;
  bool printEnabled = false;
  bool staticEnabled = false;
  bool execEnabled = false;
  char* fileName = NULL;

  for(int i = 1; i < argc; i++) {
    string* arg = new string(argv[i]);
    if(arg->compare(OPT_TRANSFORM) == 0) {
      transformEnabled = true;
    } else if(arg->compare(OPT_PRINT) == 0) {
      printEnabled = true;
    } else if(arg->compare(OPT_STATIC) == 0) {
      staticEnabled = true;
    } else if(arg->compare(OPT_EXEC) == 0) {
      execEnabled = true;
    } else {
      fileName = argv[i];
    }
  }

  if(fileName == NULL) {
    cerr << "No input file provided" << endl;
    return 1;
  }

  // LEXER
  // PARSER
  if(transformEnabled) {
    cout << "Transform (optimize) input" << endl;
    // TRANSFORM
  }
  if(printEnabled) {
    cout << "Print (transformed?) input" << endl;
    // PRINT
  }
  if(staticEnabled) {
    cout << "Analyze statically" << endl;
    // STATIC
  }
  if(execEnabled) {
    cout << "Execute" << endl;
    // EXEC
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "nan.h"
#include "spellchecker.h"

using node::ObjectWrap;
using namespace spellchecker;
using namespace v8;

namespace {

class Spellchecker : public ObjectWrap {
  SpellcheckerImplementation* impl;

  static NAN_METHOD(New) {
    NanScope();
    Spellchecker* that = new Spellchecker();
    that->Wrap(args.This());

    NanReturnValue(args.This());
  }

  static NAN_METHOD(SetDictionary) {
    NanScope();

    if (args.Length() < 1) {
      return NanThrowError("Bad argument");
    }

    Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());

    std::string language = *String::Utf8Value(args[0]);
    std::string directory = ".";
    if (args.Length() > 1) {
      directory = *String::Utf8Value(args[1]);
    }

    bool result = that->impl->SetDictionary(language, directory);
    NanReturnValue(NanNew(result));
  }

  static NAN_METHOD(IsMisspelled) {
    NanScope();
    if (args.Length() < 1) {
      return NanThrowError("Bad argument");
    }

    Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());
    std::string word = *String::Utf8Value(args[0]);

    NanReturnValue(NanNew(that->impl->IsMisspelled(word)));
  }

  static NAN_METHOD(Add) {
    NanScope();
    if (args.Length() < 1) {
      return NanThrowError("Bad argument");
    }

    Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());
    std::string word = *String::Utf8Value(args[0]);

    that->impl->Add(word);
    NanReturnUndefined();
  }

  static NAN_METHOD(GetAvailableDictionaries) {
    NanScope();

    Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());

    std::string path = ".";
    if (args.Length() > 0) {
      std::string path = *String::Utf8Value(args[0]);
    }

    std::vector<std::string> dictionaries =
      that->impl->GetAvailableDictionaries(path);

    Local<Array> result = NanNew<Array>(dictionaries.size());
    for (size_t i = 0; i < dictionaries.size(); ++i) {
      const std::string& dict = dictionaries[i];
      result->Set(i, NanNew(dict.data(), dict.size()));
    }

    NanReturnValue(result);
  }

  static NAN_METHOD(GetCorrectionsForMisspelling) {
    NanScope();
    if (args.Length() < 1) {
      return NanThrowError("Bad argument");
    }

    Spellchecker* that = ObjectWrap::Unwrap<Spellchecker>(args.Holder());

    std::string word = *String::Utf8Value(args[0]);
    std::vector<std::string> corrections =
      that->impl->GetCorrectionsForMisspelling(word);

    Local<Array> result = NanNew<Array>(corrections.size());
    for (size_t i = 0; i < corrections.size(); ++i) {
      const std::string& word = corrections[i];
      result->Set(i, NanNew<String>(word.data(), word.size()));
    }

    NanReturnValue(result);
  }

  Spellchecker() {
    impl = SpellcheckerFactory::CreateSpellchecker();
  }

  // actual destructor
  virtual ~Spellchecker() {
    delete impl;
  }

 public:
  static void Init(Handle<Object> exports) {
    Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(Spellchecker::New);

    tpl->SetClassName(NanNew<String>("Spellchecker"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_METHOD(tpl->InstanceTemplate(), "setDictionary", Spellchecker::SetDictionary);
    NODE_SET_METHOD(tpl->InstanceTemplate(), "getAvailableDictionaries", Spellchecker::GetAvailableDictionaries);
    NODE_SET_METHOD(tpl->InstanceTemplate(), "getCorrectionsForMisspelling", Spellchecker::GetCorrectionsForMisspelling);
    NODE_SET_METHOD(tpl->InstanceTemplate(), "isMisspelled", Spellchecker::IsMisspelled);
    NODE_SET_METHOD(tpl->InstanceTemplate(), "add", Spellchecker::Add);

    exports->Set(NanNew("Spellchecker"), tpl->GetFunction());
  }
};

void Init(Handle<Object> exports, Handle<Object> module) {
  Spellchecker::Init(exports);
}

}  // namespace

NODE_MODULE(spellchecker, Init)
<commit_msg>Rewrite to nan 2.0 methods<commit_after>#include "nan.h"
#include "spellchecker.h"

using Nan::ObjectWrap;
using namespace spellchecker;
using namespace v8;

namespace {

class Spellchecker : public Nan::ObjectWrap {
  SpellcheckerImplementation* impl;

  static NAN_METHOD(New) {
    Nan::HandleScope scope;
    Spellchecker* that = new Spellchecker();
    that->Wrap(info.This());

    info.GetReturnValue().Set(info.This());
  }

  static NAN_METHOD(SetDictionary) {
    Nan::HandleScope scope;

    if (info.Length() < 1) {
      return Nan::ThrowError("Bad argument");
    }

    Spellchecker* that = Nan::ObjectWrap::Unwrap<Spellchecker>(info.Holder());

    std::string language = *String::Utf8Value(info[0]);
    std::string directory = ".";
    if (info.Length() > 1) {
      directory = *String::Utf8Value(info[1]);
    }

    bool result = that->impl->SetDictionary(language, directory);
    info.GetReturnValue().Set(Nan::New(result));
  }

  static NAN_METHOD(IsMisspelled) {
    Nan::HandleScope scope;
    if (info.Length() < 1) {
      return Nan::ThrowError("Bad argument");
    }

    Spellchecker* that = Nan::ObjectWrap::Unwrap<Spellchecker>(info.Holder());
    std::string word = *String::Utf8Value(info[0]);

    info.GetReturnValue().Set(Nan::New(that->impl->IsMisspelled(word)));
  }

  static NAN_METHOD(Add) {
    Nan::HandleScope scope;
    if (info.Length() < 1) {
      return Nan::ThrowError("Bad argument");
    }

    Spellchecker* that = Nan::ObjectWrap::Unwrap<Spellchecker>(info.Holder());
    std::string word = *String::Utf8Value(info[0]);

    that->impl->Add(word);
    return;
  }

  static NAN_METHOD(GetAvailableDictionaries) {
    Nan::HandleScope scope;

    Spellchecker* that = Nan::ObjectWrap::Unwrap<Spellchecker>(info.Holder());

    std::string path = ".";
    if (info.Length() > 0) {
      std::string path = *String::Utf8Value(info[0]);
    }

    std::vector<std::string> dictionaries =
      that->impl->GetAvailableDictionaries(path);

    Local<Array> result = Nan::New<Array>(dictionaries.size());
    for (size_t i = 0; i < dictionaries.size(); ++i) {
      const std::string& dict = dictionaries[i];
      result->Set(i, Nan::New(dict.data(), dict.size()));
    }

    info.GetReturnValue().Set(result);
  }

  static NAN_METHOD(GetCorrectionsForMisspelling) {
    Nan::HandleScope scope;
    if (info.Length() < 1) {
      return Nan::ThrowError("Bad argument");
    }

    Spellchecker* that = Nan::ObjectWrap::Unwrap<Spellchecker>(info.Holder());

    std::string word = *String::Utf8Value(info[0]);
    std::vector<std::string> corrections =
      that->impl->GetCorrectionsForMisspelling(word);

    Local<Array> result = Nan::New<Array>(corrections.size());
    for (size_t i = 0; i < corrections.size(); ++i) {
      const std::string& word = corrections[i];
      result->Set(i, Nan::New<String>(word.data(), word.size())).ToLocalChecked();
    }

    info.GetReturnValue().Set(result);
  }

  Spellchecker() {
    impl = SpellcheckerFactory::CreateSpellchecker();
  }

  // actual destructor
  virtual ~Spellchecker() {
    delete impl;
  }

 public:
  static void Init(Handle<Object> exports) {
    Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(Spellchecker::New);

    tpl->SetClassName(Nan::New<String>("Spellchecker").ToLocalChecked());
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetMethod(tpl->InstanceTemplate(), "setDictionary", Spellchecker::SetDictionary);
    Nan::SetMethod(tpl->InstanceTemplate(), "getAvailableDictionaries", Spellchecker::GetAvailableDictionaries);
    Nan::SetMethod(tpl->InstanceTemplate(), "getCorrectionsForMisspelling", Spellchecker::GetCorrectionsForMisspelling);
    Nan::SetMethod(tpl->InstanceTemplate(), "isMisspelled", Spellchecker::IsMisspelled);
    Nan::SetMethod(tpl->InstanceTemplate(), "add", Spellchecker::Add);

    exports->Set(Nan::New("Spellchecker").ToLocalChecked(), tpl->GetFunction());
  }
};

void Init(Handle<Object> exports, Handle<Object> module) {
  Spellchecker::Init(exports);
}

}  // namespace

NODE_MODULE(spellchecker, Init)
<|endoftext|>


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

#include <pow/daa.h>

#include <chain.h>
#include <chainparams.h>
#include <config.h>

#include <test/util/setup_common.h>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(daa_tests, BasicTestingSetup)

static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval,
                                 uint32_t nBits) {
    CBlockIndex block;
    block.pprev = pindexPrev;
    block.nHeight = pindexPrev->nHeight + 1;
    block.nTime = pindexPrev->nTime + nTimeInterval;
    block.nBits = nBits;

    block.nChainWork = pindexPrev->nChainWork + GetBlockProof(block);
    return block;
}

BOOST_AUTO_TEST_CASE(daa_test) {
    DummyConfig config(CBaseChainParams::MAIN);

    std::vector<CBlockIndex> blocks(3000);

    const Consensus::Params &params = config.GetChainParams().GetConsensus();
    const arith_uint256 powLimit = UintToArith256(params.powLimit);
    uint32_t powLimitBits = powLimit.GetCompact();
    arith_uint256 currentPow = powLimit >> 4;
    uint32_t initialBits = currentPow.GetCompact();

    // Genesis block.
    blocks[0] = CBlockIndex();
    blocks[0].nHeight = 0;
    blocks[0].nTime = 1269211443;
    blocks[0].nBits = initialBits;

    blocks[0].nChainWork = GetBlockProof(blocks[0]);

    // Block counter.
    size_t i;

    // Pile up some blocks every 10 mins to establish some history.
    for (i = 1; i < 2050; i++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 600, initialBits);
    }

    CBlockHeader blkHeaderDummy;
    uint32_t nBits =
        GetNextDAAWorkRequired(&blocks[2049], &blkHeaderDummy, params);

    // Difficulty stays the same as long as we produce a block every 10 mins.
    for (size_t j = 0; j < 10; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
        BOOST_CHECK_EQUAL(
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params), nBits);
    }

    // Make sure we skip over blocks that are out of wack. To do so, we produce
    // a block that is far in the future, and then produce a block with the
    // expected timestamp.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
    BOOST_CHECK_EQUAL(
        GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);
    blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 600 - 6000, nBits);
    BOOST_CHECK_EQUAL(
        GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);

    // The system should continue unaffected by the block with a bogous
    // timestamps.
    for (size_t j = 0; j < 20; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
        BOOST_CHECK_EQUAL(
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params), nBits);
    }

    // We start emitting blocks slightly faster. The first block has no impact.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits);
    BOOST_CHECK_EQUAL(
        GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);

    // Now we should see difficulty increase slowly.
    for (size_t j = 0; j < 10; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Make sure that difficulty increases very slowly.
        BOOST_CHECK(nextTarget < currentTarget);
        BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 10));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c0fe7b1);

    // If we dramatically shorten block production, difficulty increases faster.
    for (size_t j = 0; j < 20; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Make sure that difficulty increases faster.
        BOOST_CHECK(nextTarget < currentTarget);
        BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 4));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c0db19f);

    // We start to emit blocks significantly slower. The first block has no
    // impact.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
    nBits = GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params);

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c0d9222);

    // If we dramatically slow down block production, difficulty decreases.
    for (size_t j = 0; j < 93; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Check the difficulty decreases.
        BOOST_CHECK(nextTarget <= powLimit);
        BOOST_CHECK(nextTarget > currentTarget);
        BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c2f13b9);

    // Due to the window of time being bounded, next block's difficulty actually
    // gets harder.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
    nBits = GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params);
    BOOST_CHECK_EQUAL(nBits, 0x1c2ee9bf);

    // And goes down again. It takes a while due to the window being bounded and
    // the skewed block causes 2 blocks to get out of the window.
    for (size_t j = 0; j < 192; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Check the difficulty decreases.
        BOOST_CHECK(nextTarget <= powLimit);
        BOOST_CHECK(nextTarget > currentTarget);
        BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1d00ffff);

    // Once the difficulty reached the minimum allowed level, it doesn't get any
    // easier.
    for (size_t j = 0; j < 5; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        // Check the difficulty stays constant.
        BOOST_CHECK_EQUAL(nextBits, powLimitBits);
        nBits = nextBits;
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Trigger DAA underflow in DAA unit tests<commit_after>// Copyright (c) 2015-2019 The Bitcoin Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <pow/daa.h>

#include <chain.h>
#include <chainparams.h>
#include <config.h>

#include <test/util/setup_common.h>

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(daa_tests, BasicTestingSetup)

static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval,
                                 uint32_t nBits) {
    CBlockIndex block;
    block.pprev = pindexPrev;
    block.nHeight = pindexPrev->nHeight + 1;
    block.nTime = pindexPrev->nTime + nTimeInterval;
    block.nBits = nBits;

    block.nChainWork = pindexPrev->nChainWork + GetBlockProof(block);
    return block;
}

BOOST_AUTO_TEST_CASE(daa_test) {
    DummyConfig config(CBaseChainParams::MAIN);

    std::vector<CBlockIndex> blocks(3000);

    const Consensus::Params &params = config.GetChainParams().GetConsensus();
    const arith_uint256 powLimit = UintToArith256(params.powLimit);
    uint32_t powLimitBits = powLimit.GetCompact();
    arith_uint256 currentPow = powLimit >> 4;
    uint32_t initialBits = currentPow.GetCompact();

    // Genesis block.
    blocks[0] = CBlockIndex();
    blocks[0].nHeight = 0;
    blocks[0].nTime = 1269211443;
    blocks[0].nBits = initialBits;

    blocks[0].nChainWork = GetBlockProof(blocks[0]);

    // Block counter.
    size_t i;

    // Pile up some blocks every 10 mins to establish some history.
    for (i = 1; i < 2050; i++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 600, initialBits);
    }

    CBlockHeader blkHeaderDummy;
    uint32_t nBits =
        GetNextDAAWorkRequired(&blocks[2049], &blkHeaderDummy, params);

    // Difficulty stays the same as long as we produce a block every 10 mins.
    for (size_t j = 0; j < 10; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
        BOOST_CHECK_EQUAL(
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params), nBits);
    }

    // Make sure we skip over blocks that are out of wack. To do so, we produce
    // a block that is far in the future, and then produce a block with the
    // expected timestamp.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
    BOOST_CHECK_EQUAL(
        GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);
    blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 600 - 6000, nBits);
    BOOST_CHECK_EQUAL(
        GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);

    // The system should continue unaffected by the block with a bogous
    // timestamps.
    for (size_t j = 0; j < 20; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits);
        BOOST_CHECK_EQUAL(
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params), nBits);
    }

    // We start emitting blocks slightly faster. The first block has no impact.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits);
    BOOST_CHECK_EQUAL(
        GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params), nBits);

    // Now we should see difficulty increase slowly.
    for (size_t j = 0; j < 10; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Make sure that difficulty increases very slowly.
        BOOST_CHECK(nextTarget < currentTarget);
        BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 10));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c0fe7b1);

    // If we dramatically shorten block production, difficulty increases faster.
    for (size_t j = 0; j < 20; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Make sure that difficulty increases faster.
        BOOST_CHECK(nextTarget < currentTarget);
        BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 4));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c0db19f);

    // We start to emit blocks significantly slower. The first block has no
    // impact.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
    nBits = GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params);

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c0d9222);

    // If we dramatically slow down block production, difficulty decreases.
    for (size_t j = 0; j < 93; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Check the difficulty decreases.
        BOOST_CHECK(nextTarget <= powLimit);
        BOOST_CHECK(nextTarget > currentTarget);
        BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c2f13b9);

    // Due to the window of time being bounded, next block's difficulty actually
    // gets harder.
    blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
    nBits = GetNextDAAWorkRequired(&blocks[i++], &blkHeaderDummy, params);
    BOOST_CHECK_EQUAL(nBits, 0x1c2ee9bf);

    // And goes down again. It takes a while due to the window being bounded and
    // the skewed block causes 2 blocks to get out of the window.
    for (size_t j = 0; j < 192; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Check the difficulty decreases.
        BOOST_CHECK(nextTarget <= powLimit);
        BOOST_CHECK(nextTarget > currentTarget);
        BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1d00ffff);

    // Once the difficulty reached the minimum allowed level, it doesn't get any
    // easier.
    for (size_t j = 0; j < 5; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        // Check the difficulty stays constant.
        BOOST_CHECK_EQUAL(nextBits, powLimitBits);
        nBits = nextBits;
    }

    // We will now mine blocks much faster. For a while, the difficulty will
    // continue to go down.
    for (size_t j = 0; j < 130; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Check the difficulty decreases.
        BOOST_CHECK(nextTarget <= powLimit);
        BOOST_CHECK(nextTarget >= currentTarget);
        BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3));

        nBits = nextBits;
    }

    // Now the difficulty will go back up, and evetually we will trigger the
    // cliff code.
    for (size_t j = 0; j < 70; i++, j++) {
        blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits);
        const uint32_t nextBits =
            GetNextDAAWorkRequired(&blocks[i], &blkHeaderDummy, params);

        arith_uint256 currentTarget;
        currentTarget.SetCompact(nBits);
        arith_uint256 nextTarget;
        nextTarget.SetCompact(nextBits);

        // Check the difficulty decreases.
        BOOST_CHECK(nextTarget < currentTarget);
        BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 3));

        nBits = nextBits;
    }

    // Check the actual value.
    BOOST_CHECK_EQUAL(nBits, 0x1c4c068c);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 * Entry point
 *
 * The kernel is "bootloaded" by an unconditional branch to start_kernel(). The
 * name is inconsequential, it only needs to be consistent.
 *
 * Authors:
 *  Scott Linder
 */

#include "led.hh"
#include "timer.hh"

extern "C"
void start_kernel() {
    LED ok;
    Timer timer;
    while (1) {
        ok.on();
        timer.wait(0x3f0000);
        ok.off();
        timer.wait(0x3f0000);
    }
}
<commit_msg>Moved main to use new timer.<commit_after>/*
 * Entry point
 *
 * The kernel is "bootloaded" by an unconditional branch to start_kernel(). The
 * name is inconsequential, it only needs to be consistent.
 *
 * Authors:
 *  Scott Linder
 */

#include "ok.hh"
#include "timer.hh"

extern "C"
void start_kernel() {
    OK ok;
    Timer timer;
    const auto kDelay = 40000_usecs;
    while (1) {
        ok.on();
        timer.wait(kDelay);
        ok.off();
        timer.wait(kDelay);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#pragma once

#include <cstdint>
#include <functional>

namespace sak
{
    /// Input stream abstraction
    class input_stream
    {
    public:

        /// Destructor
        virtual ~input_stream()
        {}

        /// Request a read from the io device
        /// @param buffer from where to read
        /// @param bytes to read
        virtual void read(uint8_t* buffer, uint32_t bytes) = 0;

        /// Returns the number of bytes available for reading
        /// @return number of bytes available
        virtual uint32_t bytes_available() = 0;

        /// Indicates if more data will be produced. For a live stream,
        /// the function will return true after the stream finishes.
        /// For a finite stream (e.g. a file) the function will always
        /// return true.
        virtual bool stopped() = 0;

    public:

        /// Signal emitted when data can be read
        typedef std::function<void ()> ready_read_callback;

        /// Specify callbacks to allow the caller to determine if
        /// new data has arrived which is ready to be read.
        /// @param slot the slot to connect
        void on_ready_read(const ready_read_callback& callback)
        {
            m_ready_read_callback = callback;
        }

        /// Signal emitted on error
        typedef std::function<void (const std::string&)> error_callback;

        /// Connect to the error signal
        /// @param slot the function to call
        void on_error(const error_callback& callback)
        {
            m_error_callback = callback;
        }

        /// Signal emitted when the stream is stopped
        typedef std::function<void ()> stopped_callback;

        /// Connect to the stopped signal
        /// @param slot the function to call
        void on_stopped(const stopped_callback& callback)
        {
            m_stopped_callback = callback;
        }

    protected:

        /// The ready read signal
        ready_read_callback m_ready_read_callback;

        /// The error signal
        error_callback m_error_callback;

        /// The stopped signals
        stopped_callback m_stopped_callback;
    };
}
<commit_msg>Fix doxygen warnings<commit_after>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#pragma once

#include <cstdint>
#include <functional>

namespace sak
{
    /// Input stream abstraction
    class input_stream
    {
    public:

        /// Destructor
        virtual ~input_stream()
        {}

        /// Request a read from the io device
        /// @param buffer from where to read
        /// @param bytes to read
        virtual void read(uint8_t* buffer, uint32_t bytes) = 0;

        /// Returns the number of bytes available for reading
        /// @return number of bytes available
        virtual uint32_t bytes_available() = 0;

        /// Indicates if more data will be produced. For a live stream,
        /// the function will return true after the stream finishes.
        /// For a finite stream (e.g. a file) the function will always
        /// return true.
        virtual bool stopped() = 0;

    public:

        /// Signal emitted when data can be read
        typedef std::function<void ()> ready_read_callback;

        /// Specify callbacks to allow the caller to determine if
        /// new data has arrived which is ready to be read.
        /// @param callback the callback function
        void on_ready_read(const ready_read_callback& callback)
        {
            m_ready_read_callback = callback;
        }

        /// Signal emitted on error
        typedef std::function<void (const std::string&)> error_callback;

        /// Specify the callback function that is invoked when an error occurs.
        /// @param callback the callback function
        void on_error(const error_callback& callback)
        {
            m_error_callback = callback;
        }

        /// Signal emitted when the stream is stopped
        typedef std::function<void ()> stopped_callback;

        /// Specify the callback function that is invoked when the stream
        /// is stopped.
        /// @param callback the callback function
        void on_stopped(const stopped_callback& callback)
        {
            m_stopped_callback = callback;
        }

    protected:

        /// The ready read signal
        ready_read_callback m_ready_read_callback;

        /// The error signal
        error_callback m_error_callback;

        /// The stopped signals
        stopped_callback m_stopped_callback;
    };
}
<|endoftext|>