<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * 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.
 *
 *  @file SignalFinder.cpp
 */

using namespace std;

#include <map>
#include <string>
#include <vector>
#include <JPetWriter/JPetWriter.h>
#include "SignalFinderTools.h"
#include "SignalFinder.h"

SignalFinder::SignalFinder(const char* name, const char* description, bool saveControlHistos)
  : JPetTask(name, description)
{
  fSaveControlHistos = saveControlHistos;
}

SignalFinder::~SignalFinder() {}

//SignalFinder init method
void SignalFinder::init(const JPetTaskInterface::Options& opts)
{
  INFO("Signal finding started.");

  if (opts.count(fEdgeMaxTimeParamKey)) {
    kSigChEdgeMaxTime = std::atof(opts.at(fEdgeMaxTimeParamKey).c_str());
  }
  if (opts.count(fLeadTrailMaxTimeParamKey)) {
    kSigChLeadTrailMaxTime = std::atof(opts.at(fLeadTrailMaxTimeParamKey).c_str());
  }

  fBarrelMap.buildMappings(getParamBank());
  if (fSaveControlHistos) {
    getStatistics().createHistogram(new TH1F("remainig_leading_sig_ch_per_thr", "Remainig Leading Signal Channels", 4, 0.5, 4.5));
    getStatistics().createHistogram(new TH1F("remainig_trailing_sig_ch_per_thr", "Remainig Trailing Signal Channels", 4, 0.5, 4.5));
    getStatistics().createHistogram(new TH1F("TOT_thr_1", "TOT on threshold 1 [ns]", 100, 20.0, 100.0));
    getStatistics().createHistogram(new TH1F("TOT_thr_2", "TOT on threshold 2 [ns]", 100, 20.0, 100.0));
    getStatistics().createHistogram(new TH1F("TOT_thr_3", "TOT on threshold 3 [ns]", 100, 20.0, 100.0));
    getStatistics().createHistogram(new TH1F("TOT_thr_4", "TOT on threshold 4 [ns]", 100, 20.0, 100.0));
  }
}

//SignalFinder execution method
void SignalFinder::exec()
{

  //getting the data from event in propriate format
  if (auto timeWindow = dynamic_cast<const JPetTimeWindow* const>(getEvent())) {

    //mapping method invocation
    map<int, vector<JPetSigCh>> sigChsPMMap = SignalFinderTools::getSigChsPMMapById(timeWindow);
    std::cout <<"after getSigChsPMMapById" <<std::endl;
    //building signals method invocation
    vector<JPetRawSignal> allSignals = SignalFinderTools::buildAllSignals(timeWindow->getIndex(), sigChsPMMap, kNumOfThresholds , getStatistics(), fSaveControlHistos,  kSigChEdgeMaxTime, kSigChLeadTrailMaxTime);

    std::cout <<"after buildAllSignals" <<std::endl;
    //saving method invocation
    saveRawSignals(allSignals);
  }
}

//SignalFinder finish method
void SignalFinder::terminate()
{
  INFO("Signal finding ended.");
}

//saving method
void SignalFinder::saveRawSignals(const vector<JPetRawSignal>& sigChVec)
{
  assert(fWriter);
  for (const auto & sigCh : sigChVec) {
    fWriter->write(sigCh);
  }
}

//other methods - TODO check if neccessary
void SignalFinder::setWriter(JPetWriter* writer)
{
  fWriter = writer;
}

void SignalFinder::setParamManager(JPetParamManager* paramManager)
{
  fParamManager = paramManager;
}

const JPetParamBank& SignalFinder::getParamBank() const
{
  return fParamManager->getParamBank();
}
<commit_msg>Remove remaining cout in SignalFinder<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 * 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.
 *
 *  @file SignalFinder.cpp
 */

using namespace std;

#include <map>
#include <string>
#include <vector>
#include <JPetWriter/JPetWriter.h>
#include "SignalFinderTools.h"
#include "SignalFinder.h"

SignalFinder::SignalFinder(const char* name, const char* description, bool saveControlHistos)
  : JPetTask(name, description)
{
  fSaveControlHistos = saveControlHistos;
}

SignalFinder::~SignalFinder() {}

//SignalFinder init method
void SignalFinder::init(const JPetTaskInterface::Options& opts)
{
  INFO("Signal finding started.");

  if (opts.count(fEdgeMaxTimeParamKey)) {
    kSigChEdgeMaxTime = std::atof(opts.at(fEdgeMaxTimeParamKey).c_str());
  }
  if (opts.count(fLeadTrailMaxTimeParamKey)) {
    kSigChLeadTrailMaxTime = std::atof(opts.at(fLeadTrailMaxTimeParamKey).c_str());
  }

  fBarrelMap.buildMappings(getParamBank());
  if (fSaveControlHistos) {
    getStatistics().createHistogram(new TH1F("remainig_leading_sig_ch_per_thr", "Remainig Leading Signal Channels", 4, 0.5, 4.5));
    getStatistics().createHistogram(new TH1F("remainig_trailing_sig_ch_per_thr", "Remainig Trailing Signal Channels", 4, 0.5, 4.5));
    getStatistics().createHistogram(new TH1F("TOT_thr_1", "TOT on threshold 1 [ns]", 100, 20.0, 100.0));
    getStatistics().createHistogram(new TH1F("TOT_thr_2", "TOT on threshold 2 [ns]", 100, 20.0, 100.0));
    getStatistics().createHistogram(new TH1F("TOT_thr_3", "TOT on threshold 3 [ns]", 100, 20.0, 100.0));
    getStatistics().createHistogram(new TH1F("TOT_thr_4", "TOT on threshold 4 [ns]", 100, 20.0, 100.0));
  }
}

//SignalFinder execution method
void SignalFinder::exec()
{

  //getting the data from event in propriate format
  if (auto timeWindow = dynamic_cast<const JPetTimeWindow* const>(getEvent())) {

    //mapping method invocation
    map<int, vector<JPetSigCh>> sigChsPMMap = SignalFinderTools::getSigChsPMMapById(timeWindow);
    //building signals method invocation
    vector<JPetRawSignal> allSignals = SignalFinderTools::buildAllSignals(timeWindow->getIndex(), sigChsPMMap, kNumOfThresholds , getStatistics(), fSaveControlHistos,  kSigChEdgeMaxTime, kSigChLeadTrailMaxTime);
    //saving method invocation
    saveRawSignals(allSignals);
  }
}

//SignalFinder finish method
void SignalFinder::terminate()
{
  INFO("Signal finding ended.");
}

//saving method
void SignalFinder::saveRawSignals(const vector<JPetRawSignal>& sigChVec)
{
  assert(fWriter);
  for (const auto & sigCh : sigChVec) {
    fWriter->write(sigCh);
  }
}

//other methods - TODO check if neccessary
void SignalFinder::setWriter(JPetWriter* writer)
{
  fWriter = writer;
}

void SignalFinder::setParamManager(JPetParamManager* paramManager)
{
  fParamManager = paramManager;
}

const JPetParamBank& SignalFinder::getParamBank() const
{
  return fParamManager->getParamBank();
}
<|endoftext|>


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

#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"

#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "walletmodel.h"
#include "ui_interface.h"
#include "guiconstants.h"

#include <QMessageBox>
#include <QApplication>
#include <QClipboard>

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

    setCurrentWidget(ui->SendCoins);

#ifdef Q_OS_MAC
    ui->payToLayout->setSpacing(4);
#endif
#if QT_VERSION >= 0x040700
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
    ui->addAsData->setPlaceholderText(tr("Enter a message to send with your transfer"));
#endif

    // normal bitcoin address field
    GUIUtil::setupAddressWidget(ui->payTo, this);
    // just a label for displaying bitcoin address(es)
    ui->payTo_is->setFont(GUIUtil::bitcoinAddressFont());
}

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

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

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

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    updateLabel(address);
}

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

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

    connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
    connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));

    // If one of the widgets changes, the combined content changes as well
    connect(ui->addAsData, SIGNAL(valueChanged(QString)), this, SIGNAL(textChanged()));

    clear();
}

void SendCoinsEntry::clear()
{
    // clear UI elements for normal payment
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->addAsData->clear();
    ui->messageTextLabel->clear();
    ui->messageTextLabel->hide();
    ui->messageLabel->hide();
    // clear UI elements for insecure payment request
    ui->payTo_is->clear();
    ui->memoTextLabel_is->clear();
    ui->payAmount_is->clear();
    ui->addAsData_is->clear();
    // clear UI elements for secure payment request
    ui->payTo_s->clear();
    ui->memoTextLabel_s->clear();
    ui->payAmount_s->clear();
    ui->addAsData_s->clear();

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

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

bool SendCoinsEntry::validate()
{
    if (!model)
        return false;

    // Check input validity
    bool retval = true;

    // Skip checks for payment request
    if (recipient.paymentRequest.IsInitialized())
        return retval;

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

    if (!ui->payAmount->validate())
    {
        retval = false;
    }

    // Reject dust outputs:
    if (retval && GUIUtil::isDust(ui->payTo->text(), ui->payAmount->value())) {
        ui->payAmount->setValid(false);
        retval = false;
    }

    // If dropdown selection is 'Hex' and data input is in ASCII format reject it
    if (ui->addAsData2->currentText() == "HEX" && !IsHex(ui->addAsData->text().toStdString())) {
        QMessageBox::critical(0, tr("Data input was rejected!"),
                              tr("The data input must be a string in hexadecimal format"));
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    // Payment request
    if (recipient.paymentRequest.IsInitialized())
        return recipient;

    // Normal payment
    recipient.address = ui->payTo->text();
    recipient.label = ui->addAsLabel->text();
    recipient.amount = ui->payAmount->value();
    recipient.message = ui->messageTextLabel->text();

    if(ui->addAsData2->currentText() == "ASCII") {
        QString asciiData = ui->addAsData->text();
        recipient.data = asciiData.toLatin1().toHex();
    } else {
        recipient.data = ui->addAsData->text();
    }

    return recipient;
}

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

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    recipient = value;

    if (recipient.paymentRequest.IsInitialized()) // payment request
    {
        if (recipient.authenticatedMerchant.isEmpty()) // insecure
        {
            ui->payTo_is->setText(recipient.address);
            ui->memoTextLabel_is->setText(recipient.message);
            ui->addAsData_is->setText(recipient.data);
            ui->payAmount_is->setValue(recipient.amount);
            ui->payAmount_is->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_InsecurePaymentRequest);
        }
        else // secure
        {
            ui->payTo_s->setText(recipient.authenticatedMerchant);
            ui->memoTextLabel_s->setText(recipient.message);
            ui->addAsData_s->setText(recipient.data);
            ui->payAmount_s->setValue(recipient.amount);
            ui->payAmount_s->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_SecurePaymentRequest);
        }
    }
    else // normal payment
    {
        // message
        ui->messageTextLabel->setText(recipient.message);
        ui->addAsData->setText(recipient.data);
        ui->messageTextLabel->setVisible(!recipient.message.isEmpty());
        ui->messageLabel->setVisible(!recipient.message.isEmpty());

        ui->addAsLabel->clear();
        ui->payTo->setText(recipient.address); // this may set a label from addressbook
        if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, dont overwrite with an empty label
            ui->addAsLabel->setText(recipient.label);
        ui->payAmount->setValue(recipient.amount);
    }
}

