<commit_before>#include <qt/communityfundcreatepaymentrequestdialog.h>
#include <qt/communityfundsuccessdialog.h>
#include <qt/sendcommunityfunddialog.h>
#include <ui_communityfundcreatepaymentrequestdialog.h>

#include <QMessageBox>
#include <string>

#include <base58.h>
#include <consensus/cfund.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <main.cpp>
#include <main.h>
#include <qt/skinize.h>
#include <sync.h>
#include <wallet/wallet.h>
#include <qt/walletmodel.h>

std::string random_str(size_t length)
{
    auto randchar = []() -> char
    {
        const char charset[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[ rand() % max_index ];
    };
    std::string str(length,0);
    std::generate_n( str.begin(), length, randchar );
    return str;
}

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

    connect(ui->pushButtonClose, SIGNAL(clicked()), this, SLOT(reject()));
    connect(ui->pushButtonSubmitPaymentRequest, SIGNAL(clicked()), SLOT(click_pushButtonSubmitPaymentRequest()));
}

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

bool CommunityFundCreatePaymentRequestDialog::validate()
{
    bool isValid = true;

    // Proposal hash;
    if(!isActiveProposal(uint256S(ui->lineEditProposalHash->text().toStdString())))
    {
        isValid = false;
        ui->lineEditProposalHash->setValid(false);
    }

    // Amount
    if(!ui->lineEditRequestedAmount->validate())
    {
        isValid = false;
        ui->lineEditRequestedAmount->setValid(false);
    }

    // Description
    size_t desc_size = ui->plainTextEditDescription->toPlainText().toStdString().length();
    if(desc_size >= 1024 || desc_size == 0)
    {
        isValid = false;
        ui->plainTextEditDescription->setValid(false);
    }
    else
    {
        ui->plainTextEditDescription->setValid(true);
    }

    return isValid;
}

void CommunityFundCreatePaymentRequestDialog::click_pushButtonSubmitPaymentRequest()
{

    if(this->validate())
    {
        LOCK2(cs_main, pwalletMain->cs_wallet);

        // Get Proposal
        CFund::CProposal proposal;
        if(!pcoinsTip->GetProposal(uint256S(ui->lineEditProposalHash->text().toStdString()), proposal)) {
            QMessageBox msgBox(this);
            std::string str = "Proposal could not be found with that hash\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Proposal not found");
            msgBox.exec();
            return;
        }
        if(proposal.fState != CFund::ACCEPTED) {
            QMessageBox msgBox(this);
            std::string str = "Proposals need to have been accepted to create a Payment Request for them\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Proposal not accepted");
            msgBox.exec();
            return;
        }

        // Get Address
        CNavCoinAddress address(proposal.Address);
        if(!address.IsValid()) {
            QMessageBox msgBox(this);
            std::string str = "The address of the Proposal is not valid\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Address not valid");
            msgBox.exec();
            return;
        }

        // Get KeyID
        CKeyID keyID;
        if (!address.GetKeyID(keyID)) {
            QMessageBox msgBox(this);
            std::string str = "The address does not refer to a key\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Address not valid");
            msgBox.exec();
            return;
        }

        // Ensure wallet is unlocked
        WalletModel::UnlockContext ctx(model->requestUnlock());
        if(!ctx.isValid())
        {
            // Unlock wallet was cancelled
            return;
        }

        // Get Key
        CKey key;
        if (!pwalletMain->GetKey(keyID, key)) {
            QMessageBox msgBox(this);
            std::string str = "You are not the owner of the Proposal\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Not the owner");
            msgBox.exec();
            return;
        }

        // Get fields from form
        CAmount nReqAmount = ui->lineEditRequestedAmount->value();
        std::string id = ui->plainTextEditDescription->toPlainText().toStdString();
        std::string sRandom = random_str(16);

        // Construct Secret
        std::string Secret = sRandom + "I kindly ask to withdraw " +
                std::to_string(nReqAmount) + "NAV from the proposal " +
                proposal.hash.ToString() + ". Payment request id: " + id;

        CHashWriter ss(SER_GETHASH, 0);
        ss << strMessageMagic;
        ss << Secret;

        // Attempt to sign
        vector<unsigned char> vchSig;
        if (!key.SignCompact(ss.GetHash(), vchSig)) {
            QMessageBox msgBox(this);
            std::string str = "Failed to sign\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Sign Failed");
            msgBox.exec();
            return;
        }

        // Create Signature
        std::string Signature = EncodeBase64(&vchSig[0], vchSig.size());

        // Validate requested amount
        if (nReqAmount <= 0 || nReqAmount > proposal.GetAvailable(*pcoinsTip, true)) {
            QMessageBox msgBox(this);
            std::string str = "Cannot create a Payment Request for the requested amount\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Invalid Amount");
            msgBox.exec();
            return;
        }

        // Create wtx
        CWalletTx wtx;
        bool fSubtractFeeFromAmount = false;

        UniValue strDZeel(UniValue::VOBJ);

        strDZeel.pushKV("h",ui->lineEditProposalHash->text().toStdString());
        strDZeel.pushKV("n",nReqAmount);
        strDZeel.pushKV("s",Signature);
        strDZeel.pushKV("r",sRandom);
        strDZeel.pushKV("i",id);
        strDZeel.pushKV("v",IsReducedCFundQuorumEnabled(chainActive.Tip(), Params().GetConsensus()) ? CFund::CPaymentRequest::CURRENT_VERSION : 2);

        wtx.strDZeel = strDZeel.write();
        wtx.nCustomVersion = CTransaction::PAYMENT_REQUEST_VERSION;

        // Validate wtx
        if(wtx.strDZeel.length() > 1024) {
            QMessageBox msgBox(this);
            std::string str = "Description too long\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Invalid String");
            msgBox.exec();
            return;
        }

        // Check balance
        CAmount curBalance = pwalletMain->GetBalance();
        if (curBalance <= 10000) {
            QMessageBox msgBox(this);
            string fee = std::to_string(10000 / COIN);
            std::string str = "You require at least " + fee + " NAV mature and available to create a payment request\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Insufficient NAV");
            msgBox.exec();
            return;
        }

        // Create partial proposal object with all nessesary display fields from input and create confirmation dialog
        {
            // Create confirmation dialog
            CFund::CPaymentRequest* preq = new CFund::CPaymentRequest();
            preq->nAmount = ui->lineEditRequestedAmount->value();
            preq->proposalhash = proposal.hash;
            preq->strDZeel = ui->plainTextEditDescription->toPlainText().toStdString();

            SendCommunityFundDialog dlg(this, preq, 10);
            if(dlg.exec()== QDialog::Rejected) {
                // User Declined to make the prequest
                return;
            }
            else {
                // User accepted making the prequest
                // Parse NavCoin address
                CScript CFContributionScript;
                CScript scriptPubKey = GetScriptForDestination(address.Get());
                CFund::SetScriptForCommunityFundContribution(scriptPubKey);

                // Create and send the transaction
                CReserveKey reservekey(pwalletMain);
                CAmount nFeeRequired;
                std::string strError;
                vector<CRecipient> vecSend;
                int nChangePosRet = -1;
                CAmount nValue = 1000;
                CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount, ""};
                vecSend.push_back(recipient);

                bool created_prequest = true;

                if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError, nullptr, true, "")) {
                    if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance()) {
                        created_prequest = false;
                    }
                }
                if (!pwalletMain->CommitTransaction(wtx, reservekey)) {
                    created_prequest = false;
                }

                // If the proposal was successfully made, confirm to the user it was made
                if (created_prequest) {
                    // Display success UI
                    CommunityFundSuccessDialog dlg(wtx.GetHash(), this, preq);
                    dlg.exec();
                    QDialog::accept();
                    return;
                }
                else {
                    // Display something went wrong UI
                    QMessageBox msgBox(this);
                    std::string str = "Payment Request creation failed\n";
                    msgBox.setText(tr(str.c_str()));
                    msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
                    msgBox.setIcon(QMessageBox::Warning);
                    msgBox.setWindowTitle("Error");
                    msgBox.exec();
                    return;
                }
            }
        }
    }
    else
    {
        QMessageBox msgBox(this);
        QString str = tr("Please enter a valid:\n");
        if(!isActiveProposal(uint256S(ui->lineEditProposalHash->text().toStdString())))
            str += QString(tr("- Proposal Hash\n"));
        if(!ui->lineEditRequestedAmount->validate())
            str += QString(tr("- Requested Amount\n"));
        if(ui->plainTextEditDescription->toPlainText() == QString("") || ui->plainTextEditDescription->toPlainText().size() <= 0)
            str += QString(tr("- Description\n"));

        msgBox.setText(str);
        msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
        msgBox.setIcon(QMessageBox::Warning);
        msgBox.exec();
        return;
    }
}

bool CommunityFundCreatePaymentRequestDialog::isActiveProposal(uint256 hash)
{
    std::vector<CFund::CProposal> vec;
    CProposalMap mapProposals;

    if(pcoinsTip->GetAllProposals(mapProposals))
    {
        for (CProposalMap::iterator it = mapProposals.begin(); it != mapProposals.end(); it++)
        {
            CFund::CProposal proposal;
            if (!pcoinsTip->GetProposal(it->first, proposal))
                continue;
            vec.push_back(proposal);
        }

        if(std::find_if(vec.begin(), vec.end(), [&hash](CFund::CProposal& obj) {return obj.hash == hash;}) == vec.end())
        {
            return false;
        }
    }

    return true;
}

CommunityFundCreatePaymentRequestDialog::~CommunityFundCreatePaymentRequestDialog()
{
    delete ui;
}
<commit_msg>Added clearer error messages for the nRequest amount validation (#609)<commit_after>#include <qt/communityfundcreatepaymentrequestdialog.h>
#include <qt/communityfundsuccessdialog.h>
#include <qt/sendcommunityfunddialog.h>
#include <ui_communityfundcreatepaymentrequestdialog.h>

#include <QMessageBox>
#include <string>

#include <qt/navcoinunits.h>

#include <base58.h>
#include <consensus/cfund.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <main.cpp>
#include <main.h>
#include <qt/skinize.h>
#include <sync.h>
#include <wallet/wallet.h>
#include <qt/walletmodel.h>

std::string random_str(size_t length)
{
    auto randchar = []() -> char
    {
        const char charset[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[ rand() % max_index ];
    };
    std::string str(length,0);
    std::generate_n( str.begin(), length, randchar );
    return str;
}

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

    connect(ui->pushButtonClose, SIGNAL(clicked()), this, SLOT(reject()));
    connect(ui->pushButtonSubmitPaymentRequest, SIGNAL(clicked()), SLOT(click_pushButtonSubmitPaymentRequest()));
}

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

bool CommunityFundCreatePaymentRequestDialog::validate()
{
    bool isValid = true;

    // Proposal hash;
    if(!isActiveProposal(uint256S(ui->lineEditProposalHash->text().toStdString())))
    {
        isValid = false;
        ui->lineEditProposalHash->setValid(false);
    }

    // Amount
    if(!ui->lineEditRequestedAmount->validate())
    {
        isValid = false;
        ui->lineEditRequestedAmount->setValid(false);
    }

    // Description
    size_t desc_size = ui->plainTextEditDescription->toPlainText().toStdString().length();
    if(desc_size >= 1024 || desc_size == 0)
    {
        isValid = false;
        ui->plainTextEditDescription->setValid(false);
    }
    else
    {
        ui->plainTextEditDescription->setValid(true);
    }

    return isValid;
}

void CommunityFundCreatePaymentRequestDialog::click_pushButtonSubmitPaymentRequest()
{

    if(this->validate())
    {
        LOCK2(cs_main, pwalletMain->cs_wallet);

        // Get Proposal
        CFund::CProposal proposal;
        if(!pcoinsTip->GetProposal(uint256S(ui->lineEditProposalHash->text().toStdString()), proposal)) {
            QMessageBox msgBox(this);
            std::string str = "Proposal could not be found with that hash\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Proposal not found");
            msgBox.exec();
            return;
        }
        if(proposal.fState != CFund::ACCEPTED) {
            QMessageBox msgBox(this);
            std::string str = "Proposals need to have been accepted to create a Payment Request for them\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Proposal not accepted");
            msgBox.exec();
            return;
        }

        // Get Address
        CNavCoinAddress address(proposal.Address);
        if(!address.IsValid()) {
            QMessageBox msgBox(this);
            std::string str = "The address of the Proposal is not valid\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Address not valid");
            msgBox.exec();
            return;
        }

        // Get KeyID
        CKeyID keyID;
        if (!address.GetKeyID(keyID)) {
            QMessageBox msgBox(this);
            std::string str = "The address does not refer to a key\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Address not valid");
            msgBox.exec();
            return;
        }

        // Ensure wallet is unlocked
        WalletModel::UnlockContext ctx(model->requestUnlock());
        if(!ctx.isValid())
        {
            // Unlock wallet was cancelled
            return;
        }

        // Get Key
        CKey key;
        if (!pwalletMain->GetKey(keyID, key)) {
            QMessageBox msgBox(this);
            std::string str = "You are not the owner of the Proposal\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Not the owner");
            msgBox.exec();
            return;
        }

        // Get fields from form
        CAmount nReqAmount = ui->lineEditRequestedAmount->value();
        std::string id = ui->plainTextEditDescription->toPlainText().toStdString();
        std::string sRandom = random_str(16);

        // Construct Secret
        std::string Secret = sRandom + "I kindly ask to withdraw " +
                std::to_string(nReqAmount) + "NAV from the proposal " +
                proposal.hash.ToString() + ". Payment request id: " + id;

        CHashWriter ss(SER_GETHASH, 0);
        ss << strMessageMagic;
        ss << Secret;

        // Attempt to sign
        vector<unsigned char> vchSig;
        if (!key.SignCompact(ss.GetHash(), vchSig)) {
            QMessageBox msgBox(this);
            std::string str = "Failed to sign\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Sign Failed");
            msgBox.exec();
            return;
        }

        // Create Signature
        std::string Signature = EncodeBase64(&vchSig[0], vchSig.size());

        // Validate requested amount
        if (nReqAmount <= 0 || nReqAmount > proposal.GetAvailable(*pcoinsTip, true)) {
            QMessageBox msgBox(this);
            QString str = tr("Requested amount must be greater than 0 NAV (Zero)\n");
            if (nReqAmount > proposal.GetAvailable(*pcoinsTip, true)) {
                str = tr("Requested amount %1 is more than avaible coins in the proposal (%2)\n")
                    .arg(
                        NavCoinUnits::formatWithUnit(NavCoinUnits::NAV, nReqAmount),
                        NavCoinUnits::formatWithUnit(NavCoinUnits::NAV, proposal.GetAvailable(*pcoinsTip, true))
                    );
            }
            msgBox.setText(str);
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle(tr("Invalid Amount"));
            msgBox.exec();
            return;
        }

        // Create wtx
        CWalletTx wtx;
        bool fSubtractFeeFromAmount = false;

        UniValue strDZeel(UniValue::VOBJ);

        strDZeel.pushKV("h",ui->lineEditProposalHash->text().toStdString());
        strDZeel.pushKV("n",nReqAmount);
        strDZeel.pushKV("s",Signature);
        strDZeel.pushKV("r",sRandom);
        strDZeel.pushKV("i",id);
        strDZeel.pushKV("v",IsReducedCFundQuorumEnabled(chainActive.Tip(), Params().GetConsensus()) ? CFund::CPaymentRequest::CURRENT_VERSION : 2);

        wtx.strDZeel = strDZeel.write();
        wtx.nCustomVersion = CTransaction::PAYMENT_REQUEST_VERSION;

        // Validate wtx
        if(wtx.strDZeel.length() > 1024) {
            QMessageBox msgBox(this);
            std::string str = "Description too long\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Invalid String");
            msgBox.exec();
            return;
        }

        // Check balance
        CAmount curBalance = pwalletMain->GetBalance();
        if (curBalance <= 10000) {
            QMessageBox msgBox(this);
            string fee = std::to_string(10000 / COIN);
            std::string str = "You require at least " + fee + " NAV mature and available to create a payment request\n";
            msgBox.setText(tr(str.c_str()));
            msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
            msgBox.setIcon(QMessageBox::Warning);
            msgBox.setWindowTitle("Insufficient NAV");
            msgBox.exec();
            return;
        }

        // Create partial proposal object with all nessesary display fields from input and create confirmation dialog
        {
            // Create confirmation dialog
            CFund::CPaymentRequest* preq = new CFund::CPaymentRequest();
            preq->nAmount = ui->lineEditRequestedAmount->value();
            preq->proposalhash = proposal.hash;
            preq->strDZeel = ui->plainTextEditDescription->toPlainText().toStdString();

            SendCommunityFundDialog dlg(this, preq, 10);
            if(dlg.exec()== QDialog::Rejected) {
                // User Declined to make the prequest
                return;
            }
            else {
                // User accepted making the prequest
                // Parse NavCoin address
                CScript CFContributionScript;
                CScript scriptPubKey = GetScriptForDestination(address.Get());
                CFund::SetScriptForCommunityFundContribution(scriptPubKey);

                // Create and send the transaction
                CReserveKey reservekey(pwalletMain);
                CAmount nFeeRequired;
                std::string strError;
                vector<CRecipient> vecSend;
                int nChangePosRet = -1;
                CAmount nValue = 1000;
                CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount, ""};
                vecSend.push_back(recipient);

                bool created_prequest = true;

                if (!pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRequired, nChangePosRet, strError, nullptr, true, "")) {
                    if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance()) {
                        created_prequest = false;
                    }
                }
                if (!pwalletMain->CommitTransaction(wtx, reservekey)) {
                    created_prequest = false;
                }

                // If the proposal was successfully made, confirm to the user it was made
                if (created_prequest) {
                    // Display success UI
                    CommunityFundSuccessDialog dlg(wtx.GetHash(), this, preq);
                    dlg.exec();
                    QDialog::accept();
                    return;
                }
                else {
                    // Display something went wrong UI
                    QMessageBox msgBox(this);
                    std::string str = "Payment Request creation failed\n";
                    msgBox.setText(tr(str.c_str()));
                    msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
                    msgBox.setIcon(QMessageBox::Warning);
                    msgBox.setWindowTitle("Error");
                    msgBox.exec();
                    return;
                }
            }
        }
    }
    else
    {
        QMessageBox msgBox(this);
        QString str = tr("Please enter a valid:\n");
        if(!isActiveProposal(uint256S(ui->lineEditProposalHash->text().toStdString())))
            str += QString(tr("- Proposal Hash\n"));
        if(!ui->lineEditRequestedAmount->validate())
            str += QString(tr("- Requested Amount\n"));
        if(ui->plainTextEditDescription->toPlainText() == QString("") || ui->plainTextEditDescription->toPlainText().size() <= 0)
            str += QString(tr("- Description\n"));

        msgBox.setText(str);
        msgBox.addButton(tr("Ok"), QMessageBox::AcceptRole);
        msgBox.setIcon(QMessageBox::Warning);
        msgBox.exec();
        return;
    }
}

bool CommunityFundCreatePaymentRequestDialog::isActiveProposal(uint256 hash)
{
    std::vector<CFund::CProposal> vec;
    CProposalMap mapProposals;

    if(pcoinsTip->GetAllProposals(mapProposals))
    {
        for (CProposalMap::iterator it = mapProposals.begin(); it != mapProposals.end(); it++)
        {
            CFund::CProposal proposal;
            if (!pcoinsTip->GetProposal(it->first, proposal))
                continue;
            vec.push_back(proposal);
        }

        if(std::find_if(vec.begin(), vec.end(), [&hash](CFund::CProposal& obj) {return obj.hash == hash;}) == vec.end())
        {
            return false;
        }
    }

    return true;
}

CommunityFundCreatePaymentRequestDialog::~CommunityFundCreatePaymentRequestDialog()
{
    delete ui;
}
<|endoftext|>


<commit_before>#include "Mailer.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
#include "database.h"
#include "../urlplugin/IUrlFactory.h"
#include "ClientMain.h"
#include <math.h>