void SendCoinsEntry::setAddress(const QString &address)
{
    ui->payTo->setText(address);
    ui->payAmount->setFocus();
}

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

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

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

bool SendCoinsEntry::updateLabel(const QString &address)
{
    if(!model)
        return false;

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

    return false;
}
<commit_msg>Bug fix in sendcoinsentry<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"

#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include "walletmodel.h"
#include "ui_interface.h"
#include "guiconstants.h"

#include <QMessageBox>
#include <QApplication>
#include <QClipboard>

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

    setCurrentWidget(ui->SendCoins);

#ifdef Q_OS_MAC
    ui->payToLayout->setSpacing(4);
#endif
#if QT_VERSION >= 0x040700
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
    ui->addAsData->setPlaceholderText(tr("Enter a message to send with your transfer"));
#endif

    // normal bitcoin address field
    GUIUtil::setupAddressWidget(ui->payTo, this);
    // just a label for displaying bitcoin address(es)
    ui->payTo_is->setFont(GUIUtil::bitcoinAddressFont());
    ui->addAsData2->addItem("HEX");
    ui->addAsData2->addItem("ASCII");
}

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

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

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

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    updateLabel(address);
}

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

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

    connect(ui->payAmount, SIGNAL(textChanged()), this, SIGNAL(payAmountChanged()));
    connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
    connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));

    // If one of the widgets changes, the combined content changes as well
    connect(ui->addAsData, SIGNAL(valueChanged(QString)), this, SIGNAL(textChanged()));

    clear();
}

void SendCoinsEntry::clear()
{
    // clear UI elements for normal payment
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->addAsData->clear();
    ui->messageTextLabel->clear();
    ui->messageTextLabel->hide();
    ui->messageLabel->hide();
    // clear UI elements for insecure payment request
    ui->payTo_is->clear();
    ui->memoTextLabel_is->clear();
    ui->payAmount_is->clear();
    ui->addAsData_is->clear();
    // clear UI elements for secure payment request
    ui->payTo_s->clear();
    ui->memoTextLabel_s->clear();
    ui->payAmount_s->clear();
    ui->addAsData_s->clear();

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

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

bool SendCoinsEntry::validate()
{
    if (!model)
        return false;

    // Check input validity
    bool retval = true;

    // Skip checks for payment request
    if (recipient.paymentRequest.IsInitialized())
        return retval;

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

    if (!ui->payAmount->validate())
    {
        retval = false;
    }

    // Reject dust outputs:
    if (retval && GUIUtil::isDust(ui->payTo->text(), ui->payAmount->value())) {
        ui->payAmount->setValid(false);
        retval = false;
    }

    // If dropdown selection is 'Hex' and data input is in ASCII format reject it
    if (ui->addAsData2->currentText() == "HEX" && !IsHex(ui->addAsData->text().toStdString())) {
        QMessageBox::critical(0, tr("Data input was rejected!"),
                              tr("The data input must be a string in hexadecimal format"));
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    // Payment request
    if (recipient.paymentRequest.IsInitialized())
        return recipient;

    // Normal payment
    recipient.address = ui->payTo->text();
    recipient.label = ui->addAsLabel->text();
    recipient.amount = ui->payAmount->value();
    recipient.message = ui->messageTextLabel->text();

    if(ui->addAsData2->currentText() == "ASCII") {
        QString asciiData = ui->addAsData->text();
        recipient.data = asciiData.toLatin1().toHex();
    } else {
        recipient.data = ui->addAsData->text();
    }

    return recipient;
}

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

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    recipient = value;

    if (recipient.paymentRequest.IsInitialized()) // payment request
    {
        if (recipient.authenticatedMerchant.isEmpty()) // insecure
        {
            ui->payTo_is->setText(recipient.address);
            ui->memoTextLabel_is->setText(recipient.message);
            ui->addAsData_is->setText(recipient.data);
            ui->payAmount_is->setValue(recipient.amount);
            ui->payAmount_is->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_InsecurePaymentRequest);
        }
        else // secure
        {
            ui->payTo_s->setText(recipient.authenticatedMerchant);
            ui->memoTextLabel_s->setText(recipient.message);
            ui->addAsData_s->setText(recipient.data);
            ui->payAmount_s->setValue(recipient.amount);
            ui->payAmount_s->setReadOnly(true);
            setCurrentWidget(ui->SendCoins_SecurePaymentRequest);
        }
    }
    else // normal payment
    {
        // message
        ui->messageTextLabel->setText(recipient.message);
        ui->addAsData->setText(recipient.data);
        ui->messageTextLabel->setVisible(!recipient.message.isEmpty());
        ui->messageLabel->setVisible(!recipient.message.isEmpty());

        ui->addAsLabel->clear();
        ui->payTo->setText(recipient.address); // this may set a label from addressbook
        if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, dont overwrite with an empty label
            ui->addAsLabel->setText(recipient.label);
        ui->payAmount->setValue(recipient.amount);
    }
}

void SendCoinsEntry::setAddress(const QString &address)
{
    ui->payTo->setText(address);
    ui->payAmount->setFocus();
}

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

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

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

bool SendCoinsEntry::updateLabel(const QString &address)
{
    if(!model)
        return false;

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

    return false;
}
<|endoftext|>


<commit_before>// #include <cstdio>

// int n, m;

// int main() {
// 	scanf("%d %d", &n, &m);
// 	if (n == 1) {
// 		printf("1\n");
// 	}
// 	else if (n == 2) {
// 		if (m <= 6) {
// 			printf("%d\n", (m + 1) / 2);
// 		}
// 		else {
// 			printf("4\n");
// 		}
// 	}
// 	else {
// 		if (m <= 4) {
// 			printf("%d\n", m);
// 		}
// 		else if (m == 5 || m == 6) {
// 			printf("4\n");
// 		}
// 		else {
// 			printf("%d\n", m - 2);
// 		}
// 	}
// 	return 0;
// }

#include <cstdio>
using namespace std;

int n, m;

int main() {
	scanf("%d %d", &n, &m);

	if (n == 1) {
		printf("1\n");
		return 0;
	}
	if (n == 2) {
		printf("%d\n", (4 < ((m + 1) / 2)) ? 4 : ((m + 1) / 2));
		return 0;
	}
	if (m < 7) {
		printf("%d\n", (4 < m) ? 4 : m);
		return 0;
	}
	printf("%d\n", m - 7 + 5);
	return 0;
}<commit_msg>add comment<commit_after>#include <cstdio>
#include <algorithm>
using namespace std;

int n, m;

int main() {
	scanf("%d %d", &n, &m);

	if (n == 1) { // 세로가 1일 때는 움직을 수 없다. 하지만 시작위치까지 움직였다 생각하므로 1이다
		printf("1\n");
		return 0;
	}
	if (n == 2) { // 세로가 2일 때는 2, 3번 조건만 사용할 수 있기 때문에 최대 3회 움직일 수 있다
		printf("%d\n", min(4, (m + 1) / 2));
		return 0;
	}
	if (m < 7) { // 가로가 6이하면 최대 4칸 이동가능
		printf("%d\n", min(4, m));
		return 0;
	}

	// 4회 이상 이동할 경우 모든 방법을 다 사용
	// 2, 번 경우에 2칸 씩 오른쪽으로 이동
	// 그러므로 한칸 씩은 손해를본다
	printf("%d\n", m - 2);
	return 0;
}<|endoftext|>


<commit_before>#include <cstdio>
#include <algorithm>
using namespace std;

int n, weight;
int arr[100001];

int main() {
	scanf("%d", &n);

	for (int i = 0; i < n; i++) {
		scanf("%d", &arr[i]);
	}

	sort(arr, arr + n);

	// 로프마다 들수 있는 중량이 다르다
	// 그래서 제일 작은 중량 값 * 로프의 개수를 해주면 답이 나온다
	for (int i = n - 1; i >= 0; i--) {
		weight = max(weight, arr[i] * (n - i));
	}

	printf("%d\n", weight);
}<commit_msg>add comment 2217<commit_after>#include <cstdio>
#include <algorithm>
using namespace std;

int n, weight;
int arr[100001];

/*
[10, 15] 의 로프가 있을 때
15 / 1 = 15 이므로 15의 무게를 견딜 수 있다
(10 + 15) / 2 = 12.5 이므로 무게 10을 결딜 수 있는 로프는 견디지 못한다
그래서 사용한 로프는 2개 최대 하중은 10 이므로
10 * 2 = 20의 무게를 견딜 수 있다
*/

int main() {
	scanf("%d", &n);

	for (int i = 0; i < n; i++) {
		scanf("%d", &arr[i]);
	}

	sort(arr, arr + n);

	// 로프마다 들수 있는 중량이 다르다
	// 그래서 제일 작은 중량 값 * 로프의 개수를 해주면 답이 나온다
	for (int i = n - 1; i >= 0; i--) {
		weight = max(weight, arr[i] * (n - i));
	}

	printf("%d\n", weight);
}<|endoftext|>


<commit_before>// fmfrecord.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#include <FlyCapture2.h>
#include <omp.h>
#include <queue>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#define TRIGGER_CAMERA	1

using namespace std;
using namespace FlyCapture2;
using namespace cv;

FILE **fout;
FILE *flog;
FlyCapture2::Camera** ppCameras;
char fname[10][100];
char flogname[100];

char wname[10][100];

void PrintCameraInfo( FlyCapture2::CameraInfo* pCamInfo )
{
    printf("%u %s %s\n", pCamInfo->serialNumber, pCamInfo->modelName, pCamInfo->sensorResolution);
}

void PrintError( FlyCapture2::Error error )
{
    error.PrintErrorTrace();
}

int RunSingleCamera(int i, int numImages)
{
	int frameNumber = 0;
	FlyCapture2::Image rawImage;
	FlyCapture2::Error error;

	bool stream = true;

	// Create a converted image
	FlyCapture2::Image convertedImage;
	FlyCapture2::TimeStamp timestamp;

	queue <int> frameCount;
	queue <Image> rawImageStream;
	queue <Image> dispImageStream;
	queue <TimeStamp> rawTimeStamps;

	#pragma omp parallel sections
	{
		#pragma omp section
		{
			// press [ESC] to exit from continuous streaming mode
			while (stream)
			{
					// Start capturing images
					error = ppCameras[i]->RetrieveBuffer( &rawImage );

					//get image timestamp
					timestamp = rawImage.GetTimeStamp();

					// Convert the raw image
					error = rawImage.Convert( FlyCapture2::PIXEL_FORMAT_MONO8, &convertedImage );

					if (error != FlyCapture2::PGRERROR_OK)
					{
						PrintError( error );
					}

					#pragma omp critical
					{
						dispImageStream.push(convertedImage);
						frameCount.push(frameNumber);
						rawImageStream.push(convertedImage);
						rawTimeStamps.push(timestamp);
					}

					frameNumber++;

					if ( GetAsyncKeyState(VK_ESCAPE) || frameNumber == numImages )
						stream = false;
			}
		}

		#pragma omp section
		{
			while (stream || !rawImageStream.empty())
			{
				if (!rawImageStream.empty())
				{
					Image tImage = rawImageStream.front();
					TimeStamp tStamp = rawTimeStamps.front();

					double dtStamp = (double) tStamp.seconds;

					fwrite(&dtStamp, sizeof(double), 1, fout[i]);
					fwrite(tImage.GetData(), tImage.GetDataSize(), 1, fout[i]);

					fprintf(flog, "Cam %d - Frame %d - TimeStamp [%d %d]\n", i, frameCount.front(), tStamp.seconds, tStamp.microSeconds);

					#pragma omp critical
					{
						frameCount.pop();
						rawImageStream.pop();
						rawTimeStamps.pop();
					}
				}
			}
		}

		#pragma omp section
		{
			while (stream)
			{
				if (!dispImageStream.empty())
				{
					Image dImage;
					dImage.DeepCopy(&dispImageStream.back());

					// convert to OpenCV Mat
					unsigned int rowBytes = (double)dImage.GetReceivedDataSize() / (double)dImage.GetRows();
					Mat frame = Mat(dImage.GetRows(), dImage.GetCols(), CV_8UC1, dImage.GetData(), rowBytes);

					//int width=frame.size().width;
					//int height=frame.size().height;

					//line(frame, Point((width/2)-50,height/2), Point((width/2)+50, height/2), 255);  //crosshair horizontal
					//line(frame, Point(width/2,(height/2)-50), Point(width/2,(height/2)+50), 255);  //crosshair vertical

					imshow(wname[i], frame);
					waitKey(1);

					#pragma omp critical
					dispImageStream = queue<Image>();
				}
			}
		}
	}

	return frameNumber;	//return frame number in the event that [ESC] was pressed to stop camera streaming before set nframes was reached
}