IMutex* Mailer::mutex = NULL;
ICondition* Mailer::cond = NULL;
bool Mailer::queue_limit = false;
bool Mailer::queued_mail = false;
extern IUrlFactory *url_fak;

bool Mailer::sendMail(const std::string & send_to, const std::string & subject, const std::string & message)
{
	IScopedLock lock(mutex);
	if (queue_limit)
		return false;

	lock.relock(NULL);

	IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
	DBScopedSynchronous db_synchronous(db);
	IQuery* q = db->Prepare("INSERT INTO mail_queue (send_to, subject, message) VALUES (?,?,?)", false);
	q->Bind(send_to);
	q->Bind(subject);
	q->Bind(message);
	bool b = q->Write();

	if (b)
	{
		lock.relock(mutex);
		cond->notify_all();
		queued_mail = true;
	}

	db->destroyQuery(q);

	return b;
}

void Mailer::init()
{
	mutex = Server->createMutex();
	cond = Server->createCondition();
	Server->createThread(new Mailer, "mail queue");
}

void Mailer::operator()()
{
	if (url_fak == NULL)
		return;

	bool has_mail_server;
	{
		MailServer mail_server = ClientMain::getMailServerSettings();
		has_mail_server = !mail_server.servername.empty();
	}

	if (!has_mail_server)
	{
		queue_limit = true;
	}

	IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
	IQuery* q_get_mail = db->Prepare("SELECT id, send_to, subject, message, next_try, retry_count FROM mail_queue WHERE next_try IS NULL or next_try>=?");
	IQuery* q_set_retry = db->Prepare("UPDATE mail_queue SET next_try=?, retry_count=? WHERE id=?");
	IQuery* q_remove_mail = db->Prepare("DELETE FROM mail_queue WHERE id=?");

	db->Write("UPDATE mail_queue SET next_try=NULL");

	while (true)
	{
		{
			IScopedLock lock(mutex);
			if (!queued_mail)
			{
				cond->wait(&lock, 5 * 60 * 1000);
				queued_mail = false;
			}
		}

		q_get_mail->Bind(Server->getTimeMS());
		db_results res = q_get_mail->Read();
		q_get_mail->Reset();

		if (res.size() > 1000)
		{
			IScopedLock lock(mutex);
			queue_limit = true;
		}
		else if (queue_limit
			&& has_mail_server)
		{
			IScopedLock lock(mutex);
			queue_limit = false;
		}

		MailServer mail_server;

		if (!res.empty() || !has_mail_server)
		{
			mail_server = ClientMain::getMailServerSettings();
		}

		if (mail_server.servername.empty())
		{
			has_mail_server = false;
			continue;
		}
		else
		{
			has_mail_server = true;
		}

		for (size_t i = 0; i < res.size(); ++i)
		{
			std::vector<std::string> addrs;
			Tokenize(res[i]["send_to"], addrs, ";,");

			std::string errmsg;
			if (!url_fak->sendMail(mail_server, addrs, res[i]["subject"], res[i]["message"], &errmsg))
			{
				int n = watoi(res[i]["retry_count"]);
				unsigned int waittime = (std::min)(static_cast<unsigned int>(1000.*pow(2., static_cast<double>(n))), (unsigned int)30 * 60 * 1000); //30min
				if (n>20)
				{
					waittime = (unsigned int)30 * 60 * 1000;
				}

				Server->Log("Error sending mail to \"" + res[i]["send_to"] + "\". " + errmsg + ". Retrying in " + PrettyPrintTime(waittime), LL_WARNING);

				q_set_retry->Bind(Server->getTimeMS()+waittime);
				q_set_retry->Bind(n + 1);
				q_set_retry->Bind(res[i]["id"]);
				q_set_retry->Write();
				q_set_retry->Reset();
			}
			else
			{
				q_remove_mail->Bind(res[i]["id"]);
				q_remove_mail->Write();
				q_remove_mail->Reset();
			}
		}
	}
}
<commit_msg>Reset queued_mail<commit_after>#include "Mailer.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
#include "database.h"
#include "../urlplugin/IUrlFactory.h"
#include "ClientMain.h"
#include <math.h>

IMutex* Mailer::mutex = NULL;
ICondition* Mailer::cond = NULL;
bool Mailer::queue_limit = false;
bool Mailer::queued_mail = false;
extern IUrlFactory *url_fak;

bool Mailer::sendMail(const std::string & send_to, const std::string & subject, const std::string & message)
{
	IScopedLock lock(mutex);
	if (queue_limit)
		return false;

	lock.relock(NULL);

	IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
	DBScopedSynchronous db_synchronous(db);
	IQuery* q = db->Prepare("INSERT INTO mail_queue (send_to, subject, message) VALUES (?,?,?)", false);
	q->Bind(send_to);
	q->Bind(subject);
	q->Bind(message);
	bool b = q->Write();

	if (b)
	{
		lock.relock(mutex);
		cond->notify_all();
		queued_mail = true;
	}

	db->destroyQuery(q);

	return b;
}

void Mailer::init()
{
	mutex = Server->createMutex();
	cond = Server->createCondition();
	Server->createThread(new Mailer, "mail queue");
}

void Mailer::operator()()
{
	if (url_fak == NULL)
		return;

	bool has_mail_server;
	{
		MailServer mail_server = ClientMain::getMailServerSettings();
		has_mail_server = !mail_server.servername.empty();
	}

	if (!has_mail_server)
	{
		queue_limit = true;
	}

	IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
	IQuery* q_get_mail = db->Prepare("SELECT id, send_to, subject, message, next_try, retry_count FROM mail_queue WHERE next_try IS NULL or next_try>=?");
	IQuery* q_set_retry = db->Prepare("UPDATE mail_queue SET next_try=?, retry_count=? WHERE id=?");
	IQuery* q_remove_mail = db->Prepare("DELETE FROM mail_queue WHERE id=?");

	db->Write("UPDATE mail_queue SET next_try=NULL");

	while (true)
	{
		{
			IScopedLock lock(mutex);
			if (!queued_mail)
			{
				cond->wait(&lock, 5 * 60 * 1000);
			}
			queued_mail = false;
		}

		q_get_mail->Bind(Server->getTimeMS());
		db_results res = q_get_mail->Read();
		q_get_mail->Reset();

		if (res.size() > 1000)
		{
			IScopedLock lock(mutex);
			queue_limit = true;
		}
		else if (queue_limit
			&& has_mail_server)
		{
			IScopedLock lock(mutex);
			queue_limit = false;
		}

		MailServer mail_server;

		if (!res.empty() || !has_mail_server)
		{
			mail_server = ClientMain::getMailServerSettings();
		}

		if (mail_server.servername.empty())
		{
			has_mail_server = false;
			continue;
		}
		else
		{
			has_mail_server = true;
		}

		for (size_t i = 0; i < res.size(); ++i)
		{
			std::vector<std::string> addrs;
			Tokenize(res[i]["send_to"], addrs, ";,");

			std::string errmsg;
			if (!url_fak->sendMail(mail_server, addrs, res[i]["subject"], res[i]["message"], &errmsg))
			{
				int n = watoi(res[i]["retry_count"]);
				unsigned int waittime = (std::min)(static_cast<unsigned int>(1000.*pow(2., static_cast<double>(n))), (unsigned int)30 * 60 * 1000); //30min
				if (n>20)
				{
					waittime = (unsigned int)30 * 60 * 1000;
				}

				Server->Log("Error sending mail to \"" + res[i]["send_to"] + "\". " + errmsg + ". Retrying in " + PrettyPrintTime(waittime), LL_WARNING);

				q_set_retry->Bind(Server->getTimeMS()+waittime);
				q_set_retry->Bind(n + 1);
				q_set_retry->Bind(res[i]["id"]);
				q_set_retry->Write();
				q_set_retry->Reset();
			}
			else
			{
				q_remove_mail->Bind(res[i]["id"]);
				q_remove_mail->Write();
				q_remove_mail->Reset();
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2008 Bertjan Broeksema <b.broeksema@kdemail.net>
    Copyright (c) 2008 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "singlefileresourcebase.h"

#include <akonadi/changerecorder.h>
#include <akonadi/collectiondisplayattribute.h>
#include <akonadi/itemfetchscope.h>

#include <KDebug>
#include <KDirWatch>
#include <KLocale>
#include <KStandardDirs>

#include <QDir>

using namespace Akonadi;

SingleFileResourceBase::SingleFileResourceBase( const QString & id ) :
    ResourceBase( id )
{
  connect( &mDirtyTimer, SIGNAL(timeout()), SLOT(writeFile()) );
  mDirtyTimer.setSingleShot( true );

  connect( this, SIGNAL(reloadConfiguration()), SLOT(reloadFile()) );
  QTimer::singleShot( 0, this, SLOT(readFile()) );

  changeRecorder()->itemFetchScope().fetchFullPayload();
  changeRecorder()->fetchCollection( true );

  connect( KDirWatch::self(), SIGNAL(dirty(QString)), SLOT(fileChanged(QString)) );
}

void SingleFileResourceBase::setSupportedMimetypes(const QStringList & mimeTypes, const QString &icon)
{
  mSupportedMimetypes = mimeTypes;
  mCollectionIcon = icon;
}

void SingleFileResourceBase::collectionChanged(const Akonadi::Collection & collection)
{
  QString newName = collection.name();
  if ( collection.hasAttribute<CollectionDisplayAttribute>() ) {
    CollectionDisplayAttribute *attr = collection.attribute<CollectionDisplayAttribute>();
    if ( !attr->displayName().isEmpty() )
      newName = attr->displayName();
  }

  if ( newName != name() )
    setName( newName );
}

void SingleFileResourceBase::reloadFile()
{
  // if we have something loaded already, make sure we write that back in case the settings changed
  if ( !mCurrentUrl.isEmpty() )
    writeFile();
 readFile();
}

void SingleFileResourceBase::fileChanged(const QString & fileName)
{
  if ( fileName != mCurrentUrl.path() )
    return;

  // handle conflicts
  if ( mDirtyTimer.isActive() && !mCurrentUrl.isEmpty() ) {
    const KUrl prevUrl = mCurrentUrl;
    int i = 0;
    QString lostFoundFileName;
    do {
      lostFoundFileName = KStandardDirs::locateLocal( "data", identifier() + QDir::separator()
          + prevUrl.fileName() + "-" + QString::number( ++i ) );
    } while ( KStandardDirs::exists( lostFoundFileName ) );
    mCurrentUrl = KUrl( lostFoundFileName );
    writeFile();
    emit warning( i18n( "The file '%1' was changed on disk while there were still pending changes in Akonadi. "
        "To avoid dataloss, a backup of the internal changes has been created at '%2'.",
         prevUrl.prettyUrl(), mCurrentUrl.prettyUrl() ) );
    mCurrentUrl = prevUrl;
  }

  readFile();
  synchronize();
}

#include "singlefileresourcebase.moc"
<commit_msg>Do a sync after reloading the file, so that the contacts and events show up directly after running the migrator.<commit_after>/*
    Copyright (c) 2008 Bertjan Broeksema <b.broeksema@kdemail.net>
    Copyright (c) 2008 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "singlefileresourcebase.h"

#include <akonadi/changerecorder.h>
#include <akonadi/collectiondisplayattribute.h>
#include <akonadi/itemfetchscope.h>

#include <KDebug>
#include <KDirWatch>
#include <KLocale>
#include <KStandardDirs>

#include <QDir>

using namespace Akonadi;

SingleFileResourceBase::SingleFileResourceBase( const QString & id ) :
    ResourceBase( id )
{
  connect( &mDirtyTimer, SIGNAL(timeout()), SLOT(writeFile()) );
  mDirtyTimer.setSingleShot( true );

  connect( this, SIGNAL(reloadConfiguration()), SLOT(reloadFile()) );
  QTimer::singleShot( 0, this, SLOT(readFile()) );

  changeRecorder()->itemFetchScope().fetchFullPayload();
  changeRecorder()->fetchCollection( true );

  connect( KDirWatch::self(), SIGNAL(dirty(QString)), SLOT(fileChanged(QString)) );
}

void SingleFileResourceBase::setSupportedMimetypes(const QStringList & mimeTypes, const QString &icon)
{
  mSupportedMimetypes = mimeTypes;
  mCollectionIcon = icon;
}

void SingleFileResourceBase::collectionChanged(const Akonadi::Collection & collection)
{
  QString newName = collection.name();
  if ( collection.hasAttribute<CollectionDisplayAttribute>() ) {
    CollectionDisplayAttribute *attr = collection.attribute<CollectionDisplayAttribute>();
    if ( !attr->displayName().isEmpty() )
      newName = attr->displayName();
  }

  if ( newName != name() )
    setName( newName );
}

void SingleFileResourceBase::reloadFile()
{
  // if we have something loaded already, make sure we write that back in case the settings changed
  if ( !mCurrentUrl.isEmpty() )
    writeFile();
 readFile();
 synchronize();
}

void SingleFileResourceBase::fileChanged(const QString & fileName)
{
  if ( fileName != mCurrentUrl.path() )
    return;

  // handle conflicts
  if ( mDirtyTimer.isActive() && !mCurrentUrl.isEmpty() ) {
    const KUrl prevUrl = mCurrentUrl;
    int i = 0;
    QString lostFoundFileName;
    do {
      lostFoundFileName = KStandardDirs::locateLocal( "data", identifier() + QDir::separator()
          + prevUrl.fileName() + "-" + QString::number( ++i ) );
    } while ( KStandardDirs::exists( lostFoundFileName ) );
    mCurrentUrl = KUrl( lostFoundFileName );
    writeFile();
    emit warning( i18n( "The file '%1' was changed on disk while there were still pending changes in Akonadi. "
        "To avoid dataloss, a backup of the internal changes has been created at '%2'.",
         prevUrl.prettyUrl(), mCurrentUrl.prettyUrl() ) );
    mCurrentUrl = prevUrl;
  }

  readFile();
  synchronize();
}

#include "singlefileresourcebase.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 Paulo Marques (pjp.marques@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Information about the P9813 protocol obtained from:
 * http://www.seeedstudio.com/wiki/index.php?title=Twig_-_Chainable_RGB_LED
 *
 * HSB to RGB routine adapted from:
 * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
 */

// --------------------------------------------------------------------------------------

#include "ChainableLED.h"

// Forward declaration
float hue2rgb(float p, float q, float t);

// --------------------------------------------------------------------------------------

ChainableLED::ChainableLED(byte clk_pin, byte data_pin, byte number_of_leds) :
    _clk_pin(clk_pin), _data_pin(data_pin), _num_leds(number_of_leds)
{
    _led_state = (byte*) calloc(_num_leds*3, sizeof(byte));
}

ChainableLED::~ChainableLED()
{
    free(_led_state);
}

// --------------------------------------------------------------------------------------

void ChainableLED::init()
{
    pinMode(_clk_pin, OUTPUT);
    pinMode(_data_pin, OUTPUT);

    for (byte i=0; i<_num_leds; i++)
        setColorRGB(i, 0, 0, 0);
}

void ChainableLED::clk(void)
{
    digitalWrite(_clk_pin, LOW);
    delayMicroseconds(_CLK_PULSE_DELAY);
    digitalWrite(_clk_pin, HIGH);
    delayMicroseconds(_CLK_PULSE_DELAY);
}

void ChainableLED::sendByte(byte b)
{
    // Send one bit at a time, starting with the MSB
    for (byte i=0; i<8; i++)
    {
        // If MSB is 1, write one and clock it, else write 0 and clock
        if ((b & 0x80) != 0)
            digitalWrite(_data_pin, HIGH);
        else
            digitalWrite(_data_pin, LOW);
        clk();

        // Advance to the next bit to send
        b <<= 1;
    }
}

void ChainableLED::sendColor(byte red, byte green, byte blue)
{
    // Start by sending a byte with the format "1 1 /B7 /B6 /G7 /G6 /R7 /R6"
    byte prefix = 0b11000000;
    if ((blue & 0x80) == 0)     prefix|= 0b00100000;
    if ((blue & 0x40) == 0)     prefix|= 0b00010000;
    if ((green & 0x80) == 0)    prefix|= 0b00001000;
    if ((green & 0x40) == 0)    prefix|= 0b00000100;
    if ((red & 0x80) == 0)      prefix|= 0b00000010;
    if ((red & 0x40) == 0)      prefix|= 0b00000001;
    sendByte(prefix);

    // Now must send the 3 colors
    sendByte(blue);
    sendByte(green);
    sendByte(red);
}

void ChainableLED::setColorRGB(byte led, byte red, byte green, byte blue)
{
    // Send data frame prefix (32x "0")
    sendByte(0x00);
    sendByte(0x00);
    sendByte(0x00);
    sendByte(0x00);

    // Send color data for each one of the leds
    for (byte i=0; i<_num_leds; i++)
    {
        if (i == led)
        {
            _led_state[i*3 + _CL_RED] = red;
            _led_state[i*3 + _CL_GREEN] = green;
            _led_state[i*3 + _CL_BLUE] = blue;
        }

        sendColor(_led_state[i*3 + _CL_RED],
                  _led_state[i*3 + _CL_GREEN],
                  _led_state[i*3 + _CL_BLUE]);
    }

    // Terminate data frame (32x "0")
    sendByte(0x00);
    sendByte(0x00);
    sendByte(0x00);
    sendByte(0x00);
}

void ChainableLED::setColorHSB(byte led, float hue, float saturation, float brightness)
{
    float r, g, b;

    constrain(hue, 0.0, 1.0);
    constrain(saturation, 0.0, 1.0);
    constrain(brightness, 0.0, 1.0);

    if(saturation == 0.0)
    {
        r = g = b = brightness;
    }
    else
    {
        float q = brightness < 0.5 ?
            brightness * (1.0 + saturation) : brightness + saturation - brightness * saturation;
        float p = 2.0 * brightness - q;
        r = hue2rgb(p, q, hue + 1.0/3.0);
        g = hue2rgb(p, q, hue);
        b = hue2rgb(p, q, hue - 1.0/3.0);
    }

    setColorRGB(led, (byte)(255.0*r), (byte)(255.0*g), (byte)(255.0*b));
}

// --------------------------------------------------------------------------------------

float hue2rgb(float p, float q, float t)
{
    if (t < 0.0)
        t += 1.0;
    if(t > 1.0)
        t -= 1.0;
    if(t < 1.0/6.0)
        return p + (q - p) * 6.0 * t;
    if(t < 1.0/2.0)
        return q;
    if(t < 2.0/3.0)
        return p + (q - p) * (2.0/3.0 - t) * 6.0;

    return p;
}
<commit_msg>Delete ChainableLED.cpp<commit_after><|endoftext|>


<commit_before>//
// Created by Umur Gedik on 5/4/16.
//

#include <fstream>
#ifdef _MSC_VER
#include <boost/config/compiler/visualc.hpp>
#endif
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <boost/filesystem/path.hpp>
#include "ConfigParser.h"
#include "parsers/EntryTypeParser.h"
#include "parsers/EntryMessageParser.h"

SupConfig ConfigParser::Parse(const fs::path &path)
{
    std::ifstream fs{path.string()};

    pt::ptree tree;
    pt::read_json(fs, tree);

    SupConfig config;

    auto issue_type_tree = tree.get_child_optional("issueType");
    if (issue_type_tree) {
        ParseEntryTypeParserOptions(*issue_type_tree, config.entry_type_parser_options);
    }

    auto body_tree = tree.get_child_optional("body");
    if (body_tree) {
        ParseMessageParserOptions(*body_tree, config.message_parser_options);
    }

    config.issue_id_regex = tree.get<string>("issueIdRegex", "#(\\d+)");
    config.entry_template = tree.get<string>("template", "[$issueId] $body");
    config.omit_newlines = tree.get<bool>("omitNewlinesInBody", false);
    config.filter_regex = tree.get<string>("filter", ".*");
    config.tag_filter = tree.get<string>("tagFilter", "v*");
    config.file_path = tree.get<string>("file", "CHANGELOG.md");
    config.group_by_issue_type = tree.get<bool>("groupByIssueType", true);

    return config;
}

void ConfigParser::ParseEntryTypeParserOptions(const pt::ptree &tree, EntryTypeParserOptions &options)
{
    auto regex = tree.get_optional<string>("regex");
    if (regex) {
        options.regex = *regex;
        options.regex_based = true;
    }

    auto line_number = tree.get_optional<int>("lineNumber");
    if (line_number) {
        options.line_number = *line_number;
        options.line_based = true;
        options.regex_based = false;
    }

    auto searchAt = tree.get_optional<int>("searchAt");
    if (regex && searchAt) {
        options.line_number = *searchAt;
        options.line_based = false;
        options.regex_based = true;
    }
}

void ConfigParser::ParseMessageParserOptions(const boost::property_tree::ptree &pt, EntryMessageParserOptions &options)
{
    auto line_number = pt.get_optional<int>("lineNumber");
    if (line_number) {
        options.line_number = *line_number;
        options.regex_based = false;
        options.one_line = true;
        return;
    }

    auto regex = pt.get_optional<string>("regex");
    if (regex) {
        options.regex = *regex;
        options.regex_based = true;
        return;
    }

    auto start_from = pt.get_optional<int>("startingAt");
    if (start_from) {
        options.from_line = *start_from;
    }

    auto delimiter = pt.get_optional<string>("endOfBody");
    if (delimiter) {
        options.delimiter = *delimiter;
        options.until_delimiter = true;
    }
}

<commit_msg>fix: regex should override delimiter for body parser<commit_after>//
// Created by Umur Gedik on 5/4/16.
//

#include <fstream>
#ifdef _MSC_VER
#include <boost/config/compiler/visualc.hpp>
#endif
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <boost/filesystem/path.hpp>
#include "ConfigParser.h"
#include "parsers/EntryTypeParser.h"
#include "parsers/EntryMessageParser.h"

SupConfig ConfigParser::Parse(const fs::path &path)
{
    std::ifstream fs{path.string()};

    pt::ptree tree;
    pt::read_json(fs, tree);

    SupConfig config;

    auto issue_type_tree = tree.get_child_optional("issueType");
    if (issue_type_tree) {
        ParseEntryTypeParserOptions(*issue_type_tree, config.entry_type_parser_options);
    }

    auto body_tree = tree.get_child_optional("body");
    if (body_tree) {
        ParseMessageParserOptions(*body_tree, config.message_parser_options);
    }

    config.issue_id_regex = tree.get<string>("issueIdRegex", "#(\\d+)");
    config.entry_template = tree.get<string>("template", "[$issueId] $body");
    config.omit_newlines = tree.get<bool>("omitNewlinesInBody", false);
    config.filter_regex = tree.get<string>("filter", ".*");
    config.tag_filter = tree.get<string>("tagFilter", "v*");
    config.file_path = tree.get<string>("file", "CHANGELOG.md");
    config.group_by_issue_type = tree.get<bool>("groupByIssueType", true);

    return config;
}

void ConfigParser::ParseEntryTypeParserOptions(const pt::ptree &tree, EntryTypeParserOptions &options)
{
    auto regex = tree.get_optional<string>("regex");
    if (regex) {
        options.regex = *regex;
        options.regex_based = true;
    }

    auto line_number = tree.get_optional<int>("lineNumber");
    if (line_number) {
        options.line_number = *line_number;
        options.line_based = true;
        options.regex_based = false;
    }

    auto searchAt = tree.get_optional<int>("searchAt");
    if (regex && searchAt) {
        options.line_number = *searchAt;
        options.line_based = false;
        options.regex_based = true;
    }
}

void ConfigParser::ParseMessageParserOptions(const boost::property_tree::ptree &pt, EntryMessageParserOptions &options)
{
    auto line_number = pt.get_optional<int>("lineNumber");
    if (line_number) {
        options.line_number = *line_number;
        options.regex_based = false;
        options.one_line = true;
        options.until_delimiter = false;
        return;
    }

    auto regex = pt.get_optional<string>("regex");
    if (regex) {
        options.regex = *regex;
        options.regex_based = true;
        options.until_delimiter = false;
        return;
    }

    auto start_from = pt.get_optional<int>("startingAt");
    if (start_from) {
        options.from_line = *start_from;
    }

    auto delimiter = pt.get_optional<string>("endOfBody");
    if (delimiter) {
        options.delimiter = *delimiter;
        options.until_delimiter = true;
    }
}

<|endoftext|>


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

#include "lpc_aspeed.hpp"

#include "mapper_errors.hpp"
#include "window_hw_interface.hpp"

#include <fcntl.h>
#include <linux/aspeed-lpc-ctrl.h>
#include <linux/kernel.h>

#include <cerrno>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <utility>

namespace ipmi_flash
{

const std::string LpcMapperAspeed::lpcControlPath = "/dev/aspeed-lpc-ctrl";

std::unique_ptr<HardwareMapperInterface>
    LpcMapperAspeed::createAspeedMapper(std::uint32_t regionAddress,
                                        std::size_t regionSize)
{
    /* NOTE: considered using a joint factory to create one or the other, for
     * now, separate factories.
     */
    return std::make_unique<LpcMapperAspeed>(regionAddress, regionSize);
}

void LpcMapperAspeed::close()
{
    if (mappedRegion)
    {
        sys->munmap(mappedRegion, regionSize);
        mappedRegion = nullptr;
    }

    if (mappedFd != -1)
    {
        sys->close(mappedFd);
        mappedFd = -1;
    }
}

WindowMapResult LpcMapperAspeed::mapWindow(std::uint32_t address,
                                           std::uint32_t length)
{
    WindowMapResult result = {};
    static const std::uint32_t MASK_64K = 0xFFFFU;
    const std::uint32_t offset = address & MASK_64K;

    if (offset + length > regionSize)
    {
        std::fprintf(stderr,
                     "requested window size %" PRIu32 ", offset %#" PRIx32
                     " is too large for mem region"
                     " of size %zu\n",
                     length, offset, regionSize);

        result.response = EFBIG;
        result.windowSize = regionSize - offset;
        return result;
    }

    struct aspeed_lpc_ctrl_mapping map = {
        .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
        .window_id = 0,
        .flags = 0,
        .addr = address & ~MASK_64K,
        .offset = 0,
        .size = __ALIGN_KERNEL_MASK(offset + length, MASK_64K),
    };

    std::fprintf(stderr,
                 "requesting Aspeed LPC window at %#" PRIx32 " of size %" PRIu32
                 "\n",
                 map.addr, map.size);

    const auto lpcControlFd = sys->open(lpcControlPath.c_str(), O_RDWR);
    if (lpcControlFd == -1)
    {
        std::fprintf(stderr,
                     "cannot open Aspeed LPC kernel control dev \"%s\"\n",
                     lpcControlPath.c_str());

        result.response = EINVAL;
        return result;
    }

    if (sys->ioctl(lpcControlFd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) == -1)
    {
        std::fprintf(stderr, "Failed to ioctl Aspeed LPC map with error %s\n",
                     std::strerror(errno));
        sys->close(lpcControlFd);

        result.response = EINVAL;
        return result;
    }

    sys->close(lpcControlFd);

    result.response = 0;
    result.windowOffset = offset;
    result.windowSize = length;
    return result;
}

MemorySet LpcMapperAspeed::open()
{
    if (mapRegion())
    {
        MemorySet output;
        output.mappedFd = mappedFd;
        output.mapped = mappedRegion;
        return output;
    }

    throw MapperException("Unable to memory-map region");
}

bool LpcMapperAspeed::mapRegion()
{
    /* Open the file to map. */
    mappedFd = sys->open(lpcControlPath.c_str(), O_RDONLY | O_SYNC);

    /* TODO: The offset to use is the address we use for the map - the base
     * address of the memory region we reserved in the device-tree.
     */
    mappedRegion = reinterpret_cast<uint8_t*>(
        sys->mmap(0, regionSize, PROT_READ, MAP_SHARED, mappedFd, 0));

    if (mappedRegion == MAP_FAILED)
    {
        sys->close(mappedFd);
        mappedFd = -1;
        std::fprintf(stderr, "Mmap failure: '%s'\n", std::strerror(errno));
        return false;
    }

    /* TOOD: There is no close() method here, to close mappedFd, or mappedRegion
     * -- therefore, a good next step will be to evaluate whether or not the
     * other pieces should go here...
     */
    return true;
}

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

#include "lpc_aspeed.hpp"

#include "mapper_errors.hpp"
#include "window_hw_interface.hpp"

#include <fcntl.h>
#include <linux/aspeed-lpc-ctrl.h>
#include <linux/kernel.h>

#include <cerrno>
#include <cstdint>
#include <cstring>
#include <memory>
#include <string>
#include <utility>

namespace ipmi_flash
{

const std::string LpcMapperAspeed::lpcControlPath = "/dev/aspeed-lpc-ctrl";

std::unique_ptr<HardwareMapperInterface>
    LpcMapperAspeed::createAspeedMapper(std::uint32_t regionAddress,
                                        std::size_t regionSize)
{
    /* NOTE: considered using a joint factory to create one or the other, for
     * now, separate factories.
     */
    return std::make_unique<LpcMapperAspeed>(regionAddress, regionSize);
}

void LpcMapperAspeed::close()
{
    if (mappedRegion)
    {
        sys->munmap(mappedRegion, regionSize);
        mappedRegion = nullptr;
    }

    if (mappedFd != -1)
    {
        sys->close(mappedFd);
        mappedFd = -1;
    }
}

WindowMapResult LpcMapperAspeed::mapWindow(std::uint32_t address,
                                           std::uint32_t length)
{
    WindowMapResult result = {};
    static const std::uint32_t MASK_64K = 0xFFFFU;
    const std::uint32_t offset = address & MASK_64K;

    if (offset + length > regionSize)
    {
        std::fprintf(stderr,
                     "requested window size %" PRIu32 ", offset %#" PRIx32
                     " is too large for mem region"
                     " of size %zu\n",
                     length, offset, regionSize);

        result.response = EFBIG;
        result.windowSize = regionSize - offset;
        return result;
    }

    struct aspeed_lpc_ctrl_mapping map = {
        .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY,
        .window_id = 0,
        .flags = 0,
        .addr = address & ~MASK_64K,
        .offset = 0,
        .size = __ALIGN_KERNEL_MASK(offset + length, MASK_64K),
    };

    std::fprintf(stderr,
                 "requesting Aspeed LPC window at %#" PRIx32 " of size %" PRIu32
                 "\n",
                 map.addr, map.size);

    const auto lpcControlFd = sys->open(lpcControlPath.c_str(), O_RDWR);
    if (lpcControlFd == -1)
    {
        std::fprintf(stderr,
                     "cannot open Aspeed LPC kernel control dev \"%s\"\n",
                     lpcControlPath.c_str());

        result.response = EINVAL;
        return result;
    }

    if (sys->ioctl(lpcControlFd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) == -1)
    {
        std::fprintf(stderr, "Failed to ioctl Aspeed LPC map with error %s\n",
                     std::strerror(errno));
        sys->close(lpcControlFd);

        result.response = EINVAL;
        return result;
    }

    sys->close(lpcControlFd);

    result.response = 0;
    result.windowOffset = offset;
    result.windowSize = length;
    return result;
}

MemorySet LpcMapperAspeed::open()
{
    if (mapRegion())
    {
        MemorySet output;
        output.mappedFd = mappedFd;
        output.mapped = mappedRegion;
        return output;
    }

    throw MapperException("Unable to memory-map region");
}

bool LpcMapperAspeed::mapRegion()
{
    /* Open the file to map. */
    mappedFd = sys->open(lpcControlPath.c_str(), O_RDONLY | O_SYNC);
    if (mappedFd == -1)
    {
        std::fprintf(stderr, "ipmiflash: unable to open %s\n",
                     lpcControlPath.c_str());
        return false;
    }

    mappedRegion = reinterpret_cast<uint8_t*>(
        sys->mmap(0, regionSize, PROT_READ, MAP_SHARED, mappedFd, 0));

    if (mappedRegion == MAP_FAILED)
    {
        sys->close(mappedFd);
        mappedFd = -1;
        std::fprintf(stderr, "Mmap failure: '%s'\n", std::strerror(errno));
        return false;
    }

    /* TOOD: There is no close() method here, to close mappedFd, or mappedRegion
     * -- therefore, a good next step will be to evaluate whether or not the
     * other pieces should go here...
     */
    return true;
}

} // namespace ipmi_flash
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "watchman/root/Root.h"

using namespace watchman;

static json_ref config_get_ignore_vcs(Root* root) {
  json_ref ignores = root->config.get("ignore_vcs");
  if (ignores && !ignores.isArray()) {
    return nullptr;
  }

  if (!ignores) {
    // default to a well-known set of vcs's
    ignores = json_array(
        {typed_string_to_json(".git"),
         typed_string_to_json(".svn"),
         typed_string_to_json(".hg")});
  }
  return ignores;
}

void Root::applyIgnoreVCSConfiguration() {
  auto ignores = config_get_ignore_vcs(this);
  if (!ignores) {
    throw std::runtime_error("ignore_vcs must be an array of strings");
  }

  for (auto& jignore : ignores.array()) {
    if (!jignore.isString()) {
      throw std::runtime_error("ignore_vcs must be an array of strings");
    }

    auto fullname = w_string::pathCat({root_path, json_to_w_string(jignore)});

    // if we are completely ignoring this dir, we have nothing more to
    // do here
    if (ignore.isIgnoreDir(fullname)) {
      continue;
    }

    ignore.add(fullname, true);

    // Since we do not have a watcher just yet, we can't test if the watcher
    // will have WATCHER_HAS_SPLIT_WATCH, thus, rely on whether only the root
    // is present in the cookies dirs.
    auto cookieDirs = cookies.cookieDirs();
    if (cookieDirs.size() == 1 && cookieDirs.count(root_path) == 1) {
      // While we're at it, see if we can find out where to put our
      // query cookie information
      try {
        auto info = getFileInformation(fullname.c_str(), case_sensitive);
        if (info.isDir()) {
          // root/{.hg,.git,.svn}
          cookies.setCookieDir(fullname);
        }
      } catch (...) {
        // Don't care
      }
    }
  }
}

/* vim:ts=2:sw=2:et:
 */
<commit_msg>remove an invariant conditional<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "watchman/Logging.h"
#include "watchman/root/Root.h"

using namespace watchman;

static json_ref config_get_ignore_vcs(Root* root) {
  json_ref ignores = root->config.get("ignore_vcs");
  if (ignores && !ignores.isArray()) {
    return nullptr;
  }

  if (!ignores) {
    // default to a well-known set of vcs's
    ignores = json_array(
        {typed_string_to_json(".git"),
         typed_string_to_json(".svn"),
         typed_string_to_json(".hg")});
  }
  return ignores;
}

void Root::applyIgnoreVCSConfiguration() {
  auto cookieDirs = cookies.cookieDirs();
  w_check(
      cookieDirs.size() == 1 && cookieDirs.count(root_path) == 1,
      fmt::format(
          "cookie was already initialized with {}: {}\n",
          cookieDirs.size(),
          *cookieDirs.begin()));

  bool default_cookie = true;

  auto ignores = config_get_ignore_vcs(this);
  if (!ignores) {
    throw std::runtime_error("ignore_vcs must be an array of strings");
  }

  for (auto& jignore : ignores.array()) {
    if (!jignore.isString()) {
      throw std::runtime_error("ignore_vcs must be an array of strings");
    }

    auto fullname = w_string::pathCat({root_path, json_to_w_string(jignore)});

    // if we are completely ignoring this dir, we have nothing more to
    // do here
    if (ignore.isIgnoreDir(fullname)) {
      continue;
    }

    ignore.add(fullname, true);

    if (default_cookie) {
      // While we're at it, see if we can find out where to put our
      // query cookie information
      try {
        auto info = getFileInformation(fullname.c_str(), case_sensitive);
        if (info.isDir()) {
          // root/{.hg,.git,.svn}
          cookies.setCookieDir(fullname);
          default_cookie = false;
        }
      } catch (...) {
        // Don't care
      }
    }
  }
}

/* vim:ts=2:sw=2:et:
 */
<|endoftext|>


<commit_before>#ifndef ALGORITHM_HPP
# define ALGORUTHM_HPP
# pragma once

#include <cstddef>

#include <type_traits>

#include <utility>

#include "meta.hpp"

namespace generic
{

// min, max
template <typename T>
constexpr inline T const& max(T const& a, T const& b) noexcept
{
  return a > b ? a : b;
}

template <typename T>
constexpr inline T const& min(T const& a, T const& b) noexcept
{
  return a < b ? a : b;
}

template <typename T, typename ...A>
constexpr inline typename ::std::enable_if<
  bool(sizeof...(A)) &&
  all_of<
    ::std::is_same<
      typename ::std::decay<T>::type,
      typename ::std::decay<A>::type
    >...
  >{},
  T
>::type
max(T const& a, T const& b, A&& ...args) noexcept
{
  return a > b ?
    max(a, ::std::forward<A>(args)...) :
    max(b, ::std::forward<A>(args)...);
}

template <typename T, typename ...A>
constexpr inline typename ::std::enable_if<
  bool(sizeof...(A)) &&
  all_of<
    ::std::is_same<
      typename ::std::decay<T>::type,
      typename ::std::decay<A>::type
    >...
  >{},
  T
>::type
min(T const& a, T const& b, A&& ...args) noexcept
{
  return a < b ?
    min(a, ::std::forward<A>(args)...) :
    min(b, ::std::forward<A>(args)...);
}

template <typename ...A>
constexpr inline typename ::std::enable_if<
  bool(sizeof...(A)) &&
  all_of<
    ::std::is_same<
      typename ::std::decay<typename front<A...>::type>::type,
      typename ::std::decay<A>::type
    >...
  >{},
  ::std::pair<
    typename ::std::decay<typename front<A...>::type>::type,
    typename ::std::decay<typename front<A...>::type>::type
  >
>::type
minmax(A&& ...args) noexcept
{
  return {
    min(::std::forward<A>(args)...),
    max(::std::forward<A>(args)...)
  };
}

}

#endif // ALGORITHM_HPP
<commit_msg>some fixes<commit_after>#ifndef GENERIC_ALGORITHM_HPP
# define GENERIC_ALGORITHM_HPP
# pragma once

#include <cstddef>

#include <type_traits>

#include <utility>

#include "meta.hpp"

namespace generic
{

// min, max
template <typename T>
constexpr inline T const& max(T const& a, T const& b) noexcept
{
  return a > b ? a : b;
}

template <typename T>
constexpr inline T const& min(T const& a, T const& b) noexcept
{
  return a < b ? a : b;
}

template <typename T, typename ...A>
constexpr inline typename ::std::enable_if<
  bool(sizeof...(A)) &&
  all_of<
    ::std::is_same<
      typename ::std::decay<T>::type,
      typename ::std::decay<A>::type
    >...
  >{},
  T
>::type
max(T const& a, T const& b, A&& ...args) noexcept
{
  return a > b ?
    max(a, ::std::forward<A>(args)...) :
    max(b, ::std::forward<A>(args)...);
}

template <typename T, typename ...A>
constexpr inline typename ::std::enable_if<
  bool(sizeof...(A)) &&
  all_of<
    ::std::is_same<
      typename ::std::decay<T>::type,
      typename ::std::decay<A>::type
    >...
  >{},
  T
>::type
min(T const& a, T const& b, A&& ...args) noexcept
{
  return a < b ?
    min(a, ::std::forward<A>(args)...) :
    min(b, ::std::forward<A>(args)...);
}

template <typename ...A>
constexpr inline typename ::std::enable_if<
  bool(sizeof...(A)) &&
  all_of<
    ::std::is_same<
      typename ::std::decay<typename front<A...>::type>::type,
      typename ::std::decay<A>::type
    >...
  >{},
  ::std::pair<
    typename ::std::decay<typename front<A...>::type>::type,
    typename ::std::decay<typename front<A...>::type>::type
  >
>::type
minmax(A&& ...args) noexcept
{
  return {
    min(::std::forward<A>(args)...),
    max(::std::forward<A>(args)...)
  };
}

}

#endif // GENERIC_ALGORITHM_HPP
<|endoftext|>


<commit_before>#ifndef KISSFFT_CLASS_HH
#include <complex>
#include <vector>

namespace kissfft_utils {

template <typename T_scalar>
struct traits
{
    typedef T_scalar scalar_type;
    typedef std::complex<scalar_type> cpx_type;
    void fill_twiddles( std::complex<T_scalar> * dst ,int nfft,bool inverse)
    {
        T_scalar phinc =  (inverse?2:-2)* acos( (T_scalar) -1)  / nfft;
        for (int i=0;i<nfft;++i)
            dst[i] = exp( std::complex<T_scalar>(0,i*phinc) );
    }

    void prepare(
            std::vector< std::complex<T_scalar> > & dst,
            int nfft,bool inverse,
            std::vector<int> & stageRadix,
            std::vector<int> & stageRemainder )
    {
        _twiddles.resize(nfft);
        fill_twiddles( &_twiddles[0],nfft,inverse);
        dst = _twiddles;

        //factorize
        //start factoring out 4's, then 2's, then 3,5,7,9,...
        int n= nfft;
        int p=4;
        do {
            while (n % p) {
                switch (p) {
                    case 4: p = 2; break;
                    case 2: p = 3; break;
                    default: p += 2; break;
                }
                if (p*p>n)
                    p=n;// no more factors
            }
            n /= p;
            stageRadix.push_back(p);
            stageRemainder.push_back(n);
        }while(n>1);
    }
    std::vector<cpx_type> _twiddles;

    const cpx_type twiddle(int i) { return _twiddles[i]; }
};

}

template <typename T_Scalar,
         typename T_traits=kissfft_utils::traits<T_Scalar>
         >
class kissfft
{
    public:
        typedef T_traits traits_type;
        typedef typename traits_type::scalar_type scalar_type;
        typedef typename traits_type::cpx_type cpx_type;

        kissfft(int nfft,bool inverse,const traits_type & traits=traits_type() )
            :_nfft(nfft),_inverse(inverse),_traits(traits)
        {
            _traits.prepare(_twiddles, _nfft,_inverse ,_stageRadix, _stageRemainder);
        }

        void transform(const cpx_type * src , cpx_type * dst)
        {
            kf_work(0, dst, src, 1,1);
        }

    private:
        void kf_work( int stage,cpx_type * Fout, const cpx_type * f, size_t fstride,size_t in_stride)
        {
            int p = _stageRadix[stage];
            int m = _stageRemainder[stage];
            cpx_type * Fout_beg = Fout;
            cpx_type * Fout_end = Fout + p*m;

            if (m==1) {
                do{
                    *Fout = *f;
                    f += fstride*in_stride;
                }while(++Fout != Fout_end );
            }else{
                do{
                    // recursive call:
                    // DFT of size m*p performed by doing
                    // p instances of smaller DFTs of size m,
                    // each one takes a decimated version of the input
                    kf_work(stage+1, Fout , f, fstride*p,in_stride);
                    f += fstride*in_stride;
                }while( (Fout += m) != Fout_end );
            }

            Fout=Fout_beg;

            // recombine the p smaller DFTs
            switch (p) {
                case 2: kf_bfly2(Fout,fstride,m); break;
                case 3: kf_bfly3(Fout,fstride,m); break;
                case 4: kf_bfly4(Fout,fstride,m); break;
                case 5: kf_bfly5(Fout,fstride,m); break;
                default: kf_bfly_generic(Fout,fstride,m,p); break;
            }
        }

        // these were #define macros in the original kiss_fft
        void C_ADD( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a+b;}
        void C_MUL( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a*b;}
        void C_SUB( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a-b;}
        void C_ADDTO( cpx_type & c,const cpx_type & a) { c+=a;}
        void C_FIXDIV( cpx_type & ,int ) {} // NO-OP for float types
        scalar_type S_MUL( const scalar_type & a,const scalar_type & b) { return a*b;}
        scalar_type HALF_OF( const scalar_type & a) { return a*.5;}
        void C_MULBYSCALAR(cpx_type & c,const scalar_type & a) {c*=a;}

        void kf_bfly2( cpx_type * Fout, const size_t fstride, int m)
        {
            for (int k=0;k<m;++k) {
                cpx_type t = Fout[m+k] * _traits.twiddle(k*fstride);
                Fout[m+k] = Fout[k] - t;
                Fout[k] += t;
            }
        }

        void kf_bfly4( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type scratch[7];
            int negative_if_inverse = _inverse * -2 +1;
            for (size_t k=0;k<m;++k) {
                scratch[0] = Fout[k+m] * _traits.twiddle(k*fstride);
                scratch[1] = Fout[k+2*m] * _traits.twiddle(k*fstride*2);
                scratch[2] = Fout[k+3*m] * _traits.twiddle(k*fstride*3);
                scratch[5] = Fout[k] - scratch[1];

                Fout[k] += scratch[1];
                scratch[3] = scratch[0] + scratch[2];
                scratch[4] = scratch[0] - scratch[2];
                scratch[4] = cpx_type( scratch[4].imag()*negative_if_inverse , -scratch[4].real()* negative_if_inverse );

                Fout[k+2*m]  = Fout[k] - scratch[3];
                Fout[k] += scratch[3];
                Fout[k+m] = scratch[5] + scratch[4];
                Fout[k+3*m] = scratch[5] - scratch[4];
            }
        }

        void kf_bfly3( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            size_t k=m;
            const size_t m2 = 2*m;
            cpx_type *tw1,*tw2;
            cpx_type scratch[5];
            cpx_type epi3;
            epi3 = _twiddles[fstride*m];

            tw1=tw2=&_twiddles[0];

            do{
                C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);

                C_MUL(scratch[1],Fout[m] , *tw1);
                C_MUL(scratch[2],Fout[m2] , *tw2);

                C_ADD(scratch[3],scratch[1],scratch[2]);
                C_SUB(scratch[0],scratch[1],scratch[2]);
                tw1 += fstride;
                tw2 += fstride*2;

                Fout[m] = cpx_type( Fout->real() - HALF_OF(scratch[3].real() ) , Fout->imag() - HALF_OF(scratch[3].imag() ) );

                C_MULBYSCALAR( scratch[0] , epi3.imag() );

                C_ADDTO(*Fout,scratch[3]);

                Fout[m2] = cpx_type(  Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );

                C_ADDTO( Fout[m] , cpx_type( -scratch[0].imag(),scratch[0].real() ) );
                ++Fout;
            }while(--k);
        }

        void kf_bfly5( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
            size_t u;
            cpx_type scratch[13];
            cpx_type * twiddles = &_twiddles[0];
            cpx_type *tw;
            cpx_type ya,yb;
            ya = twiddles[fstride*m];
            yb = twiddles[fstride*2*m];

            Fout0=Fout;
            Fout1=Fout0+m;
            Fout2=Fout0+2*m;
            Fout3=Fout0+3*m;
            Fout4=Fout0+4*m;

            tw=twiddles;
            for ( u=0; u<m; ++u ) {
                C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
                scratch[0] = *Fout0;

                C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
                C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
                C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
                C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);

                C_ADD( scratch[7],scratch[1],scratch[4]);
                C_SUB( scratch[10],scratch[1],scratch[4]);
                C_ADD( scratch[8],scratch[2],scratch[3]);
                C_SUB( scratch[9],scratch[2],scratch[3]);

                C_ADDTO( *Fout0, scratch[7]);
                C_ADDTO( *Fout0, scratch[8]);

                scratch[5] = scratch[0] + cpx_type(
                        S_MUL(scratch[7].real(),ya.real() ) + S_MUL(scratch[8].real() ,yb.real() ),
                        S_MUL(scratch[7].imag(),ya.real()) + S_MUL(scratch[8].imag(),yb.real())
                        );

                scratch[6] =  cpx_type(
                        S_MUL(scratch[10].imag(),ya.imag()) + S_MUL(scratch[9].imag(),yb.imag()),
                        -S_MUL(scratch[10].real(),ya.imag()) - S_MUL(scratch[9].real(),yb.imag())
                        );

                C_SUB(*Fout1,scratch[5],scratch[6]);
                C_ADD(*Fout4,scratch[5],scratch[6]);

                scratch[11] = scratch[0] +
                    cpx_type(
                            S_MUL(scratch[7].real(),yb.real()) + S_MUL(scratch[8].real(),ya.real()),
                            S_MUL(scratch[7].imag(),yb.real()) + S_MUL(scratch[8].imag(),ya.real())
                            );

                scratch[12] = cpx_type(
                        -S_MUL(scratch[10].imag(),yb.imag()) + S_MUL(scratch[9].imag(),ya.imag()),
                        S_MUL(scratch[10].real(),yb.imag()) - S_MUL(scratch[9].real(),ya.imag())
                        );

                C_ADD(*Fout2,scratch[11],scratch[12]);
                C_SUB(*Fout3,scratch[11],scratch[12]);

                ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
            }
        }

        /* perform the butterfly for one stage of a mixed radix FFT */
        void kf_bfly_generic(
                cpx_type * Fout,
                const size_t fstride,
                int m,
                int p
                )
        {
            int u,k,q1,q;
            cpx_type * twiddles = &_twiddles[0];
            cpx_type t;
            int Norig = _nfft;
            cpx_type scratchbuf[p];

            for ( u=0; u<m; ++u ) {
                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    scratchbuf[q1] = Fout[ k  ];
                    C_FIXDIV(scratchbuf[q1],p);
                    k += m;
                }

                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    int twidx=0;
                    Fout[ k ] = scratchbuf[0];
                    for (q=1;q<p;++q ) {
                        twidx += fstride * k;
                        if (twidx>=Norig) twidx-=Norig;
                        C_MUL(t,scratchbuf[q] , twiddles[twidx] );
                        C_ADDTO( Fout[ k ] ,t);
                    }
                    k += m;
                }
            }
        }

        int _nfft;
        bool _inverse;
        std::vector<cpx_type> _twiddles;
        std::vector<int> _stageRadix;
        std::vector<int> _stageRemainder;
        traits_type _traits;
};
#endif
<commit_msg>guard against multiple inclusion<commit_after>#ifndef KISSFFT_CLASS_HH
#define KISSFFT_CLASS_HH
#include <complex>
#include <vector>

namespace kissfft_utils {

template <typename T_scalar>
struct traits
{
    typedef T_scalar scalar_type;
    typedef std::complex<scalar_type> cpx_type;
    void fill_twiddles( std::complex<T_scalar> * dst ,int nfft,bool inverse)
    {
        T_scalar phinc =  (inverse?2:-2)* acos( (T_scalar) -1)  / nfft;
        for (int i=0;i<nfft;++i)
            dst[i] = exp( std::complex<T_scalar>(0,i*phinc) );
    }

    void prepare(
            std::vector< std::complex<T_scalar> > & dst,
            int nfft,bool inverse,
            std::vector<int> & stageRadix,
            std::vector<int> & stageRemainder )
    {
        _twiddles.resize(nfft);
        fill_twiddles( &_twiddles[0],nfft,inverse);
        dst = _twiddles;

        //factorize
        //start factoring out 4's, then 2's, then 3,5,7,9,...
        int n= nfft;
        int p=4;
        do {
            while (n % p) {
                switch (p) {
                    case 4: p = 2; break;
                    case 2: p = 3; break;
                    default: p += 2; break;
                }
                if (p*p>n)
                    p=n;// no more factors
            }
            n /= p;
            stageRadix.push_back(p);
            stageRemainder.push_back(n);
        }while(n>1);
    }
    std::vector<cpx_type> _twiddles;

    const cpx_type twiddle(int i) { return _twiddles[i]; }
};

}

template <typename T_Scalar,
         typename T_traits=kissfft_utils::traits<T_Scalar>
         >
class kissfft
{
    public:
        typedef T_traits traits_type;
        typedef typename traits_type::scalar_type scalar_type;
        typedef typename traits_type::cpx_type cpx_type;

        kissfft(int nfft,bool inverse,const traits_type & traits=traits_type() )
            :_nfft(nfft),_inverse(inverse),_traits(traits)
        {
            _traits.prepare(_twiddles, _nfft,_inverse ,_stageRadix, _stageRemainder);
        }

        void transform(const cpx_type * src , cpx_type * dst)
        {
            kf_work(0, dst, src, 1,1);
        }

    private:
        void kf_work( int stage,cpx_type * Fout, const cpx_type * f, size_t fstride,size_t in_stride)
        {
            int p = _stageRadix[stage];
            int m = _stageRemainder[stage];
            cpx_type * Fout_beg = Fout;
            cpx_type * Fout_end = Fout + p*m;

            if (m==1) {
                do{
                    *Fout = *f;
                    f += fstride*in_stride;
                }while(++Fout != Fout_end );
            }else{
                do{
                    // recursive call:
                    // DFT of size m*p performed by doing
                    // p instances of smaller DFTs of size m,
                    // each one takes a decimated version of the input
                    kf_work(stage+1, Fout , f, fstride*p,in_stride);
                    f += fstride*in_stride;
                }while( (Fout += m) != Fout_end );
            }

            Fout=Fout_beg;

            // recombine the p smaller DFTs
            switch (p) {
                case 2: kf_bfly2(Fout,fstride,m); break;
                case 3: kf_bfly3(Fout,fstride,m); break;
                case 4: kf_bfly4(Fout,fstride,m); break;
                case 5: kf_bfly5(Fout,fstride,m); break;
                default: kf_bfly_generic(Fout,fstride,m,p); break;
            }
        }

        // these were #define macros in the original kiss_fft
        void C_ADD( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a+b;}
        void C_MUL( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a*b;}
        void C_SUB( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a-b;}
        void C_ADDTO( cpx_type & c,const cpx_type & a) { c+=a;}
        void C_FIXDIV( cpx_type & ,int ) {} // NO-OP for float types
        scalar_type S_MUL( const scalar_type & a,const scalar_type & b) { return a*b;}
        scalar_type HALF_OF( const scalar_type & a) { return a*.5;}
        void C_MULBYSCALAR(cpx_type & c,const scalar_type & a) {c*=a;}

        void kf_bfly2( cpx_type * Fout, const size_t fstride, int m)
        {
            for (int k=0;k<m;++k) {
                cpx_type t = Fout[m+k] * _traits.twiddle(k*fstride);
                Fout[m+k] = Fout[k] - t;
                Fout[k] += t;
            }
        }

        void kf_bfly4( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type scratch[7];
            int negative_if_inverse = _inverse * -2 +1;
            for (size_t k=0;k<m;++k) {
                scratch[0] = Fout[k+m] * _traits.twiddle(k*fstride);
                scratch[1] = Fout[k+2*m] * _traits.twiddle(k*fstride*2);
                scratch[2] = Fout[k+3*m] * _traits.twiddle(k*fstride*3);
                scratch[5] = Fout[k] - scratch[1];

                Fout[k] += scratch[1];
                scratch[3] = scratch[0] + scratch[2];
                scratch[4] = scratch[0] - scratch[2];
                scratch[4] = cpx_type( scratch[4].imag()*negative_if_inverse , -scratch[4].real()* negative_if_inverse );

                Fout[k+2*m]  = Fout[k] - scratch[3];
                Fout[k] += scratch[3];
                Fout[k+m] = scratch[5] + scratch[4];
                Fout[k+3*m] = scratch[5] - scratch[4];
            }
        }

        void kf_bfly3( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            size_t k=m;
            const size_t m2 = 2*m;
            cpx_type *tw1,*tw2;
            cpx_type scratch[5];
            cpx_type epi3;
            epi3 = _twiddles[fstride*m];

            tw1=tw2=&_twiddles[0];

            do{
                C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);

                C_MUL(scratch[1],Fout[m] , *tw1);
                C_MUL(scratch[2],Fout[m2] , *tw2);

                C_ADD(scratch[3],scratch[1],scratch[2]);
                C_SUB(scratch[0],scratch[1],scratch[2]);
                tw1 += fstride;
                tw2 += fstride*2;

                Fout[m] = cpx_type( Fout->real() - HALF_OF(scratch[3].real() ) , Fout->imag() - HALF_OF(scratch[3].imag() ) );

                C_MULBYSCALAR( scratch[0] , epi3.imag() );

                C_ADDTO(*Fout,scratch[3]);

                Fout[m2] = cpx_type(  Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );

                C_ADDTO( Fout[m] , cpx_type( -scratch[0].imag(),scratch[0].real() ) );
                ++Fout;
            }while(--k);
        }

        void kf_bfly5( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
            size_t u;
            cpx_type scratch[13];
            cpx_type * twiddles = &_twiddles[0];
            cpx_type *tw;
            cpx_type ya,yb;
            ya = twiddles[fstride*m];
            yb = twiddles[fstride*2*m];

            Fout0=Fout;
            Fout1=Fout0+m;
            Fout2=Fout0+2*m;
            Fout3=Fout0+3*m;
            Fout4=Fout0+4*m;

            tw=twiddles;
            for ( u=0; u<m; ++u ) {
                C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
                scratch[0] = *Fout0;

                C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
                C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
                C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
                C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);

                C_ADD( scratch[7],scratch[1],scratch[4]);
                C_SUB( scratch[10],scratch[1],scratch[4]);
                C_ADD( scratch[8],scratch[2],scratch[3]);
                C_SUB( scratch[9],scratch[2],scratch[3]);

                C_ADDTO( *Fout0, scratch[7]);
                C_ADDTO( *Fout0, scratch[8]);

                scratch[5] = scratch[0] + cpx_type(
                        S_MUL(scratch[7].real(),ya.real() ) + S_MUL(scratch[8].real() ,yb.real() ),
                        S_MUL(scratch[7].imag(),ya.real()) + S_MUL(scratch[8].imag(),yb.real())
                        );

                scratch[6] =  cpx_type(
                        S_MUL(scratch[10].imag(),ya.imag()) + S_MUL(scratch[9].imag(),yb.imag()),
                        -S_MUL(scratch[10].real(),ya.imag()) - S_MUL(scratch[9].real(),yb.imag())
                        );

                C_SUB(*Fout1,scratch[5],scratch[6]);
                C_ADD(*Fout4,scratch[5],scratch[6]);

                scratch[11] = scratch[0] +
                    cpx_type(
                            S_MUL(scratch[7].real(),yb.real()) + S_MUL(scratch[8].real(),ya.real()),
                            S_MUL(scratch[7].imag(),yb.real()) + S_MUL(scratch[8].imag(),ya.real())
                            );

                scratch[12] = cpx_type(
                        -S_MUL(scratch[10].imag(),yb.imag()) + S_MUL(scratch[9].imag(),ya.imag()),
                        S_MUL(scratch[10].real(),yb.imag()) - S_MUL(scratch[9].real(),ya.imag())
                        );

                C_ADD(*Fout2,scratch[11],scratch[12]);
                C_SUB(*Fout3,scratch[11],scratch[12]);

                ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
            }
        }

        /* perform the butterfly for one stage of a mixed radix FFT */
        void kf_bfly_generic(
                cpx_type * Fout,
                const size_t fstride,
                int m,
                int p
                )
        {
            int u,k,q1,q;
            cpx_type * twiddles = &_twiddles[0];
            cpx_type t;
            int Norig = _nfft;
            cpx_type scratchbuf[p];

            for ( u=0; u<m; ++u ) {
                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    scratchbuf[q1] = Fout[ k  ];
                    C_FIXDIV(scratchbuf[q1],p);
                    k += m;
                }

                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    int twidx=0;
                    Fout[ k ] = scratchbuf[0];
                    for (q=1;q<p;++q ) {
                        twidx += fstride * k;
                        if (twidx>=Norig) twidx-=Norig;
                        C_MUL(t,scratchbuf[q] , twiddles[twidx] );
                        C_ADDTO( Fout[ k ] ,t);
                    }
                    k += m;
                }
            }
        }

        int _nfft;
        bool _inverse;
        std::vector<cpx_type> _twiddles;
        std::vector<int> _stageRadix;
        std::vector<int> _stageRemainder;
        traits_type _traits;
};
#endif
<|endoftext|>