int _tmain(int argc, _TCHAR* argv[])
{
	FlyCapture2::Error error;

	const Mode k_fmt7Mode = MODE_0;
    const PixelFormat k_fmt7PixFmt = PIXEL_FORMAT_RAW8;
	Format7Info fmt7Info;
	bool supported;

    FlyCapture2::PGRGuid guid;
    FlyCapture2::BusManager busMgr;
    unsigned int numCameras;

	unsigned __int32 fmfVersion;
	unsigned __int64 bytesPerChunk, nframes, nframesRun;
	unsigned __int32 sizeHeight, sizeWidth;

	TriggerMode triggerMode;

    error = busMgr.GetNumOfCameras(&numCameras);

    if (error != FlyCapture2::PGRERROR_OK)
    {
        PrintError( error );
        return -1;
    }

    printf( "Number of cameras detected: %u\n\n", numCameras );

    if ( numCameras < 1 )
    {
        printf( "Insufficient number of cameras\n" );
        getchar();
		return -1;
    }

	if (argc == 2)
		nframes = _ttoi(argv[1]);
	else
		nframes = -1;

	// initialize camera and video writer instances
	ppCameras = new FlyCapture2::Camera*[numCameras];
	fout = new FILE*[numCameras];
	flog = new FILE;

	SYSTEMTIME st;
	GetLocalTime(&st);

    for (unsigned int i = 0; i < numCameras; i++)
    {
        ppCameras[i] = new FlyCapture2::Camera();

        error = busMgr.GetCameraFromIndex( i, &guid );
        if (error != FlyCapture2::PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

        // Connect to a camera
        error = ppCameras[i]->Connect( &guid );
        if (error != FlyCapture2::PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

		// Power on the camera
		const unsigned int k_cameraPower = 0x610;
		const unsigned int k_powerVal = 0x80000000;
		error  = ppCameras[i]->WriteRegister( k_cameraPower, k_powerVal );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		const unsigned int millisecondsToSleep = 100;
		unsigned int regVal = 0;
		unsigned int retries = 10;

		// Wait for camera to complete power-up
		do
		{
#if defined(WIN32) || defined(WIN64)
			Sleep(millisecondsToSleep);
#else
			usleep(millisecondsToSleep * 1000);
#endif
			error = ppCameras[i]->ReadRegister(k_cameraPower, &regVal);
			if (error == FlyCapture2::PGRERROR_TIMEOUT)
			{
				// ignore timeout errors, camera may not be responding to
				// register reads during power-up
			}
			else if (error != FlyCapture2::PGRERROR_OK)
			{
				PrintError( error );
				return -1;
			}

			retries--;
		} while ((regVal & k_powerVal) == 0 && retries > 0);

		// Check for timeout errors after retrying
		if (error == FlyCapture2::PGRERROR_TIMEOUT)
		{
			PrintError( error );
			return -1;
		}

        // Get the camera information
        FlyCapture2::CameraInfo camInfo;
        error = ppCameras[i]->GetCameraInfo( &camInfo );
        if (error != FlyCapture2::PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

        PrintCameraInfo(&camInfo);

		// Query for available Format 7 modes
		fmt7Info.mode = k_fmt7Mode;
		error = ppCameras[i]->GetFormat7Info( &fmt7Info, &supported );

		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		if ( (k_fmt7PixFmt & fmt7Info.pixelFormatBitField) == 0 )
		{
			// Pixel format not supported!
			printf("Pixel format is not supported\n");
			return -1;
		}

		Format7ImageSettings fmt7ImageSettings;
		fmt7ImageSettings.mode = k_fmt7Mode;
		fmt7ImageSettings.offsetX = 0;
		fmt7ImageSettings.offsetY = 0;
		fmt7ImageSettings.width = fmt7Info.maxWidth;
		fmt7ImageSettings.height = fmt7Info.maxHeight;
		fmt7ImageSettings.pixelFormat = k_fmt7PixFmt;

		bool valid;
		Format7PacketInfo fmt7PacketInfo;

		// Validate the settings to make sure that they are valid
		error = ppCameras[i]->ValidateFormat7Settings(&fmt7ImageSettings, &valid, &fmt7PacketInfo );

		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		if ( !valid )
		{
			// Settings are not valid
			printf("Format7 settings are not valid\n");
			return -1;
		}

		// Set the settings to the camera
		error = ppCameras[i]->SetFormat7Configuration(&fmt7ImageSettings, fmt7PacketInfo.recommendedBytesPerPacket );

		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		//Lower shutter speed for fast triggering
		FlyCapture2::Property pProp;

		pProp.type = SHUTTER;
		pProp.absControl = true;
		pProp.onePush = false;
		pProp.onOff = true;
		pProp.autoManualMode = false;
		pProp.absValue = 0.006;

		error = ppCameras[i]->SetProperty( &pProp );
        if (error != PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

#if TRIGGER_CAMERA

		// Check for external trigger support
		TriggerModeInfo triggerModeInfo;
		error = ppCameras[i]->GetTriggerModeInfo( &triggerModeInfo );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		if ( triggerModeInfo.present != true )
		{
			printf( "Camera does not support external trigger! Exiting...\n" );
			return -1;
		}

	    // Get current trigger settings
		error = ppCameras[i]->GetTriggerMode( &triggerMode );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		// Set camera to trigger mode 0
		triggerMode.onOff = true;
		triggerMode.mode = 0;
		triggerMode.parameter = 0;

		// Triggering the camera externally using source 0.
		triggerMode.source = 0;

		error = ppCameras[i]->SetTriggerMode( &triggerMode );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}
#endif

		//settings for version 1.0 fmf header
		fmfVersion = 1;
		sizeHeight = fmt7ImageSettings.height;
		sizeWidth = fmt7ImageSettings.width;
		bytesPerChunk = sizeHeight*sizeWidth + sizeof(double);

		sprintf_s(fname[i], "E:\\Cam%d-%d%02d%02dT%02d%02d%02d.fmf", i, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		remove(fname[i]);

		fout[i] = fopen(fname[i], "wb");

		if(fout[i]==NULL)
		{
			printf("\nError opening FMF writer. Recording terminated.");
			return -1;
		}

		//write FMF header data
		fwrite(&fmfVersion, sizeof(unsigned __int32), 1, fout[i]);
		fwrite(&sizeHeight, sizeof(unsigned __int32), 1, fout[i]);
		fwrite(&sizeWidth, sizeof(unsigned __int32), 1, fout[i]);
		fwrite(&bytesPerChunk, sizeof(unsigned __int64), 1, fout[i]);
		fwrite(&nframes, sizeof(unsigned __int64), 1, fout[i]);

		if (i == 0)
		{
				sprintf_s(flogname, "E:\\log-%d%02d%02dT%02d%02d%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
				remove(flogname);

				flog = fopen(flogname, "w");

				if(flog==NULL)
				{
					printf("\nError creating log file. Recording terminated.");
					return -1;
				}
		}

		sprintf_s(wname[i], "camera view %d", i);
    }

	//Starting individual cameras
	for (unsigned int i = 0; i < numCameras; i++)
    {
		error = ppCameras[i]->StartCapture();
		if (error != FlyCapture2::PGRERROR_OK)
		{
			PrintError( error );
			getchar();
			return -1;
		}
	}

	//Retrieve frame rate property
	Property frmRate;
	frmRate.type = FRAME_RATE;
	error = ppCameras[0]->GetProperty( &frmRate );
	if (error != PGRERROR_OK)
	{
	    PrintError( error );
	    return -1;
	}

	 printf( "\nFrame rate is %3.2f fps\n", frmRate.absValue );

	printf("\nGrabbing ...\n");

	//OpenMP parallel execution of camera streaming and recording to uncompressed fmf format videos
	omp_set_nested(1);
	#pragma omp parallel for num_threads(numCameras)
    for (int i = 0; i < numCameras; i++ )
    {
		nframesRun = (unsigned __int64)RunSingleCamera(i, nframes);
    }

	printf( "\nFinished grabbing %d images\n", nframesRun );

	for (unsigned int i = 0; i < numCameras; i++ )
    {
		//check if number of frames streamed from the camera were the same as what was initially set
		if (nframesRun != nframes)
		{
			//seek to location in file where nframes is stored and replace
			fseek (fout[i], 20 , SEEK_SET );
			fwrite(&nframesRun, sizeof(unsigned __int64), 1, fout[i]);
		}

		// close fmf flies
		fclose(fout[i]);

		// Stop capturing images
		ppCameras[i]->StopCapture();
		if (error != FlyCapture2::PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		fclose(flog);

#if TRIGGER_CAMERA
	    // Turn off trigger mode
		triggerMode.onOff = false;
		error = ppCameras[i]->SetTriggerMode( &triggerMode );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}
#endif

		// Disconnect the camera
		ppCameras[i]->Disconnect();
		if (error != FlyCapture2::PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

        // Delete camera instances
		delete ppCameras[i];
    }

	// Free up memory
    delete [] ppCameras;

	printf("Done! Press Enter to exit...\n");
	getchar();

	return 0;
}
<commit_msg>Code cleanup<commit_after>// fmfrecord.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"

#include <FlyCapture2.h>
#include <omp.h>
#include <queue>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#define TRIGGER_CAMERA	1

using namespace std;
using namespace FlyCapture2;
using namespace cv;

FILE **fout;
FILE *flog;
FlyCapture2::Camera** ppCameras;
char fname[10][100];
char flogname[100];

char wname[10][100];

void PrintCameraInfo( FlyCapture2::CameraInfo* pCamInfo )
{
    printf("%u %s %s\n", pCamInfo->serialNumber, pCamInfo->modelName, pCamInfo->sensorResolution);
}

void PrintError( FlyCapture2::Error error )
{
    error.PrintErrorTrace();
}

int RunSingleCamera(int i, int numImages)
{
	int frameNumber = 0;
	FlyCapture2::Image rawImage;
	FlyCapture2::Error error;

	bool stream = true;

	// Create a converted image
	FlyCapture2::Image convertedImage;
	FlyCapture2::TimeStamp timestamp;

	queue <int> frameCount;
	queue <Image> rawImageStream;
	queue <Image> dispImageStream;
	queue <TimeStamp> rawTimeStamps;

	#pragma omp parallel sections
	{
		#pragma omp section
		{
			// press [ESC] to exit from continuous streaming mode
			while (stream)
			{
					// Start capturing images
					error = ppCameras[i]->RetrieveBuffer( &rawImage );

					//get image timestamp
					timestamp = rawImage.GetTimeStamp();

					// Convert the raw image
					error = rawImage.Convert( FlyCapture2::PIXEL_FORMAT_MONO8, &convertedImage );

					if (error != FlyCapture2::PGRERROR_OK)
					{
						PrintError( error );
					}

					#pragma omp critical
					{
						dispImageStream.push(convertedImage);
						frameCount.push(frameNumber);
						rawImageStream.push(convertedImage);
						rawTimeStamps.push(timestamp);
					}

					frameNumber++;

					if ( GetAsyncKeyState(VK_ESCAPE) || frameNumber == numImages )
						stream = false;
			}
		}

		#pragma omp section
		{
			while (stream || !rawImageStream.empty())
			{
				if (!rawImageStream.empty())
				{
					Image tImage = rawImageStream.front();
					TimeStamp tStamp = rawTimeStamps.front();

					double dtStamp = (double) tStamp.seconds;

					fwrite(&dtStamp, sizeof(double), 1, fout[i]);
					fwrite(tImage.GetData(), tImage.GetDataSize(), 1, fout[i]);

					fprintf(flog, "Cam %d - Frame %d - TimeStamp [%d %d]\n", i, frameCount.front(), tStamp.seconds, tStamp.microSeconds);

					#pragma omp critical
					{
						frameCount.pop();
						rawImageStream.pop();
						rawTimeStamps.pop();
					}
				}
			}
		}

		#pragma omp section
		{
			while (stream)
			{
				if (!dispImageStream.empty())
				{
					Image dImage;
					dImage.DeepCopy(&dispImageStream.back());

					// convert to OpenCV Mat
					unsigned int rowBytes = (double)dImage.GetReceivedDataSize() / (double)dImage.GetRows();
					Mat frame = Mat(dImage.GetRows(), dImage.GetCols(), CV_8UC1, dImage.GetData(), rowBytes);

					imshow(wname[i], frame);
					waitKey(1);

					#pragma omp critical
					dispImageStream = queue<Image>();
				}
			}
		}
	}

	return frameNumber;	//return frame number in the event that [ESC] was pressed to stop camera streaming before set nframes was reached
}

int _tmain(int argc, _TCHAR* argv[])
{
	FlyCapture2::Error error;

	const Mode k_fmt7Mode = MODE_0;
    const PixelFormat k_fmt7PixFmt = PIXEL_FORMAT_RAW8;
	Format7Info fmt7Info;
	bool supported;

    FlyCapture2::PGRGuid guid;
    FlyCapture2::BusManager busMgr;
    unsigned int numCameras;

	unsigned __int32 fmfVersion;
	unsigned __int64 bytesPerChunk, nframes, nframesRun;
	unsigned __int32 sizeHeight, sizeWidth;

	TriggerMode triggerMode;

    error = busMgr.GetNumOfCameras(&numCameras);

    if (error != FlyCapture2::PGRERROR_OK)
    {
        PrintError( error );
        return -1;
    }

    printf( "Number of cameras detected: %u\n\n", numCameras );

    if ( numCameras < 1 )
    {
        printf( "Insufficient number of cameras\n" );
        getchar();
		return -1;
    }

	if (argc == 2)
		nframes = _ttoi(argv[1]);
	else
		nframes = -1;

	// initialize camera and video writer instances
	ppCameras = new FlyCapture2::Camera*[numCameras];
	fout = new FILE*[numCameras];
	flog = new FILE;

	SYSTEMTIME st;
	GetLocalTime(&st);

    for (unsigned int i = 0; i < numCameras; i++)
    {
        ppCameras[i] = new FlyCapture2::Camera();

        error = busMgr.GetCameraFromIndex( i, &guid );
        if (error != FlyCapture2::PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

        // Connect to a camera
        error = ppCameras[i]->Connect( &guid );
        if (error != FlyCapture2::PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

		// Power on the camera
		const unsigned int k_cameraPower = 0x610;
		const unsigned int k_powerVal = 0x80000000;
		error  = ppCameras[i]->WriteRegister( k_cameraPower, k_powerVal );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		const unsigned int millisecondsToSleep = 100;
		unsigned int regVal = 0;
		unsigned int retries = 10;

		// Wait for camera to complete power-up
		do
		{
#if defined(WIN32) || defined(WIN64)
			Sleep(millisecondsToSleep);
#else
			usleep(millisecondsToSleep * 1000);
#endif
			error = ppCameras[i]->ReadRegister(k_cameraPower, &regVal);
			if (error == FlyCapture2::PGRERROR_TIMEOUT)
			{
				// ignore timeout errors, camera may not be responding to
				// register reads during power-up
			}
			else if (error != FlyCapture2::PGRERROR_OK)
			{
				PrintError( error );
				return -1;
			}

			retries--;
		} while ((regVal & k_powerVal) == 0 && retries > 0);

		// Check for timeout errors after retrying
		if (error == FlyCapture2::PGRERROR_TIMEOUT)
		{
			PrintError( error );
			return -1;
		}

        // Get the camera information
        FlyCapture2::CameraInfo camInfo;
        error = ppCameras[i]->GetCameraInfo( &camInfo );
        if (error != FlyCapture2::PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

        PrintCameraInfo(&camInfo);

		// Query for available Format 7 modes
		fmt7Info.mode = k_fmt7Mode;
		error = ppCameras[i]->GetFormat7Info( &fmt7Info, &supported );

		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		if ( (k_fmt7PixFmt & fmt7Info.pixelFormatBitField) == 0 )
		{
			// Pixel format not supported!
			printf("Pixel format is not supported\n");
			return -1;
		}

		Format7ImageSettings fmt7ImageSettings;
		fmt7ImageSettings.mode = k_fmt7Mode;
		fmt7ImageSettings.offsetX = 0;
		fmt7ImageSettings.offsetY = 0;
		fmt7ImageSettings.width = fmt7Info.maxWidth;
		fmt7ImageSettings.height = fmt7Info.maxHeight;
		fmt7ImageSettings.pixelFormat = k_fmt7PixFmt;

		bool valid;
		Format7PacketInfo fmt7PacketInfo;

		// Validate the settings to make sure that they are valid
		error = ppCameras[i]->ValidateFormat7Settings(&fmt7ImageSettings, &valid, &fmt7PacketInfo );

		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		if ( !valid )
		{
			// Settings are not valid
			printf("Format7 settings are not valid\n");
			return -1;
		}

		// Set the settings to the camera
		error = ppCameras[i]->SetFormat7Configuration(&fmt7ImageSettings, fmt7PacketInfo.recommendedBytesPerPacket );

		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		//Lower shutter speed for fast triggering
		FlyCapture2::Property pProp;

		pProp.type = SHUTTER;
		pProp.absControl = true;
		pProp.onePush = false;
		pProp.onOff = true;
		pProp.autoManualMode = false;
		pProp.absValue = 0.006;

		error = ppCameras[i]->SetProperty( &pProp );
        if (error != PGRERROR_OK)
        {
            PrintError( error );
            return -1;
        }

#if TRIGGER_CAMERA

		// Check for external trigger support
		TriggerModeInfo triggerModeInfo;
		error = ppCameras[i]->GetTriggerModeInfo( &triggerModeInfo );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		if ( triggerModeInfo.present != true )
		{
			printf( "Camera does not support external trigger! Exiting...\n" );
			return -1;
		}

	    // Get current trigger settings
		error = ppCameras[i]->GetTriggerMode( &triggerMode );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		// Set camera to trigger mode 0
		triggerMode.onOff = true;
		triggerMode.mode = 0;
		triggerMode.parameter = 0;

		// Triggering the camera externally using source 0.
		triggerMode.source = 0;

		error = ppCameras[i]->SetTriggerMode( &triggerMode );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}
#endif

		//settings for version 1.0 fmf header
		fmfVersion = 1;
		sizeHeight = fmt7ImageSettings.height;
		sizeWidth = fmt7ImageSettings.width;
		bytesPerChunk = sizeHeight*sizeWidth + sizeof(double);

		sprintf_s(fname[i], "E:\\Cam%d-%d%02d%02dT%02d%02d%02d.fmf", i, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
		remove(fname[i]);

		fout[i] = fopen(fname[i], "wb");

		if(fout[i]==NULL)
		{
			printf("\nError opening FMF writer. Recording terminated.");
			return -1;
		}

		//write FMF header data
		fwrite(&fmfVersion, sizeof(unsigned __int32), 1, fout[i]);
		fwrite(&sizeHeight, sizeof(unsigned __int32), 1, fout[i]);
		fwrite(&sizeWidth, sizeof(unsigned __int32), 1, fout[i]);
		fwrite(&bytesPerChunk, sizeof(unsigned __int64), 1, fout[i]);
		fwrite(&nframes, sizeof(unsigned __int64), 1, fout[i]);

		if (i == 0)
		{
				sprintf_s(flogname, "E:\\log-%d%02d%02dT%02d%02d%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
				remove(flogname);

				flog = fopen(flogname, "w");

				if(flog==NULL)
				{
					printf("\nError creating log file. Recording terminated.");
					return -1;
				}
		}

		sprintf_s(wname[i], "camera view %d", i);
    }

	//Starting individual cameras
	for (unsigned int i = 0; i < numCameras; i++)
    {
		error = ppCameras[i]->StartCapture();
		if (error != FlyCapture2::PGRERROR_OK)
		{
			PrintError( error );
			getchar();
			return -1;
		}
	}

	//Retrieve frame rate property
	Property frmRate;
	frmRate.type = FRAME_RATE;
	error = ppCameras[0]->GetProperty( &frmRate );
	if (error != PGRERROR_OK)
	{
	    PrintError( error );
	    return -1;
	}

	 printf( "\nFrame rate is %3.2f fps\n", frmRate.absValue );

	printf("\nGrabbing ...\n");

	//OpenMP parallel execution of camera streaming and recording to uncompressed fmf format videos
	omp_set_nested(1);
	#pragma omp parallel for num_threads(numCameras)
    for (int i = 0; i < numCameras; i++ )
    {
		nframesRun = (unsigned __int64)RunSingleCamera(i, nframes);
    }

	printf( "\nFinished grabbing %d images\n", nframesRun );

	for (unsigned int i = 0; i < numCameras; i++ )
    {
		//check if number of frames streamed from the camera were the same as what was initially set
		if (nframesRun != nframes)
		{
			//seek to location in file where nframes is stored and replace
			fseek (fout[i], 20 , SEEK_SET );
			fwrite(&nframesRun, sizeof(unsigned __int64), 1, fout[i]);
		}

		// close fmf flies
		fclose(fout[i]);

		// Stop capturing images
		ppCameras[i]->StopCapture();
		if (error != FlyCapture2::PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

		fclose(flog);

#if TRIGGER_CAMERA
	    // Turn off trigger mode
		triggerMode.onOff = false;
		error = ppCameras[i]->SetTriggerMode( &triggerMode );
		if (error != PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}
#endif

		// Disconnect the camera
		ppCameras[i]->Disconnect();
		if (error != FlyCapture2::PGRERROR_OK)
		{
			PrintError( error );
			return -1;
		}

        // Delete camera instances
		delete ppCameras[i];
    }

	// Free up memory
    delete [] ppCameras;

	printf("Done! Press Enter to exit...\n");
	getchar();

	return 0;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-base/io/fileutil.h>
#include <fnord-base/io/mmappedfile.h>
#include <fnord-base/util/binarymessagereader.h>
#include <fnord-base/util/binarymessagewriter.h>
#include <fnord-sstable/sstablewriter.h>
#include <fnord-sstable/sstablereader.h>
#include <fnord-tsdb/RecordSet.h>

namespace fnord {
namespace tsdb {

RecordRef::RecordRef(
    uint64_t _record_id,
    uint64_t _time,
    const Buffer& _record) :
    record_id(_record_id),
    time(_time),
    record(_record) {}

RecordSet::RecordSet(
    const String& filename_prefix,
    RecordSetState state /* = RecordSetState{} */) :
    filename_prefix_(filename_prefix),
    state_(state),
    max_datafile_size_(kDefaultMaxDatafileSize),
    version_(0) {
  auto id_index_fn = [this] (uint64_t id, const void* data, size_t size) {
    commitlog_ids_.emplace(id);
  };

  for (const auto& o : state_.old_commitlogs) {
    loadCommitlog(o, id_index_fn);
  }

  if (!state.commitlog.isEmpty()) {
    loadCommitlog(state.commitlog.get(), id_index_fn);
  }
}

RecordSet::RecordSetState RecordSet::getState() const {
  std::unique_lock<std::mutex> lk(mutex_);
  return state_;
}

size_t RecordSet::version() const {
  std::unique_lock<std::mutex> lk(mutex_);
  return version_;
}

size_t RecordSet::commitlogSize() const {
  std::unique_lock<std::mutex> lk(mutex_);
  return commitlog_ids_.size();
}

void RecordSet::addRecord(uint64_t record_id, const Buffer& message) {
  util::BinaryMessageWriter buf;
  buf.appendUInt64(record_id);
  buf.appendVarUInt(message.size());
  buf.append(message.data(), message.size());

  std::unique_lock<std::mutex> lk(mutex_);

  if (commitlog_ids_.count(record_id) > 0) {
    return;
  }

  addRecords(buf);

  commitlog_ids_.emplace(record_id);
}

void RecordSet::addRecords(const Vector<RecordRef>& records) {
  std::unique_lock<std::mutex> lk(mutex_);

  util::BinaryMessageWriter buf;
  for (const auto& rec : records) {
    if (commitlog_ids_.count(rec.record_id) > 0) {
      continue;
    }

    buf.appendUInt64(rec.record_id);
    buf.appendVarUInt(rec.record.size());
    buf.append(rec.record.data(), rec.record.size());
  }

  if (buf.size() == 0) {
    return;
  }

  addRecords(buf);

  for (const auto& rec : records) {
    commitlog_ids_.emplace(rec.record_id);
  }
}

void RecordSet::addRecords(const util::BinaryMessageWriter& buf) {
  String commitlog;
  uint64_t commitlog_size;
  if (state_.commitlog.isEmpty()) {
    commitlog = filename_prefix_ + rnd_.hex64() + ".log";
    commitlog_size = 0;
    ++version_;
  } else {
    commitlog = state_.commitlog.get();
    commitlog_size = state_.commitlog_size;
  }

  auto file = File::openFile(commitlog, File::O_WRITE | File::O_CREATEOROPEN);
  file.truncate(sizeof(uint64_t) + commitlog_size + buf.size());
  file.seekTo(sizeof(uint64_t) + commitlog_size);
  file.write(buf.data(), buf.size());

  // FIXPAUL fsync here for non order preserving storage?

  commitlog_size += buf.size();
  file.seekTo(0);
  file.write(&commitlog_size, sizeof(commitlog_size));

  state_.commitlog = Some(commitlog);
  state_.commitlog_size = commitlog_size;
}

void RecordSet::rollCommitlog() {
  if (state_.commitlog.isEmpty()) {
    return;
  }

  auto old_log = state_.commitlog.get();
  FileUtil::truncate(old_log, state_.commitlog_size + sizeof(uint64_t));
  state_.old_commitlogs.emplace(old_log);
  state_.commitlog = None<String>();
  state_.commitlog_size = 0;
  ++version_;
}

void RecordSet::compact() {
  Set<String> deleted_files;
  compact(&deleted_files);
}

void RecordSet::compact(Set<String>* deleted_files) {
  std::unique_lock<std::mutex> compact_lk(compact_mutex_, std::defer_lock);
  if (!compact_lk.try_lock()) {
    return; // compaction is already running
  }

  std::unique_lock<std::mutex> lk(mutex_);
  rollCommitlog();
  auto snap = state_;
  lk.unlock();

  if (snap.old_commitlogs.size() == 0) {
    return;
  }

  auto outfile_path = filename_prefix_ + rnd_.hex64() + ".sst";
  auto outfile = sstable::SSTableWriter::create(
      outfile_path + "~",
      sstable::IndexProvider{},
      nullptr,
      0);

  size_t outfile_nrecords = 0;
  size_t outfile_offset = 0;

  Set<uint64_t> old_id_set;
  Set<uint64_t> new_id_set;

  bool rewrite_last =
      snap.datafiles.size() > 0 &&
      FileUtil::size(snap.datafiles.back().filename) < max_datafile_size_;

  if (rewrite_last) {
    outfile_offset = snap.datafiles.back().offset;
  } else {
    outfile_offset = snap.datafiles.size() > 0 ?
        snap.datafiles.back().offset + snap.datafiles.back().num_records :
        0;
  }

  for (int j = 0; j < snap.datafiles.size(); ++j) {
    sstable::SSTableReader reader(snap.datafiles[j].filename);
    auto cursor = reader.getCursor();

    while (cursor->valid()) {
      void* key;
      size_t key_size;
      cursor->getKey(&key, &key_size);
      if (key_size != sizeof(uint64_t)) {
        RAISE(kRuntimeError, "invalid row");
      }

      uint64_t msgid = *((uint64_t*) key);
      old_id_set.emplace(msgid);

      if (rewrite_last && j + 1 == snap.datafiles.size()) {
        void* data;
        size_t data_size;
        cursor->getData(&data, &data_size);

        outfile->appendRow(key, key_size, data, data_size);
        ++outfile_nrecords;
      }

      if (!cursor->next()) {
        break;
      }
    }
  }

  for (const auto& cl : snap.old_commitlogs) {
    loadCommitlog(cl, [this, &outfile, &old_id_set, &new_id_set, &outfile_nrecords] (
        uint64_t id,
        const void* data,
        size_t size) {
      if (new_id_set.count(id) > 0) {
        return;
      }

      new_id_set.emplace(id);

      if (old_id_set.count(id) > 0) {
        return;
      }

      outfile->appendRow(&id, sizeof(id), data, size);
      ++outfile_nrecords;
    });
  }

  if (outfile_nrecords == 0) {
    return;
  }

  outfile->finalize();
  FileUtil::mv(outfile_path + "~", outfile_path);

  lk.lock();

  if (rewrite_last) {
    deleted_files->emplace(state_.datafiles.back().filename);
    state_.datafiles.pop_back();
  }

  state_.datafiles.emplace_back(DatafileRef {
    .filename = outfile_path,
    .num_records = outfile_nrecords,
    .offset = outfile_offset
  });

  for (const auto& cl : snap.old_commitlogs) {
    state_.old_commitlogs.erase(cl);
    deleted_files->emplace(cl);
  }

  for (const auto& id : new_id_set) {
    commitlog_ids_.erase(id);
  }

  ++version_;
}

void RecordSet::loadCommitlog(
    const String& filename,
    Function<void (uint64_t, const void*, size_t)> fn) {
  io::MmappedFile mmap(File::openFile(filename, File::O_READ));
  util::BinaryMessageReader reader(mmap.data(), mmap.size());
  auto limit = *reader.readUInt64() + sizeof(uint64_t);

  while (reader.position() < limit) {
    auto id = *reader.readUInt64();
    auto len = reader.readVarUInt();
    auto data = reader.read(len);

    fn(id, data, len);
  }
}

uint64_t RecordSet::numRecords() const {
  uint64_t res = 0;

  std::unique_lock<std::mutex> lk(mutex_);
  for (const auto& df : state_.datafiles) {
    res += df.num_records;
  }

  return res;
}

uint64_t RecordSet::firstOffset() const {
  std::unique_lock<std::mutex> lk(mutex_);

  if (state_.datafiles.size() == 0) {
    return 0;
  } else {
    return state_.datafiles.front().offset;
  }
}

uint64_t RecordSet::lastOffset() const {
  std::unique_lock<std::mutex> lk(mutex_);

  if (state_.datafiles.size() == 0) {
    return 0;
  } else {
    return state_.datafiles.back().offset + state_.datafiles.back().num_records;
  }
}

void RecordSet::fetchRecords(
      uint64_t offset,
      uint64_t limit,
      Function<void (uint64_t record_id, const void* record_data, size_t record_size)> fn) {
  Set<uint64_t> res;

  std::unique_lock<std::mutex> lk(mutex_);
  auto datafiles = state_.datafiles;
  lk.unlock();

  if (datafiles.size() == 0) {
    return;
  }

  size_t o = datafiles.front().offset;
  if (o > offset) {
    RAISEF(kRuntimeError, "offset was garbage collected: $0", offset);
  }

  size_t l = 0;
  for (const auto& datafile : datafiles) {
    if (o + datafile.num_records <= offset) {
      o += datafile.num_records;
      continue;
    }

    sstable::SSTableReader reader(datafile.filename);
    auto cursor = reader.getCursor();

    while (cursor->valid()) {
      if (++o > offset) {
        void* key;
        size_t key_size;
        cursor->getKey(&key, &key_size);
        if (key_size != sizeof(uint64_t)) {
          RAISE(kRuntimeError, "invalid row");
        }

        uint64_t msgid = *((uint64_t*) key);

        void* data;
        size_t data_size;
        cursor->getData(&data, &data_size);
        fn(msgid, data, data_size);

        if (++l == limit) {
          return;
        }
      }

      if (!cursor->next()) {
        break;
      }
    }
  }
}

Set<uint64_t> RecordSet::listRecords() const {
  Set<uint64_t> res;

  std::unique_lock<std::mutex> lk(mutex_);
  if (state_.datafiles.empty()) {
    return res;
  }

  auto datafiles = state_.datafiles;
  lk.unlock();

  for (const auto& datafile : datafiles) {
    sstable::SSTableReader reader(datafile.filename);
    auto cursor = reader.getCursor();

    while (cursor->valid()) {
      void* key;
      size_t key_size;
      cursor->getKey(&key, &key_size);
      if (key_size != sizeof(uint64_t)) {
        RAISE(kRuntimeError, "invalid row");
      }

      res.emplace(*((uint64_t*) key));

      if (!cursor->next()) {
        break;
      }
    }
  }

  return res;
}

Vector<String> RecordSet::listDatafiles() const {
  std::unique_lock<std::mutex> lk(mutex_);
  Vector<String> datafiles;

  for (const auto& df : state_.datafiles) {
    datafiles.emplace_back(df.filename);
  }

  return datafiles;
}

void RecordSet::setMaxDatafileSize(size_t size) {
  max_datafile_size_ = size;
}

const String& RecordSet::filenamePrefix() const {
 return filename_prefix_;
}

RecordSet::RecordSetState::RecordSetState() :
    commitlog_size(0) {}

void RecordSet::RecordSetState::encode(
    util::BinaryMessageWriter* writer) const {
  Set<String> all_commitlogs = old_commitlogs;
  if (!commitlog.isEmpty()) {
    all_commitlogs.emplace(commitlog.get());
  }

  writer->appendVarUInt(datafiles.size());
  for (const auto& d : datafiles) {
    writer->appendVarUInt(d.num_records);
    writer->appendVarUInt(d.offset);
    writer->appendLenencString(d.filename);
  }

  writer->appendVarUInt(all_commitlogs.size());
  for (const auto& cl : all_commitlogs) {
    writer->appendLenencString(cl);
  }
}

void RecordSet::RecordSetState::decode(util::BinaryMessageReader* reader) {
  auto num_datafiles = reader->readVarUInt();
  for (size_t i = 0; i < num_datafiles; ++i) {
    auto num_records = reader->readVarUInt();
    auto offset = reader->readVarUInt();
    auto fname = reader->readLenencString();
    datafiles.emplace_back(DatafileRef {
      .filename = fname,
      .num_records = num_records,
      .offset = offset
    });
  }

  auto num_commitlogs = reader->readVarUInt();
  for (size_t i = 0; i < num_commitlogs; ++i) {
    auto fname = reader->readLenencString();
    old_commitlogs.emplace(fname);
  }
}

} // namespace tsdb
} // namespace fnord

<commit_msg>delete commitlogs if they do not contain any unseen data<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-base/io/fileutil.h>
#include <fnord-base/io/mmappedfile.h>
#include <fnord-base/util/binarymessagereader.h>
#include <fnord-base/util/binarymessagewriter.h>
#include <fnord-sstable/sstablewriter.h>
#include <fnord-sstable/sstablereader.h>
#include <fnord-tsdb/RecordSet.h>

namespace fnord {
namespace tsdb {

RecordRef::RecordRef(
    uint64_t _record_id,
    uint64_t _time,
    const Buffer& _record) :
    record_id(_record_id),
    time(_time),
    record(_record) {}

RecordSet::RecordSet(
    const String& filename_prefix,
    RecordSetState state /* = RecordSetState{} */) :
    filename_prefix_(filename_prefix),
    state_(state),
    max_datafile_size_(kDefaultMaxDatafileSize),
    version_(0) {
  auto id_index_fn = [this] (uint64_t id, const void* data, size_t size) {
    commitlog_ids_.emplace(id);
  };

  for (const auto& o : state_.old_commitlogs) {
    loadCommitlog(o, id_index_fn);
  }

  if (!state.commitlog.isEmpty()) {
    loadCommitlog(state.commitlog.get(), id_index_fn);
  }
}

RecordSet::RecordSetState RecordSet::getState() const {
  std::unique_lock<std::mutex> lk(mutex_);
  return state_;
}

size_t RecordSet::version() const {
  std::unique_lock<std::mutex> lk(mutex_);
  return version_;
}

size_t RecordSet::commitlogSize() const {
  std::unique_lock<std::mutex> lk(mutex_);
  return commitlog_ids_.size();
}

void RecordSet::addRecord(uint64_t record_id, const Buffer& message) {
  util::BinaryMessageWriter buf;
  buf.appendUInt64(record_id);
  buf.appendVarUInt(message.size());
  buf.append(message.data(), message.size());

  std::unique_lock<std::mutex> lk(mutex_);

  if (commitlog_ids_.count(record_id) > 0) {
    return;
  }

  addRecords(buf);

  commitlog_ids_.emplace(record_id);
}

void RecordSet::addRecords(const Vector<RecordRef>& records) {
  std::unique_lock<std::mutex> lk(mutex_);

  util::BinaryMessageWriter buf;
  for (const auto& rec : records) {
    if (commitlog_ids_.count(rec.record_id) > 0) {
      continue;
    }

    buf.appendUInt64(rec.record_id);
    buf.appendVarUInt(rec.record.size());
    buf.append(rec.record.data(), rec.record.size());
  }

  if (buf.size() == 0) {
    return;
  }

  addRecords(buf);

  for (const auto& rec : records) {
    commitlog_ids_.emplace(rec.record_id);
  }
}

void RecordSet::addRecords(const util::BinaryMessageWriter& buf) {
  String commitlog;
  uint64_t commitlog_size;
  if (state_.commitlog.isEmpty()) {
    commitlog = filename_prefix_ + rnd_.hex64() + ".log";
    commitlog_size = 0;
    ++version_;
  } else {
    commitlog = state_.commitlog.get();
    commitlog_size = state_.commitlog_size;
  }

  auto file = File::openFile(commitlog, File::O_WRITE | File::O_CREATEOROPEN);
  file.truncate(sizeof(uint64_t) + commitlog_size + buf.size());
  file.seekTo(sizeof(uint64_t) + commitlog_size);
  file.write(buf.data(), buf.size());

  // FIXPAUL fsync here for non order preserving storage?

  commitlog_size += buf.size();
  file.seekTo(0);
  file.write(&commitlog_size, sizeof(commitlog_size));

  state_.commitlog = Some(commitlog);
  state_.commitlog_size = commitlog_size;
}

void RecordSet::rollCommitlog() {
  if (state_.commitlog.isEmpty()) {
    return;
  }

  auto old_log = state_.commitlog.get();
  FileUtil::truncate(old_log, state_.commitlog_size + sizeof(uint64_t));
  state_.old_commitlogs.emplace(old_log);
  state_.commitlog = None<String>();
  state_.commitlog_size = 0;
  ++version_;
}

void RecordSet::compact() {
  Set<String> deleted_files;
  compact(&deleted_files);
}

void RecordSet::compact(Set<String>* deleted_files) {
  std::unique_lock<std::mutex> compact_lk(compact_mutex_, std::defer_lock);
  if (!compact_lk.try_lock()) {
    return; // compaction is already running
  }

  std::unique_lock<std::mutex> lk(mutex_);
  rollCommitlog();
  auto snap = state_;
  lk.unlock();

  if (snap.old_commitlogs.size() == 0) {
    return;
  }

  auto outfile_path = filename_prefix_ + rnd_.hex64() + ".sst";
  auto outfile = sstable::SSTableWriter::create(
      outfile_path + "~",
      sstable::IndexProvider{},
      nullptr,
      0);

  size_t outfile_nrecords = 0;
  size_t outfile_offset = 0;

  Set<uint64_t> old_id_set;
  Set<uint64_t> new_id_set;

  bool rewrite_last =
      snap.datafiles.size() > 0 &&
      FileUtil::size(snap.datafiles.back().filename) < max_datafile_size_;

  if (rewrite_last) {
    outfile_offset = snap.datafiles.back().offset;
  } else {
    outfile_offset = snap.datafiles.size() > 0 ?
        snap.datafiles.back().offset + snap.datafiles.back().num_records :
        0;
  }

  for (int j = 0; j < snap.datafiles.size(); ++j) {
    sstable::SSTableReader reader(snap.datafiles[j].filename);
    auto cursor = reader.getCursor();

    while (cursor->valid()) {
      void* key;
      size_t key_size;
      cursor->getKey(&key, &key_size);
      if (key_size != sizeof(uint64_t)) {
        RAISE(kRuntimeError, "invalid row");
      }

      uint64_t msgid = *((uint64_t*) key);
      old_id_set.emplace(msgid);

      if (rewrite_last && j + 1 == snap.datafiles.size()) {
        void* data;
        size_t data_size;
        cursor->getData(&data, &data_size);

        outfile->appendRow(key, key_size, data, data_size);
        ++outfile_nrecords;
      }

      if (!cursor->next()) {
        break;
      }
    }
  }

  for (const auto& cl : snap.old_commitlogs) {
    loadCommitlog(cl, [this, &outfile, &old_id_set, &new_id_set, &outfile_nrecords] (
        uint64_t id,
        const void* data,
        size_t size) {
      if (new_id_set.count(id) > 0) {
        return;
      }

      new_id_set.emplace(id);

      if (old_id_set.count(id) > 0) {
        return;
      }

      outfile->appendRow(&id, sizeof(id), data, size);
      ++outfile_nrecords;
    });
  }

  if (outfile_nrecords == 0) {
    FileUtil::rm(outfile_path + "~");
  } else {
    outfile->finalize();
    FileUtil::mv(outfile_path + "~", outfile_path);
  }

  lk.lock();

  if (rewrite_last) {
    deleted_files->emplace(state_.datafiles.back().filename);
    state_.datafiles.pop_back();
  }

  if (outfile_nrecords > 0) {
    state_.datafiles.emplace_back(DatafileRef {
      .filename = outfile_path,
      .num_records = outfile_nrecords,
      .offset = outfile_offset
    });
  }

  for (const auto& cl : snap.old_commitlogs) {
    state_.old_commitlogs.erase(cl);
    deleted_files->emplace(cl);
  }

  for (const auto& id : new_id_set) {
    commitlog_ids_.erase(id);
  }

  ++version_;
}

void RecordSet::loadCommitlog(
    const String& filename,
    Function<void (uint64_t, const void*, size_t)> fn) {
  io::MmappedFile mmap(File::openFile(filename, File::O_READ));
  util::BinaryMessageReader reader(mmap.data(), mmap.size());
  auto limit = *reader.readUInt64() + sizeof(uint64_t);

  while (reader.position() < limit) {
    auto id = *reader.readUInt64();
    auto len = reader.readVarUInt();
    auto data = reader.read(len);

    fn(id, data, len);
  }
}

uint64_t RecordSet::numRecords() const {
  uint64_t res = 0;

  std::unique_lock<std::mutex> lk(mutex_);
  for (const auto& df : state_.datafiles) {
    res += df.num_records;
  }

  return res;
}

uint64_t RecordSet::firstOffset() const {
  std::unique_lock<std::mutex> lk(mutex_);

  if (state_.datafiles.size() == 0) {
    return 0;
  } else {
    return state_.datafiles.front().offset;
  }
}

uint64_t RecordSet::lastOffset() const {
  std::unique_lock<std::mutex> lk(mutex_);

  if (state_.datafiles.size() == 0) {
    return 0;
  } else {
    return state_.datafiles.back().offset + state_.datafiles.back().num_records;
  }
}

void RecordSet::fetchRecords(
      uint64_t offset,
      uint64_t limit,
      Function<void (uint64_t record_id, const void* record_data, size_t record_size)> fn) {
  Set<uint64_t> res;

  std::unique_lock<std::mutex> lk(mutex_);
  auto datafiles = state_.datafiles;
  lk.unlock();

  if (datafiles.size() == 0) {
    return;
  }

  size_t o = datafiles.front().offset;
  if (o > offset) {
    RAISEF(kRuntimeError, "offset was garbage collected: $0", offset);
  }

  size_t l = 0;
  for (const auto& datafile : datafiles) {
    if (o + datafile.num_records <= offset) {
      o += datafile.num_records;
      continue;
    }

    sstable::SSTableReader reader(datafile.filename);
    auto cursor = reader.getCursor();

    while (cursor->valid()) {
      if (++o > offset) {
        void* key;
        size_t key_size;
        cursor->getKey(&key, &key_size);
        if (key_size != sizeof(uint64_t)) {
          RAISE(kRuntimeError, "invalid row");
        }

        uint64_t msgid = *((uint64_t*) key);

        void* data;
        size_t data_size;
        cursor->getData(&data, &data_size);
        fn(msgid, data, data_size);

        if (++l == limit) {
          return;
        }
      }

      if (!cursor->next()) {
        break;
      }
    }
  }
}

Set<uint64_t> RecordSet::listRecords() const {
  Set<uint64_t> res;

  std::unique_lock<std::mutex> lk(mutex_);
  if (state_.datafiles.empty()) {
    return res;
  }

  auto datafiles = state_.datafiles;
  lk.unlock();

  for (const auto& datafile : datafiles) {
    sstable::SSTableReader reader(datafile.filename);
    auto cursor = reader.getCursor();

    while (cursor->valid()) {
      void* key;
      size_t key_size;
      cursor->getKey(&key, &key_size);
      if (key_size != sizeof(uint64_t)) {
        RAISE(kRuntimeError, "invalid row");
      }

      res.emplace(*((uint64_t*) key));

      if (!cursor->next()) {
        break;
      }
    }
  }

  return res;
}

Vector<String> RecordSet::listDatafiles() const {
  std::unique_lock<std::mutex> lk(mutex_);
  Vector<String> datafiles;

  for (const auto& df : state_.datafiles) {
    datafiles.emplace_back(df.filename);
  }

  return datafiles;
}

void RecordSet::setMaxDatafileSize(size_t size) {
  max_datafile_size_ = size;
}

const String& RecordSet::filenamePrefix() const {
 return filename_prefix_;
}

RecordSet::RecordSetState::RecordSetState() :
    commitlog_size(0) {}

void RecordSet::RecordSetState::encode(
    util::BinaryMessageWriter* writer) const {
  Set<String> all_commitlogs = old_commitlogs;
  if (!commitlog.isEmpty()) {
    all_commitlogs.emplace(commitlog.get());
  }

  writer->appendVarUInt(datafiles.size());
  for (const auto& d : datafiles) {
    writer->appendVarUInt(d.num_records);
    writer->appendVarUInt(d.offset);
    writer->appendLenencString(d.filename);
  }

  writer->appendVarUInt(all_commitlogs.size());
  for (const auto& cl : all_commitlogs) {
    writer->appendLenencString(cl);
  }
}

void RecordSet::RecordSetState::decode(util::BinaryMessageReader* reader) {
  auto num_datafiles = reader->readVarUInt();
  for (size_t i = 0; i < num_datafiles; ++i) {
    auto num_records = reader->readVarUInt();
    auto offset = reader->readVarUInt();
    auto fname = reader->readLenencString();
    datafiles.emplace_back(DatafileRef {
      .filename = fname,
      .num_records = num_records,
      .offset = offset
    });
  }

  auto num_commitlogs = reader->readVarUInt();
  for (size_t i = 0; i < num_commitlogs; ++i) {
    auto fname = reader->readLenencString();
    old_commitlogs.emplace(fname);
  }
}

} // namespace tsdb
} // namespace fnord

<|endoftext|>


<commit_before>#include "tests.h"

using namespace swoole;

static void coro1(void *arg)
{
    int cid = coroutine_get_cid();
    coroutine_t *co = coroutine_get_by_id(cid);
    coroutine_yield(co);
}

TEST(coroutine, create)
{
    int cid = coroutine_create(coro1, NULL);
    ASSERT_GT(cid, 0);
    coroutine_resume(coroutine_get_by_id(cid));
}

static void coro2(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9801, 0.5);
    ASSERT_EQ(retval, false);
    ASSERT_EQ(sock.errCode, ECONNREFUSED);
}

TEST(coroutine, socket_connect_refused)
{
    int cid = coroutine_create(coro2, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro3(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    sock.setTimeout(0.5);
    bool retval = sock.connect("192.0.0.1", 9801);
    ASSERT_EQ(retval, false);
    ASSERT_EQ(sock.errCode, ETIMEDOUT);
}

TEST(coroutine, socket_connect_timeout)
{
    int cid = coroutine_create(coro3, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro4(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("www.baidu.com", 80, 0.5);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
}

TEST(coroutine, socket_connect_with_dns)
{
    int cid = coroutine_create(coro4, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro5(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9501, -1);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
    sock.send("echo", 5);
    char buf[128];
    int n = sock.recv(buf, sizeof(buf));
    ASSERT_EQ(strcmp(buf, "hello world\n"), 0);
}

TEST(coroutine, socket_recv_success)
{
    int cid = coroutine_create(coro5, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro6(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9501, -1);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
    sock.send("close", 6);
    char buf[128];
    int n = sock.recv(buf, sizeof(buf));
    ASSERT_EQ(n, 0);
}

TEST(coroutine, socket_recv_fail)
{
    int cid = coroutine_create(coro6, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

TEST(coroutine, socket_bind_success)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("127.0.0.1", 9909);
    ASSERT_EQ(retval, true);
}

TEST(coroutine, socket_bind_fail)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("192.111.11.1", 9909);
    ASSERT_EQ(retval, false);
    ASSERT_EQ(sock.errCode, EADDRNOTAVAIL);
}

TEST(coroutine, socket_listen)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("127.0.0.1", 9909);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.listen(128), true);
}

/**
 * Accept
 */
static void coro7(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("127.0.0.1", 9909);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.listen(128), true);

    Socket *conn = sock.accept();
    ASSERT_NE(conn, nullptr);
}

/**
 * Connect
 */
static void coro8(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9909, -1);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
}

TEST(coroutine, socket_accept)
{
    coroutine_create(coro7, NULL);
    coroutine_create(coro8, NULL);
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro9(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    auto retval = sock.resolve("www.qq.com");
    ASSERT_EQ(retval, "180.163.26.39");
}

TEST(coroutine, socket_resolve)
{
    coroutine_create(coro9, NULL);
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

#define CID_ALLOC_PRINT  0

TEST(coroutine, cid_alloc)
{
    //alloc [1] full
    for (int i = 0; i < 65536 * 8; i++)
    {
        int cid = coroutine_test_alloc_cid();
        ASSERT_GT(cid, 0);
#if CID_ALLOC_PRINT
        if (i % 1000 == 0)
        {
            printf("cid=%d\n", cid);
        }
#endif
    }
    //limit
    {
        int cid = coroutine_test_alloc_cid();
        ASSERT_EQ(cid, CORO_LIMIT);
    }
    //free
    for (int i = 1; i < 65536; i++)
    {
        int cid = i * 7;
        coroutine_test_free_cid(cid);
#if CID_ALLOC_PRINT
        if (i % 1000 == 0)
        {
            printf("free cid=%d\n", cid);
        }
#endif
    }
    //alloc [2]
    for (int i = 0; i < 65536 / 2; i++)
    {
        int cid = coroutine_test_alloc_cid();
        ASSERT_GT(cid, 0);
#if CID_ALLOC_PRINT
        if (i % 1000 == 0)
        {
            printf("cid=%d\n", cid);
        }
#endif
    }
}
<commit_msg>fix core_test errors<commit_after>#include "tests.h"

using namespace swoole;

static void coro1(void *arg)
{
    int cid = coroutine_get_current_cid();
    coroutine_t *co = coroutine_get_by_id(cid);
    coroutine_yield(co);
}

TEST(coroutine, create)
{
    int cid = coroutine_create(coro1, NULL);
    ASSERT_GT(cid, 0);
    coroutine_resume(coroutine_get_by_id(cid));
}

static void coro2(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9801, 0.5);
    ASSERT_EQ(retval, false);
    ASSERT_EQ(sock.errCode, ECONNREFUSED);
}

TEST(coroutine, socket_connect_refused)
{
    int cid = coroutine_create(coro2, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro3(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    sock.setTimeout(0.5);
    bool retval = sock.connect("192.0.0.1", 9801);
    ASSERT_EQ(retval, false);
    ASSERT_EQ(sock.errCode, ETIMEDOUT);
}

TEST(coroutine, socket_connect_timeout)
{
    int cid = coroutine_create(coro3, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro4(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("www.baidu.com", 80, 0.5);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
}

TEST(coroutine, socket_connect_with_dns)
{
    int cid = coroutine_create(coro4, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro5(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9501, -1);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
    sock.send("echo", 5);
    char buf[128];
    int n = sock.recv(buf, sizeof(buf));
    ASSERT_EQ(strcmp(buf, "hello world\n"), 0);
}

TEST(coroutine, socket_recv_success)
{
    int cid = coroutine_create(coro5, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro6(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9501, -1);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
    sock.send("close", 6);
    char buf[128];
    int n = sock.recv(buf, sizeof(buf));
    ASSERT_EQ(n, 0);
}

TEST(coroutine, socket_recv_fail)
{
    int cid = coroutine_create(coro6, NULL);
    if (cid < 0)
    {
        return;
    }
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

TEST(coroutine, socket_bind_success)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("127.0.0.1", 9909);
    ASSERT_EQ(retval, true);
}

TEST(coroutine, socket_bind_fail)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("192.111.11.1", 9909);
    ASSERT_EQ(retval, false);
    ASSERT_EQ(sock.errCode, EADDRNOTAVAIL);
}

TEST(coroutine, socket_listen)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("127.0.0.1", 9909);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.listen(128), true);
}

/**
 * Accept
 */
static void coro7(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.bind("127.0.0.1", 9909);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.listen(128), true);

    Socket *conn = sock.accept();
    ASSERT_NE(conn, nullptr);
}

/**
 * Connect
 */
static void coro8(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    bool retval = sock.connect("127.0.0.1", 9909, -1);
    ASSERT_EQ(retval, true);
    ASSERT_EQ(sock.errCode, 0);
}

TEST(coroutine, socket_accept)
{
    coroutine_create(coro7, NULL);
    coroutine_create(coro8, NULL);
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

static void coro9(void *arg)
{
    Socket sock(SW_SOCK_TCP);
    auto retval = sock.resolve("www.qq.com");
    ASSERT_EQ(retval, "180.163.26.39");
}

TEST(coroutine, socket_resolve)
{
    coroutine_create(coro9, NULL);
    SwooleG.main_reactor->wait(SwooleG.main_reactor, nullptr);
}

#define CID_ALLOC_PRINT  0

TEST(coroutine, cid_alloc)
{
    //alloc [1] full
    for (int i = 0; i < 65536 * 8; i++)
    {
        int cid = coroutine_test_alloc_cid();
        ASSERT_GT(cid, 0);
#if CID_ALLOC_PRINT
        if (i % 1000 == 0)
        {
            printf("cid=%d\n", cid);
        }
#endif
    }
    //limit
    {
        int cid = coroutine_test_alloc_cid();
        ASSERT_EQ(cid, CORO_LIMIT);
    }
    //free
    for (int i = 1; i < 65536; i++)
    {
        int cid = i * 7;
        coroutine_test_free_cid(cid);
#if CID_ALLOC_PRINT
        if (i % 1000 == 0)
        {
            printf("free cid=%d\n", cid);
        }
#endif
    }
    //alloc [2]
    for (int i = 0; i < 65536 / 2; i++)
    {
        int cid = coroutine_test_alloc_cid();
        ASSERT_GT(cid, 0);
#if CID_ALLOC_PRINT
        if (i % 1000 == 0)
        {
            printf("cid=%d\n", cid);
        }
#endif
    }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include "sqlite_datasource.hpp"
#include "sqlite_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>

using std::clog;
using std::endl;

using boost::lexical_cast;
using boost::bad_lexical_cast;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(sqlite_datasource)

using mapnik::Envelope;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;

sqlite_datasource::sqlite_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     extent_initialized_(false),
     type_(datasource::Vector),
     table_(*params.get<std::string>("table","")),
     metadata_(*params.get<std::string>("metadata","")),
     geometry_field_(*params.get<std::string>("geometry_field","geom")),
     key_field_(*params.get<std::string>("key_field","PK_UID")),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8"))
{
    boost::optional<std::string> file = params.get<std::string>("file");
    if (!file) throw datasource_exception("missing <file> paramater");

    multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);
    use_spatial_index_ = *params_.get<mapnik::boolean>("use_spatial_index",true);

    dataset_ = new sqlite_connection (*file);

    boost::optional<std::string> ext  = params_.get<std::string>("extent");
    if (ext)
    {
        boost::char_separator<char> sep(",");
        boost::tokenizer<boost::char_separator<char> > tok(*ext,sep);
        unsigned i = 0;
        bool success = false;
        double d[4];
        for (boost::tokenizer<boost::char_separator<char> >::iterator beg=tok.begin();
             beg!=tok.end();++beg)
        {
            try
            {
                d[i] = boost::lexical_cast<double>(*beg);
            }
            catch (boost::bad_lexical_cast & ex)
            {
                std::clog << ex.what() << "\n";
                break;
            }
            if (i==3)
            {
                success = true;
                break;
            }
            ++i;
        }

        if (success)
        {
            extent_.init(d[0],d[1],d[2],d[3]);
            extent_initialized_ = true;
        }
    }

    if (metadata_ != "" && ! extent_initialized_)
    {
        std::ostringstream s;
        s << "select xmin, ymin, xmax, ymax from " << metadata_;
        s << " where lower(f_table_name) = lower('" << table_ << "')";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            double xmin = rs->column_double (0);
            double ymin = rs->column_double (1);
            double xmax = rs->column_double (2);
            double ymax = rs->column_double (3);

            extent_.init (xmin,ymin,xmax,ymax);
            extent_initialized_ = true;
        }
    }

    if (use_spatial_index_)
    {
        std::ostringstream s;
        s << "select count (*) sqlite_master";
        s << " where name = 'idx_" << table_ << "_" << geometry_field_ << "'";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            if (rs->column_integer (0) == 0)
            {
#ifdef MAPNIK_DEBUG
                clog << "cannot use the spatial index " << endl;
#endif
                use_spatial_index_ = false;
            }
        }
    }

    {
        /*
            XXX - This is problematic, if we don't have at least a row,
                  we cannot determine the right columns types and names
                  as all column_type are SQLITE_NULL
        */
        std::ostringstream s;
        s << "select * from " << table_ << " limit 1";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            for (int i = 0; i < rs->column_count (); ++i)
            {
               const int type_oid = rs->column_type (i);
               const char* fld_name = rs->column_name (i);
               switch (type_oid)
               {
                  case SQLITE_INTEGER:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
                     break;

                  case SQLITE_FLOAT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
                     break;

                  case SQLITE_TEXT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
                     break;

                  case SQLITE_NULL:
                  case SQLITE_BLOB:
                     break;

                  default:
#ifdef MAPNIK_DEBUG
                     clog << "unknown type_oid="<<type_oid<<endl;
#endif
                     break;
                }
            }
        }
    }
}

sqlite_datasource::~sqlite_datasource()
{
    delete dataset_;
}

std::string const sqlite_datasource::name_="sqlite";

std::string sqlite_datasource::name()
{
   return name_;
}

int sqlite_datasource::type() const
{
   return type_;
}

Envelope<double> sqlite_datasource::envelope() const
{
   return extent_;
}

layer_descriptor sqlite_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr sqlite_datasource::features(query const& q) const
{
   if (dataset_)
   {
        mapnik::Envelope<double> const& e = q.get_bbox();

        std::ostringstream s;
        s << "select " << geometry_field_ << "," << key_field_;
        std::set<std::string> const& props = q.property_names();
        std::set<std::string>::const_iterator pos = props.begin();
        std::set<std::string>::const_iterator end = props.end();
        while (pos != end)
        {
           s << "," << *pos << "";
           ++pos;
        }
        s << " from " << table_;

        if (use_spatial_index_)
        {
            s << std::setprecision(16);
            s << " where rowid in (select pkid from idx_" << table_ << "_" << geometry_field_;
            s << " where xmax>=" << e.minx() << " and xmin<=" << e.maxx() ;
            s << " and ymax>=" << e.miny() << " and ymin<=" << e.maxy() << ")";
        }

#ifdef MAPNIK_DEBUG
        std::cerr << "executing sql: " << s.str() << "\n";
#endif

        boost::shared_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));

        return featureset_ptr (new sqlite_featureset(rs, desc_.get_encoding(), multiple_geometries_));
   }

   return featureset_ptr();
}

featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
{
#if 0
   if (dataset_ && layer_)
   {
        OGRPoint point;
        point.setX (pt.x);
        point.setY (pt.y);

        layer_->SetSpatialFilter (&point);

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
#endif

   return featureset_ptr();
}

<commit_msg>+ corrected SQL  <commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include "sqlite_datasource.hpp"
#include "sqlite_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>

using std::clog;
using std::endl;

using boost::lexical_cast;
using boost::bad_lexical_cast;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(sqlite_datasource)

using mapnik::Envelope;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;

sqlite_datasource::sqlite_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     extent_initialized_(false),
     type_(datasource::Vector),
     table_(*params.get<std::string>("table","")),
     metadata_(*params.get<std::string>("metadata","")),
     geometry_field_(*params.get<std::string>("geometry_field","geom")),
     key_field_(*params.get<std::string>("key_field","PK_UID")),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8"))
{
    boost::optional<std::string> file = params.get<std::string>("file");
    if (!file) throw datasource_exception("missing <file> paramater");

    multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);
    use_spatial_index_ = *params_.get<mapnik::boolean>("use_spatial_index",true);

    dataset_ = new sqlite_connection (*file);

    boost::optional<std::string> ext  = params_.get<std::string>("extent");
    if (ext)
    {
        boost::char_separator<char> sep(",");
        boost::tokenizer<boost::char_separator<char> > tok(*ext,sep);
        unsigned i = 0;
        bool success = false;
        double d[4];
        for (boost::tokenizer<boost::char_separator<char> >::iterator beg=tok.begin();
             beg!=tok.end();++beg)
        {
            try
            {
                d[i] = boost::lexical_cast<double>(*beg);
            }
            catch (boost::bad_lexical_cast & ex)
            {
                std::clog << ex.what() << "\n";
                break;
            }
            if (i==3)
            {
                success = true;
                break;
            }
            ++i;
        }

        if (success)
        {
            extent_.init(d[0],d[1],d[2],d[3]);
            extent_initialized_ = true;
        }
    }

    if (metadata_ != "" && ! extent_initialized_)
    {
        std::ostringstream s;
        s << "select xmin, ymin, xmax, ymax from " << metadata_;
        s << " where lower(f_table_name) = lower('" << table_ << "')";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            double xmin = rs->column_double (0);
            double ymin = rs->column_double (1);
            double xmax = rs->column_double (2);
            double ymax = rs->column_double (3);

            extent_.init (xmin,ymin,xmax,ymax);
            extent_initialized_ = true;
        }
    }

    if (use_spatial_index_)
    {
        std::ostringstream s;
        s << "select count (*) from sqlite_master";
        s << " where name = 'idx_" << table_ << "_" << geometry_field_ << "'";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            if (rs->column_integer (0) == 0)
            {
#ifdef MAPNIK_DEBUG
                clog << "cannot use the spatial index " << endl;
#endif
                use_spatial_index_ = false;
            }
        }
    }

    {
        /*
            XXX - This is problematic, if we don't have at least a row,
                  we cannot determine the right columns types and names
                  as all column_type are SQLITE_NULL
        */
        std::ostringstream s;
        s << "select * from " << table_ << " limit 1";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            for (int i = 0; i < rs->column_count (); ++i)
            {
               const int type_oid = rs->column_type (i);
               const char* fld_name = rs->column_name (i);
               switch (type_oid)
               {
                  case SQLITE_INTEGER:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
                     break;

                  case SQLITE_FLOAT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
                     break;

                  case SQLITE_TEXT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
                     break;

                  case SQLITE_NULL:
                  case SQLITE_BLOB:
                     break;

                  default:
#ifdef MAPNIK_DEBUG
                     clog << "unknown type_oid="<<type_oid<<endl;
#endif
                     break;
                }
            }
        }
    }
}

sqlite_datasource::~sqlite_datasource()
{
    delete dataset_;
}

std::string const sqlite_datasource::name_="sqlite";

std::string sqlite_datasource::name()
{
   return name_;
}

int sqlite_datasource::type() const
{
   return type_;
}

Envelope<double> sqlite_datasource::envelope() const
{
   return extent_;
}

layer_descriptor sqlite_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr sqlite_datasource::features(query const& q) const
{
   if (dataset_)
   {
        mapnik::Envelope<double> const& e = q.get_bbox();

        std::ostringstream s;
        s << "select " << geometry_field_ << "," << key_field_;
        std::set<std::string> const& props = q.property_names();
        std::set<std::string>::const_iterator pos = props.begin();
        std::set<std::string>::const_iterator end = props.end();
        while (pos != end)
        {
           s << "," << *pos << "";
           ++pos;
        }
        s << " from " << table_;

        if (use_spatial_index_)
        {
            s << std::setprecision(16);
            s << " where rowid in (select pkid from idx_" << table_ << "_" << geometry_field_;
            s << " where xmax>=" << e.minx() << " and xmin<=" << e.maxx() ;
            s << " and ymax>=" << e.miny() << " and ymin<=" << e.maxy() << ")";
        }

#ifdef MAPNIK_DEBUG
        std::cerr << "executing sql: " << s.str() << "\n";
#endif

        boost::shared_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));

        return featureset_ptr (new sqlite_featureset(rs, desc_.get_encoding(), multiple_geometries_));
   }

   return featureset_ptr();
}

featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
{
#if 0
   if (dataset_ && layer_)
   {
        OGRPoint point;
        point.setX (pt.x);
        point.setY (pt.y);

        layer_->SetSpatialFilter (&point);

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
#endif

   return featureset_ptr();
}

<|endoftext|>