<commit_before>// Copyright (c) 2015
// Author: Chrono Law
#include <std.hpp>
using namespace std;

#include <boost/core/lightweight_test.hpp>
#include <boost/utility.hpp>
#include <boost/dynamic_bitset.hpp>
using namespace boost;

//////////////////////////////////////////
void case1()
{
    dynamic_bitset<> db1;
    dynamic_bitset<> db2(10);
    dynamic_bitset<> db3(0x16,
    BOOST_BINARY(10101));       //注意这里
    dynamic_bitset<> db4(string("0100"));
    dynamic_bitset<> db5(db3);

    dynamic_bitset<> db6;
    db6 = db4;

    cout << hex << db5.to_ulong() << endl;
    cout << db4[0] << db4[1] << db4[2] << endl;

}

//////////////////////////////////////////
void case2()
{
    dynamic_bitset<> db;

    db.resize(10, true);
    cout << db << endl;

    db.resize(5);
    cout << db << endl;

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01110));

        cout << db << endl;
        assert(db.size() == 5);

        db.clear();
        assert(db.empty()&& db.size()==0);

    }

    assert(dynamic_bitset<>(64).num_blocks()==1);
    assert(dynamic_bitset<>(65).num_blocks()==2);

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.push_back(true);
        assert(db.to_ulong() == BOOST_BINARY_UL(101001));

    }

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.append(BOOST_BINARY(101));
        assert(db.size() == sizeof(unsigned long)*8 + 5);
        cout << db << endl;             //0000000000000000000000000000010101001

    }
}

//////////////////////////////////////////
void case3()
{
    dynamic_bitset<> db1(4, BOOST_BINARY(1010));

    db1[0] &= 1;
    db1[1] ^= 1;
    cout << db1 << endl;

    dynamic_bitset<> db2(4, BOOST_BINARY(0101));
    assert(db1 > db2);

    cout << (db1 ^ db2) << endl;
    cout << (db1 | db2) << endl;

}

//////////////////////////////////////////
void case4()
{
    dynamic_bitset<> db(4, BOOST_BINARY(0101));

    assert(db.test(0) && !db.test(1));
    assert(db.any() && !db.none());
    assert(db.count() == 2);

    {
        dynamic_bitset<> db(4, BOOST_BINARY(0101));

        db.flip();
        assert(db.to_ulong() == BOOST_BINARY(1010));

        db.set();
        assert(!db.none());

        db.reset();
        assert(!db.any() );

        db.set(1, 1);
        assert(db.count() == 1);

    }

    {
        dynamic_bitset<> db(5, BOOST_BINARY(00101));

        auto pos = db.find_first();
        assert(pos == 0);

        pos = db.find_next(pos);
        assert(pos == 2);

    }
}

//////////////////////////////////////////
void case5()
{
    cout << dec;

    dynamic_bitset<> db(10, BOOST_BINARY(1010101));
    cout << db.to_ulong() << endl;      //85
    assert(db.to_ulong() == 85);

    db.append(10);
    cout << db.to_ulong() << endl;
    assert(db.to_ulong() == 10325);

    db.push_back(1);
    //BOOST_TEST_THROWS(db.to_ulong(), std::overflow_error);
    try
    {
        cout << db.to_ulong() << endl;
    }
    catch(std::overflow_error &)
    {
        cout << "can't convert to ulong."<< endl;
    }

    string str;
    to_string(db, str);
    cout << str << endl;

    dump_to_string(db , str);
    cout << str << endl;
}

//////////////////////////////////////////
void case6()
{
    dynamic_bitset<> db1(5, BOOST_BINARY(10101));
    dynamic_bitset<> db2(5, BOOST_BINARY(10010));

    cout << (db1 | db2) << endl;
    cout << (db1 & db2) << endl;
    cout << (db1 - db2) << endl;

    dynamic_bitset<> db3(5, BOOST_BINARY(101));
    assert(db3.is_proper_subset_of(db1));

    dynamic_bitset<> db4(db2);
    assert(db4.is_subset_of(db2));
    assert(!db4.is_proper_subset_of(db2));
}

//////////////////////////////////////////
void func(int n)
{
    //cout << "test " << n << endl;

    dynamic_bitset<> db(n);
    db.set();
    //cout << db.size() << endl;

    for (dynamic_bitset<>::size_type i = db.find_next(1);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i ) )
    {
        for (dynamic_bitset<>::size_type j = db.find_next(i);
                j != dynamic_bitset<>::npos ;
                j = db.find_next(j ))
        {
            if ( j % i == 0)
            {
                db[j] = 0;
            }
        }
    }

    cout << dec ;
    for (dynamic_bitset<>::size_type i = db.find_next(2);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i) )
    {
        cout << i << ", ";
    }

}

void case7()
{
    func(10);
    func(50);
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
}
<commit_msg>clean<commit_after>// Copyright (c) 2015
// Author: Chrono Law
#include <std.hpp>
using namespace std;

#include <boost/core/lightweight_test.hpp>
#include <boost/utility.hpp>
#include <boost/dynamic_bitset.hpp>
using namespace boost;

//////////////////////////////////////////
void case1()
{
    dynamic_bitset<> db1;
    dynamic_bitset<> db2(10);
    dynamic_bitset<> db3(0x16,
    BOOST_BINARY(10101));       //注意这里
    dynamic_bitset<> db4(string("0100"));
    dynamic_bitset<> db5(db3);

    dynamic_bitset<> db6;
    db6 = db4;

    cout << hex << db5.to_ulong() << endl;
    cout << db4[0] << db4[1] << db4[2] << endl;

}

//////////////////////////////////////////
void case2()
{
    dynamic_bitset<> db;

    db.resize(10, true);
    cout << db << endl;

    db.resize(5);
    cout << db << endl;

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01110));

        cout << db << endl;
        assert(db.size() == 5);

        db.clear();
        assert(db.empty()&& db.size()==0);

    }

    assert(dynamic_bitset<>(64).num_blocks()==1);
    assert(dynamic_bitset<>(65).num_blocks()==2);

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.push_back(true);
        assert(db.to_ulong() == BOOST_BINARY_UL(101001));

    }

    {
        dynamic_bitset<> db(5,BOOST_BINARY(01001));
        db.append(BOOST_BINARY(101));
        assert(db.size() == sizeof(unsigned long)*8 + 5);
        cout << db << endl;             //0000000000000000000000000000010101001

    }
}

//////////////////////////////////////////
void case3()
{
    dynamic_bitset<> db1(4, BOOST_BINARY(1010));

    db1[0] &= 1;
    db1[1] ^= 1;
    cout << db1 << endl;

    dynamic_bitset<> db2(4, BOOST_BINARY(0101));
    assert(db1 > db2);

    cout << (db1 ^ db2) << endl;
    cout << (db1 | db2) << endl;

}

//////////////////////////////////////////
void case4()
{
    dynamic_bitset<> db(4, BOOST_BINARY(0101));

    assert(db.test(0) && !db.test(1));
    assert(db.any() && !db.none());
    assert(db.count() == 2);

    {
        dynamic_bitset<> db(4, BOOST_BINARY(0101));

        db.flip();
        assert(db.to_ulong() == BOOST_BINARY(1010));

        db.set();
        assert(!db.none());

        db.reset();
        assert(!db.any() );

        db.set(1, 1);
        assert(db.count() == 1);

    }

    {
        dynamic_bitset<> db(5, BOOST_BINARY(00101));

        auto pos = db.find_first();
        assert(pos == 0);

        pos = db.find_next(pos);
        assert(pos == 2);

    }
}

//////////////////////////////////////////
void case5()
{
    cout << dec;

    dynamic_bitset<> db(10, BOOST_BINARY(1010101));
    cout << db.to_ulong() << endl;      //85
    assert(db.to_ulong() == 85);

    db.append(10);
    cout << db.to_ulong() << endl;
    assert(db.to_ulong() == 10325);

    db.push_back(1);
    //BOOST_TEST_THROWS(db.to_ulong(), std::overflow_error);
    try
    {
        cout << db.to_ulong() << endl;
    }
    catch(std::overflow_error &)
    {
        cout << "can't convert to ulong."<< endl;
    }

    string str;
    to_string(db, str);
    cout << str << endl;

    dump_to_string(db , str);
    cout << str << endl;
}

//////////////////////////////////////////
void case6()
{
    dynamic_bitset<> db1(5, BOOST_BINARY(10101));
    dynamic_bitset<> db2(5, BOOST_BINARY(10010));

    cout << (db1 | db2) << endl;
    cout << (db1 & db2) << endl;
    cout << (db1 - db2) << endl;

    dynamic_bitset<> db3(5, BOOST_BINARY(101));
    assert(db3.is_proper_subset_of(db1));

    dynamic_bitset<> db4(db2);
    assert(db4.is_subset_of(db2));
    assert(!db4.is_proper_subset_of(db2));
}

//////////////////////////////////////////
void func(int n)
{
    //cout << "test " << n << endl;

    dynamic_bitset<> db(n);
    db.set();
    //cout << db.size() << endl;

    for (auto i = db.find_next(1);
         i != dynamic_bitset<>::npos ;
         i = db.find_next(i ) )
    {
        for (auto j = db.find_next(i);
             j != dynamic_bitset<>::npos ;
             j = db.find_next(j ))
        {
            if ( j % i == 0)
            {
                db[j] = 0;
            }
        }
    }

    cout << dec ;
    for (auto i = db.find_next(2);
            i != dynamic_bitset<>::npos ;
            i = db.find_next(i) )
    {
        cout << i << ", ";
    }

    cout << endl;
}

void case7()
{
    func(10);
    func(50);
}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
}
<|endoftext|>


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

#include <cstring>

#include <QJsonDocument>
#include <QSslSocket>
#include <QtEndian>
#include <QVariantMap>

#include "../util/json.h"
#include "transfer.h"

Transfer::Transfer(QSslConfiguration *configuration, TransferModel::Direction direction)
    : mDirection(direction)
{
    // Create a socket of the appropriate type
    if (configuration) {
        QSslSocket *socket = new QSslSocket(this);
        socket->setSslConfiguration(*configuration);

        connect(socket, &QSslSocket::encrypted, this, &Transfer::onEncrypted);
        connect(socket, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors), this, &Transfer::onSslErrors);

        mSocket = socket;
    } else {
        mSocket = new QTcpSocket(this);
    }

    connect(mSocket, &QTcpSocket::connected, this, &Transfer::onConnected);
    connect(mSocket, &QTcpSocket::readyRead, this, &Transfer::onReadyRead);
    connect(mSocket, &QTcpSocket::bytesWritten, this, &Transfer::onBytesWritten);
    connect(mSocket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this, &Transfer::onError);

    // Set all of the transfer members to proper initial values
    reset();
}

void Transfer::cancel()
{
    // Ensure that the transfer is actually in progress before trying to cancel it
    if(mState == TransferModel::Failed || mState == TransferModel::Succeeded) {
        qWarning("Cannot cancel a transfer that has completed");
        return;
    }

    // Canceling a request is considered an "error" and is treated the same way
    // Only attempt to report the error if the transfer isn't already finished
    if(mProtocolState != ProtocolState::Finished) {
        writeErrorPacket(tr("Transfer was canceled"));
    }
}

void Transfer::restart()
{
    // Ensure that the transfer is sending data and not receiving
    if(mDirection == TransferModel::Receive) {
        qWarning("Cannot restart a transfer that receives files");
        return;
    }

    // Ensure that the transfer failed
    if(mState != TransferModel::Failed) {
        qWarning("Cannot restart a transfer that has not failed");
        return;
    }

    // Reset all of the transfer variables and reconnect again
    reset();
    startConnect();
}

void Transfer::onEncrypted()
{
    mState = TransferModel::InProgress;
    emit dataChanged({TransferModel::StateRole});

    startTransfer();
}

void Transfer::onConnected()
{
    QSslSocket *socket = qobject_cast<QSslSocket*>(mSocket);
    if (socket) {
        if (mDirection == TransferModel::Send) {
            socket->startClientEncryption();
        } else {
            socket->startServerEncryption();
        }
    } else {
        startTransfer();
    }
}

void Transfer::onReadyRead()
{
    // Add all of the new data to the buffer
    mBuffer.append(mSocket->readAll());

    // Process as many packets as can be read from the buffer
    forever {

        // If the transfer is finished, ignore any packets being received
        if(mProtocolState == ProtocolState::Finished) {
            break;
        }

        // If the size of the packet is not yet known attempt to read it
        if(!mBufferSize) {

            // See if there is enough data in the buffer to read the size
            if(static_cast<size_t>(mBuffer.size()) >= sizeof(mBufferSize)) {

                // memcpy must be used in order to avoid alignment issues
                // Also, the integer uses little endian byte order
                // so convert it to the host format if necessary
                memcpy(&mBufferSize, mBuffer.constData(), sizeof(mBufferSize));
                mBufferSize = qFromLittleEndian(mBufferSize);
                mBuffer.remove(0, sizeof(mBufferSize));

                // A packet size of zero is an error
                if(!mBufferSize) {
                    writeErrorPacket(tr("Empty packet received"));
                    break;
                }

            } else {
                break;
            }
        }

        // If the buffer contains enough data to read the packet, then do so
        if(mBuffer.size() >= mBufferSize) {
            processPacket();
        } else {
            break;
        }
    }
}

void Transfer::onBytesWritten()
{
    // Wait until there is no more pending data to write
    if(!mSocket->bytesToWrite()) {

        // If the transfer finished, then report success or failure
        // Otherwise, have the child class write the next packet
        if(mProtocolState == ProtocolState::Finished) {
            finish(mError.isNull() ? TransferModel::Succeeded : TransferModel::Failed);
        } else {
            writeNextPacket();
        }
    }
}

void Transfer::onError(QAbstractSocket::SocketError)
{
    // Errors are only meaningful during the Connecting and InProgress
    if(mState == TransferModel::Connecting || mState == TransferModel::InProgress) {
        finish(TransferModel::Failed);
    }
}

void Transfer::onSslErrors(const QList<QSslError> &errors)
{
    // Errors beyond the first one are ignored
    mError = errors.at(0).errorString();
    finish(TransferModel::Failed);
}

void Transfer::writeSuccessPacket()
{
    // A success packet contains absolutely no data
    writePacket(PacketType::Success);
    mProtocolState = ProtocolState::Finished;
}

void Transfer::writeErrorPacket(const QString &message)
{
    // Send the error as a UTF-8 encoded string
    writePacket(PacketType::Error, message.toUtf8());

    // Record the error message and emit the appropriate signal
    mError = message;
    emit dataChanged({TransferModel::ErrorRole});

    // Indicate that the transfer has finished so that all future packets are ignored
    mProtocolState = ProtocolState::Finished;
}

void Transfer::writeJsonPacket(const QJsonObject &object)
{
    // Convert the JSON object to a byte array and send it
    writePacket(PacketType::Json, QJsonDocument(object).toJson(QJsonDocument::Compact));
}

void Transfer::writeBinaryPacket(const QByteArray &data)
{
    // Pass the data along unmodified
    writePacket(PacketType::Binary, data);
}

void Transfer::updateProgress()
{
    // Store the old value to avoid emiting the dataChanged signal more often than necessary
    int oldProgress = mProgress;

    // Calculate the current progress in the range 0-100,
    // being careful to avoid a division by 0 error
    if(mTransferBytesTotal) {
        double n = static_cast<double>(mTransferBytes),
               d = static_cast<double>(mTransferBytesTotal);
        mProgress = static_cast<int>((n / d) * 100.0);
    } else {
        mProgress = 0;
    }

    // Ensure that the value falls within range
    mProgress = qMin(qMax(mProgress, 0), 100);

    // Only emit a signal if the value changes
    if(mProgress != oldProgress) {
        emit dataChanged({TransferModel::ProgressRole});
    }
}

void Transfer::processPacket()
{
    // Grab the data from the front of the buffer
    const char type = mBuffer.at(0);
    QByteArray data = mBuffer.mid(1, mBufferSize - 1);
    mBuffer.remove(0, mBufferSize);
    mBufferSize = 0;

    // Process the data based on the type
    switch(static_cast<PacketType>(type)) {
    case PacketType::Success:
    {
        finish(TransferModel::Succeeded);
        break;
    }
    case PacketType::Error:
    {
        // An error occurred - grab the error message
        mError = QString::fromUtf8(data);
        emit dataChanged({TransferModel::ErrorRole});

        finish(TransferModel::Failed);
        break;
    }
    case PacketType::Json:
    {
        // Verify the JSON is valid and pass it along
        QJsonDocument document = QJsonDocument::fromJson(data);
        if(document.isObject()) {
            processJsonPacket(document.object());
        } else {
            writeErrorPacket(tr("Unable to read JSON packet"));
        }
        break;
    }
    case PacketType::Binary:
    {
        // Pass the packet along unmodified
        processBinaryPacket(data);
        break;
    }
    default:
        // Any other type of packet is an error
        writeErrorPacket(tr("Unrecognized packet received"));
    }
}

void Transfer::writePacket(PacketType type, const QByteArray &data)
{
    // Write the size of the packet including its type
    qint32 packetSize = qToLittleEndian(data.length() + 1);
    mSocket->write(reinterpret_cast<const char*>(&packetSize), sizeof(packetSize));

    // Write the packet type and the data (if provided)
    mSocket->write(reinterpret_cast<const char*>(&type), 1);
    if(data.length()) {
        mSocket->write(data);
    }
}

void Transfer::reset()
{
    // Reset all of the state variables to their initial values
    mProtocolState = ProtocolState::TransferHeader;

    mTransferBytes = 0;
    mTransferBytesTotal = 0;

    mState = TransferModel::Connecting;
    mError.clear();

    mProgress = 0;

    mBuffer.clear();
    mBufferSize = 0;

    // For simplicity, signal that all roles have changed
    emit dataChanged();
}

void Transfer::finish(TransferModel::State state)
{
    // Change the state and emit the signal indicating the change
    mState = state;
    emit dataChanged({TransferModel::StateRole});

    // Close the socket and any open file
    mSocket->abort();
    mFile.close();
}
<commit_msg>Ignore hostname mismatch errors.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 **/

#include <cstring>

#include <QJsonDocument>
#include <QSslSocket>
#include <QtEndian>
#include <QVariantMap>

#include "../util/json.h"
#include "transfer.h"

Transfer::Transfer(QSslConfiguration *configuration, TransferModel::Direction direction)
    : mDirection(direction)
{
    // Create a socket of the appropriate type
    if (configuration) {
        QSslSocket *socket = new QSslSocket(this);
        socket->setSslConfiguration(*configuration);

        connect(socket, &QSslSocket::encrypted, this, &Transfer::onEncrypted);
        connect(socket, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors), this, &Transfer::onSslErrors);

        mSocket = socket;
    } else {
        mSocket = new QTcpSocket(this);
    }

    connect(mSocket, &QTcpSocket::connected, this, &Transfer::onConnected);
    connect(mSocket, &QTcpSocket::readyRead, this, &Transfer::onReadyRead);
    connect(mSocket, &QTcpSocket::bytesWritten, this, &Transfer::onBytesWritten);
    connect(mSocket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this, &Transfer::onError);

    // Set all of the transfer members to proper initial values
    reset();
}

void Transfer::cancel()
{
    // Ensure that the transfer is actually in progress before trying to cancel it
    if(mState == TransferModel::Failed || mState == TransferModel::Succeeded) {
        qWarning("Cannot cancel a transfer that has completed");
        return;
    }

    // Canceling a request is considered an "error" and is treated the same way
    // Only attempt to report the error if the transfer isn't already finished
    if(mProtocolState != ProtocolState::Finished) {
        writeErrorPacket(tr("Transfer was canceled"));
    }
}

void Transfer::restart()
{
    // Ensure that the transfer is sending data and not receiving
    if(mDirection == TransferModel::Receive) {
        qWarning("Cannot restart a transfer that receives files");
        return;
    }

    // Ensure that the transfer failed
    if(mState != TransferModel::Failed) {
        qWarning("Cannot restart a transfer that has not failed");
        return;
    }

    // Reset all of the transfer variables and reconnect again
    reset();
    startConnect();
}

void Transfer::onEncrypted()
{
    mState = TransferModel::InProgress;
    emit dataChanged({TransferModel::StateRole});

    startTransfer();
}

void Transfer::onConnected()
{
    QSslSocket *socket = qobject_cast<QSslSocket*>(mSocket);
    if (socket) {
        if (mDirection == TransferModel::Send) {
            socket->startClientEncryption();
        } else {
            socket->startServerEncryption();
        }
    } else {
        startTransfer();
    }
}

void Transfer::onReadyRead()
{
    // Add all of the new data to the buffer
    mBuffer.append(mSocket->readAll());

    // Process as many packets as can be read from the buffer
    forever {

        // If the transfer is finished, ignore any packets being received
        if(mProtocolState == ProtocolState::Finished) {
            break;
        }

        // If the size of the packet is not yet known attempt to read it
        if(!mBufferSize) {

            // See if there is enough data in the buffer to read the size
            if(static_cast<size_t>(mBuffer.size()) >= sizeof(mBufferSize)) {

                // memcpy must be used in order to avoid alignment issues
                // Also, the integer uses little endian byte order
                // so convert it to the host format if necessary
                memcpy(&mBufferSize, mBuffer.constData(), sizeof(mBufferSize));
                mBufferSize = qFromLittleEndian(mBufferSize);
                mBuffer.remove(0, sizeof(mBufferSize));

                // A packet size of zero is an error
                if(!mBufferSize) {
                    writeErrorPacket(tr("Empty packet received"));
                    break;
                }

            } else {
                break;
            }
        }

        // If the buffer contains enough data to read the packet, then do so
        if(mBuffer.size() >= mBufferSize) {
            processPacket();
        } else {
            break;
        }
    }
}

void Transfer::onBytesWritten()
{
    // Wait until there is no more pending data to write
    if(!mSocket->bytesToWrite()) {

        // If the transfer finished, then report success or failure
        // Otherwise, have the child class write the next packet
        if(mProtocolState == ProtocolState::Finished) {
            finish(mError.isNull() ? TransferModel::Succeeded : TransferModel::Failed);
        } else {
            writeNextPacket();
        }
    }
}

void Transfer::onError(QAbstractSocket::SocketError)
{
    // Errors are only meaningful during the Connecting and InProgress
    if(mState == TransferModel::Connecting || mState == TransferModel::InProgress) {
        finish(TransferModel::Failed);
    }
}

void Transfer::onSslErrors(const QList<QSslError> &errors)
{
    // Ignore HostNameMismatch errors since certificates are automatically
    // valid if they are signed by the CA - show all other errors
    if (errors.count() == 1 && errors.at(0).error() == QSslError::HostNameMismatch) {
        qobject_cast<QSslSocket*>(mSocket)->ignoreSslErrors();
    } else {
        mError = errors.at(0).errorString();
        finish(TransferModel::Failed);
    }
}

void Transfer::writeSuccessPacket()
{
    // A success packet contains absolutely no data
    writePacket(PacketType::Success);
    mProtocolState = ProtocolState::Finished;
}

void Transfer::writeErrorPacket(const QString &message)
{
    // Send the error as a UTF-8 encoded string
    writePacket(PacketType::Error, message.toUtf8());

    // Record the error message and emit the appropriate signal
    mError = message;
    emit dataChanged({TransferModel::ErrorRole});

    // Indicate that the transfer has finished so that all future packets are ignored
    mProtocolState = ProtocolState::Finished;
}

void Transfer::writeJsonPacket(const QJsonObject &object)
{
    // Convert the JSON object to a byte array and send it
    writePacket(PacketType::Json, QJsonDocument(object).toJson(QJsonDocument::Compact));
}

void Transfer::writeBinaryPacket(const QByteArray &data)
{
    // Pass the data along unmodified
    writePacket(PacketType::Binary, data);
}

void Transfer::updateProgress()
{
    // Store the old value to avoid emiting the dataChanged signal more often than necessary
    int oldProgress = mProgress;

    // Calculate the current progress in the range 0-100,
    // being careful to avoid a division by 0 error
    if(mTransferBytesTotal) {
        double n = static_cast<double>(mTransferBytes),
               d = static_cast<double>(mTransferBytesTotal);
        mProgress = static_cast<int>((n / d) * 100.0);
    } else {
        mProgress = 0;
    }

    // Ensure that the value falls within range
    mProgress = qMin(qMax(mProgress, 0), 100);

    // Only emit a signal if the value changes
    if(mProgress != oldProgress) {
        emit dataChanged({TransferModel::ProgressRole});
    }
}

void Transfer::processPacket()
{
    // Grab the data from the front of the buffer
    const char type = mBuffer.at(0);
    QByteArray data = mBuffer.mid(1, mBufferSize - 1);
    mBuffer.remove(0, mBufferSize);
    mBufferSize = 0;

    // Process the data based on the type
    switch(static_cast<PacketType>(type)) {
    case PacketType::Success:
    {
        finish(TransferModel::Succeeded);
        break;
    }
    case PacketType::Error:
    {
        // An error occurred - grab the error message
        mError = QString::fromUtf8(data);
        emit dataChanged({TransferModel::ErrorRole});

        finish(TransferModel::Failed);
        break;
    }
    case PacketType::Json:
    {
        // Verify the JSON is valid and pass it along
        QJsonDocument document = QJsonDocument::fromJson(data);
        if(document.isObject()) {
            processJsonPacket(document.object());
        } else {
            writeErrorPacket(tr("Unable to read JSON packet"));
        }
        break;
    }
    case PacketType::Binary:
    {
        // Pass the packet along unmodified
        processBinaryPacket(data);
        break;
    }
    default:
        // Any other type of packet is an error
        writeErrorPacket(tr("Unrecognized packet received"));
    }
}

void Transfer::writePacket(PacketType type, const QByteArray &data)
{
    // Write the size of the packet including its type
    qint32 packetSize = qToLittleEndian(data.length() + 1);
    mSocket->write(reinterpret_cast<const char*>(&packetSize), sizeof(packetSize));

    // Write the packet type and the data (if provided)
    mSocket->write(reinterpret_cast<const char*>(&type), 1);
    if(data.length()) {
        mSocket->write(data);
    }
}

void Transfer::reset()
{
    // Reset all of the state variables to their initial values
    mProtocolState = ProtocolState::TransferHeader;

    mTransferBytes = 0;
    mTransferBytesTotal = 0;

    mState = TransferModel::Connecting;
    mError.clear();

    mProgress = 0;

    mBuffer.clear();
    mBufferSize = 0;

    // For simplicity, signal that all roles have changed
    emit dataChanged();
}

void Transfer::finish(TransferModel::State state)
{
    // Change the state and emit the signal indicating the change
    mState = state;
    emit dataChanged({TransferModel::StateRole});

    // Close the socket and any open file
    mSocket->abort();
    mFile.close();
}
<|endoftext|>


<commit_before>/*
 * DIPlib 3.0
 * This file contains definitions of the Fourier Transform function.
 *
 * (c)2017, Cris Luengo.
 * Based on original DIPlib code: (c)1995-2014, Delft University of Technology.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "diplib.h"
#include "diplib/transform.h"
#include "diplib/framework.h"
#include "diplib/overload.h"

#include "opencv_dxt.h"

namespace dip {

namespace {

// TPI is either scomplex or dcomplex.
template< typename TPI >
class DFTLineFilter : public Framework::SeparableLineFilter {
   public:
      DFTLineFilter(
            UnsignedArray const& outSize,
            BooleanArray const& process,
            bool inverse, bool corner, bool symmetric
      ) : inverse_( inverse ), shift_( !corner ) {
         options_.resize( outSize.size() );
         scale_ = 1.0;
         for( dip::uint ii = 0; ii < outSize.size(); ++ii ) {
            if( process[ ii ] ) {
               options_[ ii ].DFTInit( static_cast< int >( outSize[ ii ] ), inverse );
               if( inverse || symmetric ) {
                  scale_ /= static_cast< FloatType< TPI >>( outSize[ ii ] );
               }
            }
         }
         if( symmetric ) {
            scale_ = std::sqrt( scale_ );
         }
      }
      virtual void SetNumberOfThreads( dip::uint threads ) override {
         buffers_.resize( threads );
      }
      virtual void Filter( Framework::SeparableLineFilterParameters const& params ) override {
         DFTOptions< FloatType< TPI >> const& opts = options_[ params.dimension ];
         if( buffers_[ params.thread ].size() != static_cast< dip::uint >( opts.bufferSize() )) {
            buffers_[ params.thread ].resize( static_cast< dip::uint >( opts.bufferSize() ));
         }
         dip::uint length = static_cast< dip::uint >( opts.transformSize() );
         dip::uint border = params.inBuffer.border;
         DIP_ASSERT( params.inBuffer.length + 2 * border >= length );
         DIP_ASSERT( params.outBuffer.length >= length );
         TPI* in = static_cast< TPI* >( params.inBuffer.buffer ) - border;
         TPI* out = static_cast< TPI* >( params.outBuffer.buffer );
         FloatType< TPI > scale{ 1.0 };
         if( params.pass == params.nPasses - 1 ) {
            scale = scale_;
         }
         if( shift_ ) {
            if( inverse_ ) {
               ifftshift( in, length );
            } else {
               fftshift( in, length );
            }
         }
         DFT( in, out, buffers_[ params.thread ].data(), opts, scale );
         if( shift_ ) {
            if( inverse_ ) {
               ifftshift( out, length );
            } else {
               fftshift( out, length );
            }
         }
      }
      // The two functions below by Alexei: http://stackoverflow.com/a/19752002/7328782
      static void fftshift( TPI* data, dip::uint length ) {
         dip::uint jj = length / 2;
         if( length & 1 ) { // Odd-sized transform
            TPI tmp = data[ 0 ];
            for( dip::uint ii = 0; ii < jj; ++ii ) {
               data[ ii ] = data[ jj + ii + 1 ];
               data[ jj + ii + 1 ] = data[ ii + 1 ];
            }
            data[ jj ] = tmp;
         } else { // Even-sized transform
            for( dip::uint ii = 0; ii < jj; ++ii ) {
               std::swap( data[ ii ], data[ ii + jj ] );
            }
         }
      }
      static void ifftshift( TPI* data, dip::uint length ) {
         dip::uint jj = length / 2;
         if( length & 1 ) { // Odd-sized transform
            TPI tmp = data[ length - 1 ];
            for( dip::uint ii = jj; ii > 0; ) {
               --ii;
               data[ jj + ii + 1 ] = data[ ii ];
               data[ ii ] = data[ jj + ii ];
            }
            data[ jj ] = tmp;
         } else { // Even-sized transform
            for( dip::uint ii = 0; ii < jj; ++ii ) {
               std::swap( data[ ii ], data[ ii + jj ] );
            }
         }
      }

   private:
      std::vector< DFTOptions< FloatType< TPI >>> options_; // one for each dimension
      std::vector< std::vector< TPI >> buffers_; // one for each thread
      FloatType< TPI > scale_;
      bool inverse_;
      bool shift_;
};

} // namespace

void FourierTransform(
      Image const& in,
      Image& out,
      StringSet const& options,
      BooleanArray process
) {
   DIP_THROW_IF( !in.IsForged(), E::IMAGE_NOT_FORGED );
   dip::uint nDims = in.Dimensionality();
   DIP_THROW_IF( nDims < 1, E::DIMENSIONALITY_NOT_SUPPORTED );
   // Read `options` set
   bool inverse = false; // forward or inverse transform?
   bool real = false; // real-valued output?
   bool fast = false; // pad the image to a "nice" size?
   bool corner = false;
   bool symmetric = false;
   for( auto& option : options ) {
      if( option == "inverse" ) {
         inverse = true;
      } else if( option == "real" ) {
         // TODO: We should probably write code to do real -> 1/2 plane complex, and 1/2 plane complex -> real DFTs.
         // TODO: If so, we'll need to write our own loop code here, we won't be able to depend on Framework::Separable (unless we add some options there...)
         real = true;
      } else if( option == "fast" ) {
         fast = true;
      } else if( option == "corner" ) {
         corner = true;
      } else if( option == "symmetric" ) {
         symmetric = true;
      } else {
         DIP_THROW_INVALID_FLAG( option );
      }
   }
   // Handle `process` array
   if( process.empty() ) {
      process.resize( nDims, true );
   } else {
      DIP_THROW_IF( process.size() != nDims, E::ARRAY_PARAMETER_WRONG_LENGTH );
   }
   //std::cout << "process = " << process << std::endl;
   // Determine output size and create `border` array
   UnsignedArray outSize = in.Sizes();
   UnsignedArray border( nDims, 0 );
   BoundaryConditionArray bc{ BoundaryCondition::ZERO_ORDER_EXTRAPOLATE }; // Is this the least damaging boundary condition?
   if( fast ) {
      for( dip::uint ii = 0; ii < nDims; ++ii ) {
         if( process[ ii ] ) {
            dip::uint sz;
            sz = getOptimalDFTSize( outSize[ ii ] ); // Awkward: OpenCV uses int a lot. We cannot handle image sizes larger than can fit in an int (2^31-1 on most platforms)
            DIP_THROW_IF( sz < 1u, "Cannot pad image dimension to a larger \"fast\" size." );
            border[ ii ] = div_ceil( sz - outSize[ ii ], 2 );
            outSize[ ii ] = sz;
         }
      }
   } else {
      for( dip::uint ii = 0; ii < nDims; ++ii ) {
         DIP_THROW_IF( outSize[ ii ] > static_cast< dip::uint >( std::numeric_limits< int >::max() ), "Image size too large for DFT algorithm." );
      }
   }
   //std::cout << "outSize = " << outSize << std::endl;
   //std::cout << "border = " << border << std::endl;
   // Determine output data type
   DataType dtype = DataType::SuggestComplex( in.DataType() );
   // Allocate output image, so that it has the right (padded) size. If we don't do padding, then we're just doing the framework's work here
   Image const in_copy = in; // Make a copy of the header to preserve image in case in == out
   Image tmp;
   if( real ) {
      tmp.ReForge( outSize, 1, dtype );
   } else {
      out.ReForge( outSize, 1, dtype );
      tmp = out.QuickCopy();
   }
   // Do the processing
   DIP_START_STACK_TRACE
      // Get callback function
      std::unique_ptr< Framework::SeparableLineFilter > lineFilter;
      DIP_OVL_NEW_COMPLEX( lineFilter, DFTLineFilter, ( outSize, process, inverse, corner, symmetric ), dtype );
      Framework::Separable(
            in_copy,
            tmp,
            dtype,
            dtype,
            process,
            border,
            bc,
            *lineFilter,
            Framework::Separable_UseInputBuffer +   // input stride is always 1
            Framework::Separable_UseOutputBuffer +  // output stride is always 1
            Framework::Separable_DontResizeOutput + // output is potentially larger than input, if padding with zeros
            Framework::Separable_AsScalarImage      // each tensor element processed separately
      );
   DIP_END_STACK_TRACE
   // Produce real-valued output
   // TODO: OpenCV has code for a DFT that takes complex data but reads only half the array, assumes symmetry, and produces a real ouput. We should use that here.
   // TODO: We should also use the code that takes real data in.
   if( real ) {
      out.Copy( tmp.Real() );
   }
   // Set output pixel sizes
   PixelSize pixelSize = in_copy.PixelSize();
   for( dip::uint ii = 0; ii < nDims; ++ii ) {
      if( process[ ii ] ) {
         pixelSize.Scale( ii, static_cast< dfloat >( out.Size( ii )));
         pixelSize.Invert( ii );
      }
   }
   pixelSize.Resize( nDims );
   out.SetPixelSize( pixelSize );
}

dip::uint OptimalFourierTransformSize( dip::uint size ) {
   size = getOptimalDFTSize( size );
   DIP_THROW_IF( size == 0, E::SIZE_EXCEEDS_LIMIT );
   return size;
}

} // namespace dip

#ifdef DIP__ENABLE_DOCTEST
#include "doctest.h"
#include "diplib/random.h"

#ifndef M_PIl
#define M_PIl 3.1415926535897932384626433832795029L
#endif

template< typename T >
T dotest( size_t nfft, bool inverse = false ) {
   // Initialize
   DIP_ASSERT( nfft <= std::numeric_limits< int >::max() );
   DFTOptions< T > opts( static_cast< int >( nfft ), inverse );
   std::vector< std::complex< T >> buf( static_cast< size_t >( opts.bufferSize() ));
   // Create test data
   std::vector< std::complex< T >> inbuf( nfft );
   std::vector< std::complex< T >> outbuf( nfft );
   dip::Random random;
   for( size_t k = 0; k < nfft; ++k ) {
      inbuf[ k ] = std::complex< T >( static_cast< T >( random() ), static_cast< T >( random() ) ) / static_cast< T >( random.max() ) - T( 0.5 );
   }
   // Do the thing
   DFT( inbuf.data(), outbuf.data(), buf.data(), opts, T( 1 ) );
   // Check
   long double totalpower = 0;
   long double difpower = 0;
   for( size_t k0 = 0; k0 < nfft; ++k0 ) {
      std::complex< long double > acc{ 0, 0 };
      long double phinc = ( inverse ? 2.0l : -2.0l ) * ( long double )k0 * M_PIl / ( long double )nfft;
      for( size_t k1 = 0; k1 < nfft; ++k1 ) {
         acc += std::complex< long double >( inbuf[ k1 ] ) *
                std::exp( std::complex< long double >( 0, ( k1 * phinc )));
      }
      totalpower += std::norm( acc );
      difpower += std::norm( acc - std::complex< long double >( outbuf[ k0 ] ));
   }
   return ( T )std::sqrt( difpower / totalpower ); // Root mean square error
}

DOCTEST_TEST_CASE("[DIPlib] testing the DFT function") {
   // Test a few different sizes that have all different radixes.
   DOCTEST_CHECK( doctest::Approx( dotest< float >( 32 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 32 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 1024 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< float >( 1152 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 840 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< float >( 1023 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 840, true )) == 0 );
}

#endif // DIP__ENABLE_DOCTEST
<commit_msg>Fix to the Fourier transform: shifts were not applied correctly.<commit_after>/*
 * DIPlib 3.0
 * This file contains definitions of the Fourier Transform function.
 *
 * (c)2017, Cris Luengo.
 * Based on original DIPlib code: (c)1995-2014, Delft University of Technology.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "diplib.h"
#include "diplib/transform.h"
#include "diplib/framework.h"
#include "diplib/overload.h"

#include "opencv_dxt.h"

namespace dip {

namespace {

// TPI is either scomplex or dcomplex.
template< typename TPI >
class DFTLineFilter : public Framework::SeparableLineFilter {
   public:
      DFTLineFilter(
            UnsignedArray const& outSize,
            BooleanArray const& process,
            bool inverse, bool corner, bool symmetric
      ) : inverse_( inverse ), shift_( !corner ) {
         options_.resize( outSize.size() );
         scale_ = 1.0;
         for( dip::uint ii = 0; ii < outSize.size(); ++ii ) {
            if( process[ ii ] ) {
               options_[ ii ].DFTInit( static_cast< int >( outSize[ ii ] ), inverse );
               if( inverse || symmetric ) {
                  scale_ /= static_cast< FloatType< TPI >>( outSize[ ii ] );
               }
            }
         }
         if( symmetric ) {
            scale_ = std::sqrt( scale_ );
         }
      }
      virtual void SetNumberOfThreads( dip::uint threads ) override {
         buffers_.resize( threads );
      }
      virtual void Filter( Framework::SeparableLineFilterParameters const& params ) override {
         DFTOptions< FloatType< TPI >> const& opts = options_[ params.dimension ];
         if( buffers_[ params.thread ].size() != static_cast< dip::uint >( opts.bufferSize() )) {
            buffers_[ params.thread ].resize( static_cast< dip::uint >( opts.bufferSize() ));
         }
         dip::uint length = static_cast< dip::uint >( opts.transformSize() );
         dip::uint border = params.inBuffer.border;
         DIP_ASSERT( params.inBuffer.length + 2 * border >= length );
         DIP_ASSERT( params.outBuffer.length >= length );
         TPI* in = static_cast< TPI* >( params.inBuffer.buffer ) - border;
         TPI* out = static_cast< TPI* >( params.outBuffer.buffer );
         FloatType< TPI > scale{ 1.0 };
         if( params.pass == params.nPasses - 1 ) {
            scale = scale_;
         }
         if( shift_ ) {
            ShiftCenterToCorner( in, length );
         }
         DFT( in, out, buffers_[ params.thread ].data(), opts, scale );
         if( shift_ ) {
            ShiftCornerToCenter( out, length );
         }
      }
      // The two functions below by Alexei: http://stackoverflow.com/a/19752002/7328782
      static void ShiftCornerToCenter( TPI* data, dip::uint length ) { // fftshift
         dip::uint jj = length / 2;
         if( length & 1 ) { // Odd-sized transform
            TPI tmp = data[ 0 ];
            for( dip::uint ii = 0; ii < jj; ++ii ) {
               data[ ii ] = data[ jj + ii + 1 ];
               data[ jj + ii + 1 ] = data[ ii + 1 ];
            }
            data[ jj ] = tmp;
         } else { // Even-sized transform
            for( dip::uint ii = 0; ii < jj; ++ii ) {
               std::swap( data[ ii ], data[ ii + jj ] );
            }
         }
      }
      static void ShiftCenterToCorner( TPI* data, dip::uint length ) { // ifftshift
         dip::uint jj = length / 2;
         if( length & 1 ) { // Odd-sized transform
            TPI tmp = data[ length - 1 ];
            for( dip::uint ii = jj; ii > 0; ) {
               --ii;
               data[ jj + ii + 1 ] = data[ ii ];
               data[ ii ] = data[ jj + ii ];
            }
            data[ jj ] = tmp;
         } else { // Even-sized transform
            for( dip::uint ii = 0; ii < jj; ++ii ) {
               std::swap( data[ ii ], data[ ii + jj ] );
            }
         }
      }

   private:
      std::vector< DFTOptions< FloatType< TPI >>> options_; // one for each dimension
      std::vector< std::vector< TPI >> buffers_; // one for each thread
      FloatType< TPI > scale_;
      bool inverse_;
      bool shift_;
};

} // namespace

void FourierTransform(
      Image const& in,
      Image& out,
      StringSet const& options,
      BooleanArray process
) {
   DIP_THROW_IF( !in.IsForged(), E::IMAGE_NOT_FORGED );
   dip::uint nDims = in.Dimensionality();
   DIP_THROW_IF( nDims < 1, E::DIMENSIONALITY_NOT_SUPPORTED );
   // Read `options` set
   bool inverse = false; // forward or inverse transform?
   bool real = false; // real-valued output?
   bool fast = false; // pad the image to a "nice" size?
   bool corner = false;
   bool symmetric = false;
   for( auto& option : options ) {
      if( option == "inverse" ) {
         inverse = true;
      } else if( option == "real" ) {
         // TODO: We should probably write code to do real -> 1/2 plane complex, and 1/2 plane complex -> real DFTs.
         // TODO: If so, we'll need to write our own loop code here, we won't be able to depend on Framework::Separable (unless we add some options there...)
         real = true;
      } else if( option == "fast" ) {
         fast = true;
      } else if( option == "corner" ) {
         corner = true;
      } else if( option == "symmetric" ) {
         symmetric = true;
      } else {
         DIP_THROW_INVALID_FLAG( option );
      }
   }
   // Handle `process` array
   if( process.empty() ) {
      process.resize( nDims, true );
   } else {
      DIP_THROW_IF( process.size() != nDims, E::ARRAY_PARAMETER_WRONG_LENGTH );
   }
   //std::cout << "process = " << process << std::endl;
   // Determine output size and create `border` array
   UnsignedArray outSize = in.Sizes();
   UnsignedArray border( nDims, 0 );
   BoundaryConditionArray bc{ BoundaryCondition::ZERO_ORDER_EXTRAPOLATE }; // Is this the least damaging boundary condition?
   if( fast ) {
      for( dip::uint ii = 0; ii < nDims; ++ii ) {
         if( process[ ii ] ) {
            dip::uint sz;
            sz = getOptimalDFTSize( outSize[ ii ] ); // Awkward: OpenCV uses int a lot. We cannot handle image sizes larger than can fit in an int (2^31-1 on most platforms)
            DIP_THROW_IF( sz < 1u, "Cannot pad image dimension to a larger \"fast\" size." );
            border[ ii ] = div_ceil( sz - outSize[ ii ], 2 );
            outSize[ ii ] = sz;
         }
      }
   } else {
      for( dip::uint ii = 0; ii < nDims; ++ii ) {
         DIP_THROW_IF( outSize[ ii ] > static_cast< dip::uint >( std::numeric_limits< int >::max() ), "Image size too large for DFT algorithm." );
      }
   }
   //std::cout << "outSize = " << outSize << std::endl;
   //std::cout << "border = " << border << std::endl;
   // Determine output data type
   DataType dtype = DataType::SuggestComplex( in.DataType() );
   // Allocate output image, so that it has the right (padded) size. If we don't do padding, then we're just doing the framework's work here
   Image const in_copy = in; // Make a copy of the header to preserve image in case in == out
   Image tmp;
   if( real ) {
      tmp.ReForge( outSize, 1, dtype );
   } else {
      out.ReForge( outSize, 1, dtype );
      tmp = out.QuickCopy();
   }
   // Do the processing
   DIP_START_STACK_TRACE
      // Get callback function
      std::unique_ptr< Framework::SeparableLineFilter > lineFilter;
      DIP_OVL_NEW_COMPLEX( lineFilter, DFTLineFilter, ( outSize, process, inverse, corner, symmetric ), dtype );
      Framework::Separable(
            in_copy,
            tmp,
            dtype,
            dtype,
            process,
            border,
            bc,
            *lineFilter,
            Framework::Separable_UseInputBuffer +   // input stride is always 1
            Framework::Separable_UseOutputBuffer +  // output stride is always 1
            Framework::Separable_DontResizeOutput + // output is potentially larger than input, if padding with zeros
            Framework::Separable_AsScalarImage      // each tensor element processed separately
      );
   DIP_END_STACK_TRACE
   // Produce real-valued output
   // TODO: OpenCV has code for a DFT that takes complex data but reads only half the array, assumes symmetry, and produces a real ouput. We should use that here.
   // TODO: We should also use the code that takes real data in.
   if( real ) {
      out.Copy( tmp.Real() );
   }
   // Set output pixel sizes
   PixelSize pixelSize = in_copy.PixelSize();
   for( dip::uint ii = 0; ii < nDims; ++ii ) {
      if( process[ ii ] ) {
         pixelSize.Scale( ii, static_cast< dfloat >( out.Size( ii )));
         pixelSize.Invert( ii );
      }
   }
   pixelSize.Resize( nDims );
   out.SetPixelSize( pixelSize );
}

dip::uint OptimalFourierTransformSize( dip::uint size ) {
   size = getOptimalDFTSize( size );
   DIP_THROW_IF( size == 0, E::SIZE_EXCEEDS_LIMIT );
   return size;
}

} // namespace dip

#ifdef DIP__ENABLE_DOCTEST
#include "doctest.h"
#include "diplib/random.h"

#ifndef M_PIl
#define M_PIl 3.1415926535897932384626433832795029L
#endif

template< typename T >
T dotest( size_t nfft, bool inverse = false ) {
   // Initialize
   DIP_ASSERT( nfft <= std::numeric_limits< int >::max() );
   DFTOptions< T > opts( static_cast< int >( nfft ), inverse );
   std::vector< std::complex< T >> buf( static_cast< size_t >( opts.bufferSize() ));
   // Create test data
   std::vector< std::complex< T >> inbuf( nfft );
   std::vector< std::complex< T >> outbuf( nfft );
   dip::Random random;
   for( size_t k = 0; k < nfft; ++k ) {
      inbuf[ k ] = std::complex< T >( static_cast< T >( random() ), static_cast< T >( random() ) ) / static_cast< T >( random.max() ) - T( 0.5 );
   }
   // Do the thing
   DFT( inbuf.data(), outbuf.data(), buf.data(), opts, T( 1 ) );
   // Check
   long double totalpower = 0;
   long double difpower = 0;
   for( size_t k0 = 0; k0 < nfft; ++k0 ) {
      std::complex< long double > acc{ 0, 0 };
      long double phinc = ( inverse ? 2.0l : -2.0l ) * ( long double )k0 * M_PIl / ( long double )nfft;
      for( size_t k1 = 0; k1 < nfft; ++k1 ) {
         acc += std::complex< long double >( inbuf[ k1 ] ) *
                std::exp( std::complex< long double >( 0, ( k1 * phinc )));
      }
      totalpower += std::norm( acc );
      difpower += std::norm( acc - std::complex< long double >( outbuf[ k0 ] ));
   }
   return ( T )std::sqrt( difpower / totalpower ); // Root mean square error
}

DOCTEST_TEST_CASE("[DIPlib] testing the DFT function") {
   // Test a few different sizes that have all different radixes.
   DOCTEST_CHECK( doctest::Approx( dotest< float >( 32 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 32 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 1024 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< float >( 1152 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 840 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< float >( 1023 )) == 0 );
   DOCTEST_CHECK( doctest::Approx( dotest< double >( 840, true )) == 0 );
}

#endif // DIP__ENABLE_DOCTEST
<|endoftext|>


<commit_before>#include <QString>
#include <QtTest>
#include <QCoreApplication>
#include <QMap>
#include <algorithm>
#include <utility>
#include <map>
#include <unordered_map>
#include "qfasthash_p.h"
#include <stdint.h>
#include <boost/unordered_map.hpp>
typedef double tTestKey;
typedef double tTestValue;
//typedef  std::pair<int,int> tVecData;
struct tVecData
{
    tVecData(tTestKey f,tTestValue s)
        :first(f)
        ,second(s)
    {}
    tVecData()
        :first(0)
        ,second(0)
    {}
    bool operator<( const tVecData &t2) const
    {
        return first < t2.first;
    }
    tTestKey first;
    tTestValue second;
};

class Map_hast_Test : public QObject
{
    Q_OBJECT

public:
    Map_hast_Test();

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    void testCase_insert_data();
    void testCase_insert();
    void testCase_find();
    void testCase_find_data();

};

Map_hast_Test::Map_hast_Test()
{
}

void Map_hast_Test::initTestCase()
{

}

void Map_hast_Test::cleanupTestCase()
{
}
static int testcounts[] = {5,7,10,12,15,17,20,25,29,34,41,47, 50,75,80,90,100};//,1000,10000,100000,1000000};

void Map_hast_Test::testCase_insert_data()
{
    QTest::addColumn<QString>("testcontainer");
    QTest::addColumn<int>("testcount");
    QString testContainer;
    static const char * tests[] = {
      "QMap_insert",
        "QHash_insert",
        "stdmap_insert",
        "stdunordered_insert",
        "qfasthash_insert",
        "boostunordered_insert"
     };

    for (unsigned int t = 0; t < sizeof(tests)/sizeof(tests[0]);++t)
    {
        for(int count : testcounts)
        {

            QString text;
            text += QLatin1String(tests[t]);
            text = text.leftJustified(20, ' ', true);
            text +=  QLatin1String(" -- ");
            text += QString::number(count).leftJustified(12, ' ');

            QTest::newRow(text.toLatin1().constData()) << QString(tests[t]) << count;
        }

    }
}
void Map_hast_Test::testCase_find_data()
{
    QTest::addColumn<QString>("testcontainer");
    QTest::addColumn<int>("testcount");
    QString testContainer;
    static const char * tests[] = {
      "QMap_find",
        "QMap_constFind",
        "QHash_find",
        "QHash_constFind",
        "QVector_lowerbound",
        "stdmap_find",
        "stdunordered_find",
        "qfasthash_find",
        "boostunordered_find"
     };

     for (unsigned int t = 0; t < sizeof(tests)/sizeof(tests[0]);++t)
     {

        for(int count : testcounts)
        {
            QString text;
            text += QLatin1String(tests[t]);
            text = text.leftJustified(20, ' ', true);
            text +=  QLatin1String(" -- ");
            text += QString::number(count).leftJustified(12, ' ');

            QTest::newRow(text.toLatin1().constData()) << QString(tests[t]) << count;
        }

    }
}

inline void insertdata(QMap<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m.insert(i,i);
    }

}
inline void insertdata(QHash<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m.insert(i,i);
    }

}
inline void insertdata(std::map<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

inline void insertdata(std::unordered_map <tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

inline void insertdata(boost::unordered_map <tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

inline void insertdata(QFastHash<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

void Map_hast_Test::testCase_insert()
{
    QFETCH(QString,testcontainer);
    QFETCH(int,testcount);

    if(testcontainer == QLatin1String("QMap_insert"))
    {
        QMap<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(*it != testcount) QFAIL( "fail");
    }
    else if (testcontainer == QLatin1String("QHash_insert"))
    {
        QHash<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(*it != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("stdmap_insert"))
    {
        std::map<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(it->first != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("stdunordered_insert"))
    {
        std::unordered_map<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(it->first != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("boostunordered_insert"))
    {
        boost::unordered_map<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(it->first != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("qfasthash_insert"))
    {
        QFastHash<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.constFind(testcount);
        if(it != testcount) QFAIL( "fail");

    }
}

void Map_hast_Test::testCase_find()
{
    QFETCH(QString,testcontainer);
    QFETCH(int,testcount);
    if(testcontainer == QLatin1String("QMap_find"))
    {
        QMap<tTestKey,tTestValue> m_mapTest;
        insertdata(m_mapTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_mapTest.find(i);
                if(*it != i) QFAIL( "fail");
            }
        }
    }
    else if (testcontainer == QLatin1String("QMap_constFind"))
    {
        QMap<tTestKey,tTestValue> m_mapTest;
        insertdata(m_mapTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_mapTest.constFind(i);
                if(*it != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("QHash_find"))
    {
        QHash<tTestKey,tTestValue> m_hashTest;
        insertdata(m_hashTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_hashTest.find(i);
                if(*it != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("QHash_constFind"))
    {
        QHash<tTestKey,tTestValue> m_hashTest;
        insertdata(m_hashTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_hashTest.constFind(i);
                if(*it != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("QVector_lowerbound"))
    {
       QVector<tVecData> m_vecTest;
        for(int i = 1 ;i<= testcount ;++i)
        {
            m_vecTest.push_back(tVecData(i,i));
        }
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = std::lower_bound(std::begin(m_vecTest),std::end(m_vecTest),tVecData(i,0));
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("stdmap_find"))
    {
        std::map<tTestKey,tTestValue> m_stdmapTest;
        insertdata(m_stdmapTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_stdmapTest.find(i);
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("stdunordered_find"))
    {
        std::unordered_map <tTestKey,tTestValue> m_stdunorderedTest;
        insertdata(m_stdunorderedTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_stdunorderedTest.find(i);
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("boostunordered_find"))
    {
        boost::unordered_map <tTestKey,tTestValue> m_stdunorderedTest;
        insertdata(m_stdunorderedTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_stdunorderedTest.find(i);
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("qfasthash_find"))
    {
        QFastHash<tTestKey,tTestValue> m_fasthash_Test;
        insertdata(m_fasthash_Test,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_fasthash_Test.constFind(i);
                if(it != i) QFAIL( "fail");
            }
        }

    }
    else
    {
        QFAIL( "fail, unknown test ");
    }

}

QTEST_MAIN(Map_hast_Test)

#include "tst_map_hast_test.moc"
<commit_msg>add stdvector test<commit_after>#include <QString>
#include <QtTest>
#include <QCoreApplication>
#include <QMap>
#include <algorithm>
#include <utility>
#include <map>
#include <unordered_map>
#include "qfasthash_p.h"
#include <stdint.h>
#include <boost/unordered_map.hpp>
typedef double tTestKey;
typedef double tTestValue;
//typedef  std::pair<int,int> tVecData;
struct tVecData
{
    tVecData(tTestKey f,tTestValue s)
        :first(f)
        ,second(s)
    {}
    tVecData()
        :first(0)
        ,second(0)
    {}
    bool operator<( const tVecData &t2) const
    {
        return first < t2.first;
    }
    tTestKey first;
    tTestValue second;
};

class Map_hast_Test : public QObject
{
    Q_OBJECT

public:
    Map_hast_Test();

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    void testCase_insert_data();
    void testCase_insert();
    void testCase_find();
    void testCase_find_data();

};

Map_hast_Test::Map_hast_Test()
{
}

void Map_hast_Test::initTestCase()
{

}

void Map_hast_Test::cleanupTestCase()
{
}
static int testcounts[] = {5,7,10,12,15,17,20,25,29,34,41,47, 50,75,80,90,100};//,1000,10000,100000,1000000};

void Map_hast_Test::testCase_insert_data()
{
    QTest::addColumn<QString>("testcontainer");
    QTest::addColumn<int>("testcount");
    QString testContainer;
    static const char * tests[] = {
      "QMap_insert",
        "QHash_insert",
        "stdmap_insert",
        "stdunordered_insert",
        "qfasthash_insert",
        "boostunordered_insert"
     };

    for (unsigned int t = 0; t < sizeof(tests)/sizeof(tests[0]);++t)
    {
        for(int count : testcounts)
        {

            QString text;
            text += QLatin1String(tests[t]);
            text = text.leftJustified(20, ' ', true);
            text +=  QLatin1String(" -- ");
            text += QString::number(count).leftJustified(12, ' ');

            QTest::newRow(text.toLatin1().constData()) << QString(tests[t]) << count;
        }

    }
}
void Map_hast_Test::testCase_find_data()
{
    QTest::addColumn<QString>("testcontainer");
    QTest::addColumn<int>("testcount");
    QString testContainer;
    static const char * tests[] = {
      "QMap_find",
        "QMap_constFind",
        "QHash_find",
        "QHash_constFind",
        "QVector_lowerbound",
        "stdvector_lowerbound",
        "stdmap_find",
        "stdunordered_find",
        "qfasthash_find",
        "boostunordered_find"
     };

     for (unsigned int t = 0; t < sizeof(tests)/sizeof(tests[0]);++t)
     {

        for(int count : testcounts)
        {
            QString text;
            text += QLatin1String(tests[t]);
            text = text.leftJustified(20, ' ', true);
            text +=  QLatin1String(" -- ");
            text += QString::number(count).leftJustified(12, ' ');

            QTest::newRow(text.toLatin1().constData()) << QString(tests[t]) << count;
        }

    }
}

inline void insertdata(QMap<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m.insert(i,i);
    }

}
inline void insertdata(QHash<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m.insert(i,i);
    }

}
inline void insertdata(std::map<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

inline void insertdata(std::unordered_map <tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

inline void insertdata(boost::unordered_map <tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

inline void insertdata(QFastHash<tTestKey,tTestValue> & m,int testcount)
{
    for(int i = testcount ;i> 0 ;--i)
    {
        m[i]=i;
    }
}

void Map_hast_Test::testCase_insert()
{
    QFETCH(QString,testcontainer);
    QFETCH(int,testcount);

    if(testcontainer == QLatin1String("QMap_insert"))
    {
        QMap<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(*it != testcount) QFAIL( "fail");
    }
    else if (testcontainer == QLatin1String("QHash_insert"))
    {
        QHash<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(*it != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("stdmap_insert"))
    {
        std::map<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(it->first != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("stdunordered_insert"))
    {
        std::unordered_map<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(it->first != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("boostunordered_insert"))
    {
        boost::unordered_map<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.find(testcount);
        if(it->first != testcount) QFAIL( "fail");

    }
    else if (testcontainer == QLatin1String("qfasthash_insert"))
    {
        QFastHash<tTestKey,tTestValue> m;

        QBENCHMARK {
            insertdata(m,testcount);
        }
        auto it = m.constFind(testcount);
        if(it != testcount) QFAIL( "fail");

    }
}

void Map_hast_Test::testCase_find()
{
    QFETCH(QString,testcontainer);
    QFETCH(int,testcount);
    if(testcontainer == QLatin1String("QMap_find"))
    {
        QMap<tTestKey,tTestValue> m_mapTest;
        insertdata(m_mapTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_mapTest.find(i);
                if(*it != i) QFAIL( "fail");
            }
        }
    }
    else if (testcontainer == QLatin1String("QMap_constFind"))
    {
        QMap<tTestKey,tTestValue> m_mapTest;
        insertdata(m_mapTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_mapTest.constFind(i);
                if(*it != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("QHash_find"))
    {
        QHash<tTestKey,tTestValue> m_hashTest;
        insertdata(m_hashTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_hashTest.find(i);
                if(*it != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("QHash_constFind"))
    {
        QHash<tTestKey,tTestValue> m_hashTest;
        insertdata(m_hashTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_hashTest.constFind(i);
                if(*it != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("QVector_lowerbound"))
    {
       QVector<tVecData> m_vecTest;
        for(int i = 1 ;i<= testcount ;++i)
        {
            m_vecTest.push_back(tVecData(i,i));
        }
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = std::lower_bound(std::begin(m_vecTest),std::end(m_vecTest),tVecData(i,0));
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("stdvector_lowerbound"))
    {
       std::vector<tVecData> m_vecTest;
        for(int i = 1 ;i<= testcount ;++i)
        {
            m_vecTest.push_back(tVecData(i,i));
        }
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = std::lower_bound(std::begin(m_vecTest),std::end(m_vecTest),tVecData(i,0));
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("stdmap_find"))
    {
        std::map<tTestKey,tTestValue> m_stdmapTest;
        insertdata(m_stdmapTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_stdmapTest.find(i);
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("stdunordered_find"))
    {
        std::unordered_map <tTestKey,tTestValue> m_stdunorderedTest;
        insertdata(m_stdunorderedTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_stdunorderedTest.find(i);
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("boostunordered_find"))
    {
        boost::unordered_map <tTestKey,tTestValue> m_stdunorderedTest;
        insertdata(m_stdunorderedTest,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_stdunorderedTest.find(i);
                if(it->first != i) QFAIL( "fail");
            }
        }

    }
    else if (testcontainer == QLatin1String("qfasthash_find"))
    {
        QFastHash<tTestKey,tTestValue> m_fasthash_Test;
        insertdata(m_fasthash_Test,testcount);
        QBENCHMARK {
            for(int i = 1 ;i <= testcount ;++i)
            {
                auto it = m_fasthash_Test.constFind(i);
                if(it != i) QFAIL( "fail");
            }
        }

    }
    else
    {
        QFAIL( "fail, unknown test ");
    }

}

QTEST_MAIN(Map_hast_Test)

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


<commit_before>
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "turtlesim/Pose.h"
#include <sstream>

using namespace std;

ros::Publisher velocity_publisher;
ros::Subscriber pose_subscriber;
turtlesim::Pose turtlesim_pose;

const double PI = 3.14159265359;

void move(double speed, double distance, bool isForward);
void rotate(double angular_speed, double angle, bool cloclwise);
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message);
//void moveGoal(turtlesim::Pose goal_pose, double distance_tolerance);

int main(int argc, char **argv)
{
    // Initiate new ROS node named "robosys_turtle"
    ros::init(argc, argv, "robosys_turtle");
    ros::NodeHandle n;
    double speed, angular_speed;
    double distance, angle;
    bool isForward, clockwise;

    velocity_publisher = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
    pose_subscriber = n.subscribe("/turtle1/pose", 10, poseCallback);
    ros::Rate loop_rate(0.5);

        for(int i = 0; i < 10; i++){

        rotate(2, 2/PI, 0);
        move(3, 10, 1);

    }

    ros::spin();

    return 0;
}
void move(double speed, double distance, bool isForward)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    if (isForward)
        vel_msg.linear.x =abs(speed);
    else
        vel_msg.linear.x =-abs(speed);
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    vel_msg.angular.z =0;

    double t0 = ros::Time::now().toSec();
    double current_distance = 0.0;
    ros::Rate loop_rate(100);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_distance = speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();

    }while(current_distance<distance);

    vel_msg.linear.x =0;
    velocity_publisher.publish(vel_msg);
}

void rotate (double angular_speed, double relative_angle, bool clockwise)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    vel_msg.linear.x =0;
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    if (clockwise)
        vel_msg.angular.z =-abs(angular_speed);
    else
         vel_msg.angular.z =abs(angular_speed);

    double t0 = ros::Time::now().toSec();
    double current_angle = 0.0;
    ros::Rate loop_rate(1000);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_angle = angular_speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();
        //cout<<(t1-t0)<<", "<<current_angle <<", "<<relative_angle<<endl;
    }while(current_angle<relative_angle);
    vel_msg.angular.z =0;
    velocity_publisher.publish(vel_msg);
}

/*
void moveGoal(turtlesim::Pose goal_pose, double distance_tolerance)
{
    //We implement a Proportional Controller. We need to go from (x,y) to (x',y'). Then, linear velocity v' = K ((x'-x)^2 + (y'-y)^2)^0.5 where K is the constant and ((x'-x)^2 + (y'-y)^2)^0.5 is the Euclidian distance. The steering angle theta = tan^-1(y'-y)/(x'-x) is the angle between these 2 points.
    geometry_msgs::Twist vel_msg;

    ros::Rate loop_rate(10);
    do{
        //linear velocity
        vel_msg.linear.x = 1.5*getDistance(turtlesim_pose.x, turtlesim_pose.y, goal_pose.x, goal_pose.y);
        vel_msg.linear.y = 0;
        vel_msg.linear.z = 0;
        //angular velocity
        vel_msg.angular.x = 0;
        vel_msg.angular.y = 0;
        vel_msg.angular.z = 4*(atan2(goal_pose.y - turtlesim_pose.y, goal_pose.x - turtlesim_pose.x)-turtlesim_pose.theta);

        velocity_publisher.publish(vel_msg);

        ros::spinOnce();
        loop_rate.sleep();

    }while(getDistance(turtlesim_pose.x, turtlesim_pose.y, goal_pose.x, goal_pose.y)>distance_tolerance);
    cout<<"end move goal"<<endl;
    vel_msg.linear.x = 0;
    vel_msg.angular.z = 0;
    velocity_publisher.publish(vel_msg);

}*/
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message)
{
    turtlesim_pose.x=pose_message->x;
    turtlesim_pose.y=pose_message->y;    turtlesim_pose.theta=pose_message->theta;
}
<commit_msg>Revert "ShunShimamura"<commit_after>
<|endoftext|>


<commit_before>#include "ml/regression_tree.h"

#include <iostream>

#include "ml/learning_rate.h"
#include "ml/utils.h"

using Eigen::Map;
using Eigen::RowVectorXd;
using Eigen::ArrayXi;

RegressionTree::RegressionTree(size_t dimensions_, LearningRate* learning_rate_)
  : dimensions(dimensions_), learning_rate(learning_rate_),
    data(ArrayXXd(1000, dimensions_)), outputs(ArrayXd(1000)), rows_read(0),
    tree(NULL) {
  if (learning_rate == NULL) {
    learning_rate = new ConstantLearningRate(0.9);
  }
}

RegressionTree::~RegressionTree() {
  delete learning_rate;
  delete tree;
}

void RegressionTree::read_data_item(double* const& features, const double& output) {
  /* Expand the data matrix. */
  if (data.rows() == rows_read) {
    data.conservativeResize(Eigen::NoChange, 2 * data.rows());
    outputs.conservativeResize(2 * outputs.size());
  }

  data.row(rows_read) = Map<RowVectorXd>(features, dimensions);
  outputs(rows_read) = output;
  rows_read++;
}

// TODO: merge the two
void RegressionTree::read_data_item(Eigen::ArrayXd& features, const double& output) {
  /* Expand the data matrix. */
  if (data.rows() == rows_read) {
    data.conservativeResize(Eigen::NoChange, 2 * data.rows());
    outputs.conservativeResize(2 * outputs.size());
  }

  // TODO: size() check?
  data.row(rows_read) = features.head(dimensions);
  outputs(rows_read) = output;
  rows_read++;
}

void RegressionTree::finalize_data() {
  data.conservativeResize(rows_read, Eigen::NoChange);
  outputs.conservativeResize(rows_read);
}

void RegressionTree::create_sorted() {
  /* First, create the sorted array, ... */
  sorted.resize(data.rows(), data.cols());
  ArrayXi tmp = ArrayXi::Constant(data.cols(), 0);
  for (size_t i = 0; i < sorted.rows(); i++) {
    sorted.row(i) = tmp;
    tmp += 1;
  }
  /* ... then sort! */
  auto begin = sorted.data();
  Comp comp(data);
  for (ArrayXXd::Index col = 0; col < data.cols(); col++) {
    comp.column = col;
    std::sort(begin, begin + sorted.rows(), comp);
    begin += sorted.rows();
  }
}

/**
 * @param[in] delta if the error does not decrease by at least @p delta, stop.
 * @param[in] q if one of the children would have at most q nodes, stop.
 */
void RegressionTree::build_tree(double delta, size_t q) {
  create_sorted();
  tree = new RealNode(0);
  tree->output = outputs.sum() / outputs.size();
  tree->error  = (outputs - tree->output).pow(2).sum();
  ArrayXi valid = ArrayXi::Zero(sorted.rows());
  int max_id = 0;
  split_node(tree, valid, max_id, valid.size(), delta, q);
}

void RegressionTree::split_node(Node* node, ArrayXi& valid, int& max_id,
                                ArrayXi::Index num_docs, double delta, size_t q) {
  double min_error   = node->error;
  size_t min_feature = dimensions;
  double min_value   = 0;
  double min_left_error  = 0;
  double min_right_error = 0;
//  ArrayXd::SegmentReturnType min_head = outputs.head(0);  // placeholder only
//  ArrayXd::SegmentReturnType min_tail = outputs.tail(0);  // placeholder only
  ArrayXd min_head, min_tail;
  size_t min_left_valids = 0;

  // TODO: to argument?
  /* Create a list of the outputs. */
  ArrayXd sorted_outputs(num_docs);

  /* Iterate through all features. */
  for (size_t f = 0; f < dimensions; f++) {
    /* The outputs sorted by the current feature. */
    for (size_t i = 0, j = 0; j < sorted_outputs.size(); i++) {
      if (valid(sorted(i, f)) == node->id) sorted_outputs(j++) = outputs(sorted(i, f));
    }

    /* Number of valids on the left side of the split. */
    size_t left_valids = 0;
    /*
     * The last value of the feature. Recorded for two reasons:
     * 1. we cannot put a cutting point between two equal-valued item;
     * 2. the check value will be halfway between the last and the current items.
     */
    double last_value = DNaN;
    /*
     * All possible split with that feature -- we cannot start at q, because we
     * have to keep track of split.
     */
    for (size_t split = 0; split <= sorted.rows() - q; split++) {
      if (valid(sorted(split, f)) != node->id) continue;  // Document not under this node

      double& curr_value = data(sorted(split, f));

      /* last_value/1: skip if feature value is the same as last item's. */
      if (double_equals(last_value, curr_value)) {
        left_valids++;  // still, it was a valid item
        continue;
      }

      size_t right_valids = num_docs - left_valids;
      if (left_valids >= q && right_valids >= q) {
        auto head = sorted_outputs.head(left_valids);
        auto tail = sorted_outputs.tail(right_valids);
        double left_error = (head - head.sum() / head.size()).pow(2).sum();
        double right_error = (tail - tail.sum() / tail.size()).pow(2).sum();
        double curr_error = left_error + right_error;
        if (curr_error < min_error) {
          min_error   = curr_error;
          min_feature = f;
          // last_value/2.
          min_value   = isnan(last_value)
                        ? curr_value - epsilon
                        : (last_value + curr_value) / 2;
          min_left_error = left_error;
          min_right_error = right_error;
          min_head = head;
          min_tail = tail;
          min_left_valids = left_valids;
        }
      }

      left_valids++;
      last_value = data(sorted(split, f), f);
    }  // for split
  }  // for features

  if (min_error + delta < node->error) {
    node->feature_no  = min_feature;
    // TODO: handle enum node type
    ((RealNode*)node)->feature_val = min_value;

    int left_id  = ++max_id;
    int right_id = ++max_id;
    ArrayXi::Index left_docs  = 0;
    ArrayXi::Index right_docs = 0;
    // TODO: sparse / set / map
    for (ArrayXXi::Index i = 0; i < valid.size(); i++) {
      if (valid(i) == node->id) {
        if (data(i, min_feature) < min_value) {
          valid(i) = left_id;
          left_docs++;
        } else {
          valid(i) = right_id;
          right_docs++;
        }
      }
    }  // for

    node->left  = new RealNode(left_id);
    node->left->output = min_head.sum() / min_head.size();
    node->left->error = min_left_error;
    node->right = new RealNode(right_id);
    node->right->output = min_tail.sum() / min_tail.size();
    node->right->error = min_right_error;

    if (left_docs >= 2 * q) {
      split_node(node->left, valid, max_id, left_docs, delta, q);
    }
    if (right_docs >= 2 * q) {
      split_node(node->right, valid, max_id, right_docs, delta, q);
    }
  }
}

std::string RegressionTree::str() const {
  std::stringstream ss;
  str_inner(ss, tree, 0);
  return ss.str();
}

void RegressionTree::str_inner(std::stringstream& ss,
                               RealNode* node, size_t level) const {
  for (size_t i = 0; i < level; i++) ss << "  ";
  ss << node->id;
  if (node->left == NULL) {
    ss << ": " << node->output << " (err: " << node->error << ")" << std::endl;
  } else {
    ss << ": $" << node->feature_no << " < " << node->feature_val << " ? " << std::endl;
    str_inner(ss, (RealNode*)node->left, level + 1);
    str_inner(ss, (RealNode*)node->right, level + 1);
  }
}

RegressionTree::Node::Node(int id_) : id(id_) {}

bool RegressionTree::Node::is_leaf() const {
  return left == NULL;
}

RegressionTree::Node::~Node() {
  if (left != NULL) {
    delete left;
    delete right;
  }
}

RegressionTree::RealNode::RealNode(int id_) : Node(id_) {}

RegressionTree::Comp::Comp(const ArrayXXd& data_, ArrayXXd::Index column_)
  : data(data_), column(column_) {}

bool RegressionTree::Comp::operator() (int i, int j) const {
  return data(i, column) < data(j, column);
}

void test_regression_tree2() {
  RegressionTree r(1);
  Eigen::ArrayXd f(1);
  f << 1.5;
  r.read_data_item(f, 1);
  f << 1.5;
  r.read_data_item(f, 1);
  f << 3;
  r.read_data_item(f, 1);
  f << 3;
  r.read_data_item(f, 2);
  f << 3;
  r.read_data_item(f, 2);
  f << 3;
  r.read_data_item(f, 2);
  r.finalize_data();
  r.build_tree(0, 1);
  std::cout << r.str();
}

void test_regression_tree() {
  RegressionTree r(3);
  Eigen::ArrayXd f(3);
  f << 1, 1, 8;
  r.read_data_item(f, 1);
  f << 2, 3, 7;
  r.read_data_item(f, 2);
  f << 3, 4, 4;
  r.read_data_item(f, 2);
  f << 4, 2, 3;
  r.read_data_item(f, 1);
  f << 5, 6, 1;
  r.read_data_item(f, 3);
  f << 6, 8, 2;
  r.read_data_item(f, 4);
  f << 7, 5, 5;
  r.read_data_item(f, 3);
  f << 8, 7, 6;
  r.read_data_item(f, 4);
  r.finalize_data();
  r.build_tree(0, 2);
  std::cout << r.str();
}

<commit_msg>Modified RegressionTree::str() a bit. 	modified:   ml/regression_tree.cpp<commit_after>#include "ml/regression_tree.h"

#include <iostream>

#include "ml/learning_rate.h"
#include "ml/utils.h"

using Eigen::Map;
using Eigen::RowVectorXd;
using Eigen::ArrayXi;

RegressionTree::RegressionTree(size_t dimensions_, LearningRate* learning_rate_)
  : dimensions(dimensions_), learning_rate(learning_rate_),
    data(ArrayXXd(1000, dimensions_)), outputs(ArrayXd(1000)), rows_read(0),
    tree(NULL) {
  if (learning_rate == NULL) {
    learning_rate = new ConstantLearningRate(0.9);
  }
}

RegressionTree::~RegressionTree() {
  delete learning_rate;
  delete tree;
}

void RegressionTree::read_data_item(double* const& features, const double& output) {
  /* Expand the data matrix. */
  if (data.rows() == rows_read) {
    data.conservativeResize(Eigen::NoChange, 2 * data.rows());
    outputs.conservativeResize(2 * outputs.size());
  }

  data.row(rows_read) = Map<RowVectorXd>(features, dimensions);
  outputs(rows_read) = output;
  rows_read++;
}

// TODO: merge the two
void RegressionTree::read_data_item(Eigen::ArrayXd& features, const double& output) {
  /* Expand the data matrix. */
  if (data.rows() == rows_read) {
    data.conservativeResize(Eigen::NoChange, 2 * data.rows());
    outputs.conservativeResize(2 * outputs.size());
  }

  // TODO: size() check?
  data.row(rows_read) = features.head(dimensions);
  outputs(rows_read) = output;
  rows_read++;
}

void RegressionTree::finalize_data() {
  data.conservativeResize(rows_read, Eigen::NoChange);
  outputs.conservativeResize(rows_read);
}

void RegressionTree::create_sorted() {
  /* First, create the sorted array, ... */
  sorted.resize(data.rows(), data.cols());
  ArrayXi tmp = ArrayXi::Constant(data.cols(), 0);
  for (size_t i = 0; i < sorted.rows(); i++) {
    sorted.row(i) = tmp;
    tmp += 1;
  }
  /* ... then sort! */
  auto begin = sorted.data();
  Comp comp(data);
  for (ArrayXXd::Index col = 0; col < data.cols(); col++) {
    comp.column = col;
    std::sort(begin, begin + sorted.rows(), comp);
    begin += sorted.rows();
  }
}

/**
 * @param[in] delta if the error does not decrease by at least @p delta, stop.
 * @param[in] q if one of the children would have at most q nodes, stop.
 */
void RegressionTree::build_tree(double delta, size_t q) {
  create_sorted();
  tree = new RealNode(0);
  tree->output = outputs.sum() / outputs.size();
  tree->error  = (outputs - tree->output).pow(2).sum();
  ArrayXi valid = ArrayXi::Zero(sorted.rows());
  int max_id = 0;
  split_node(tree, valid, max_id, valid.size(), delta, q);
}

void RegressionTree::split_node(Node* node, ArrayXi& valid, int& max_id,
                                ArrayXi::Index num_docs, double delta, size_t q) {
  double min_error   = node->error;
  size_t min_feature = dimensions;
  double min_value   = 0;
  double min_left_error  = 0;
  double min_right_error = 0;
//  ArrayXd::SegmentReturnType min_head = outputs.head(0);  // placeholder only
//  ArrayXd::SegmentReturnType min_tail = outputs.tail(0);  // placeholder only
  ArrayXd min_head, min_tail;
  size_t min_left_valids = 0;

  // TODO: to argument?
  /* Create a list of the outputs. */
  ArrayXd sorted_outputs(num_docs);

  /* Iterate through all features. */
  for (size_t f = 0; f < dimensions; f++) {
    /* The outputs sorted by the current feature. */
    for (size_t i = 0, j = 0; j < sorted_outputs.size(); i++) {
      if (valid(sorted(i, f)) == node->id) sorted_outputs(j++) = outputs(sorted(i, f));
    }

    /* Number of valids on the left side of the split. */
    size_t left_valids = 0;
    /*
     * The last value of the feature. Recorded for two reasons:
     * 1. we cannot put a cutting point between two equal-valued item;
     * 2. the check value will be halfway between the last and the current items.
     */
    double last_value = DNaN;
    /*
     * All possible split with that feature -- we cannot start at q, because we
     * have to keep track of split.
     */
    for (size_t split = 0; split <= sorted.rows() - q; split++) {
      if (valid(sorted(split, f)) != node->id) continue;  // Document not under this node

      double& curr_value = data(sorted(split, f));

      /* last_value/1: skip if feature value is the same as last item's. */
      if (double_equals(last_value, curr_value)) {
        left_valids++;  // still, it was a valid item
        continue;
      }

      size_t right_valids = num_docs - left_valids;
      if (left_valids >= q && right_valids >= q) {
        auto head = sorted_outputs.head(left_valids);
        auto tail = sorted_outputs.tail(right_valids);
        double left_error = (head - head.sum() / head.size()).pow(2).sum();
        double right_error = (tail - tail.sum() / tail.size()).pow(2).sum();
        double curr_error = left_error + right_error;
        if (curr_error < min_error) {
          min_error   = curr_error;
          min_feature = f;
          // last_value/2.
          min_value   = isnan(last_value)
                        ? curr_value - epsilon
                        : (last_value + curr_value) / 2;
          min_left_error = left_error;
          min_right_error = right_error;
          min_head = head;
          min_tail = tail;
          min_left_valids = left_valids;
        }
      }

      left_valids++;
      last_value = data(sorted(split, f), f);
    }  // for split
  }  // for features

  if (min_error + delta < node->error) {
    node->feature_no  = min_feature;
    // TODO: handle enum node type
    ((RealNode*)node)->feature_val = min_value;

    int left_id  = ++max_id;
    int right_id = ++max_id;
    ArrayXi::Index left_docs  = 0;
    ArrayXi::Index right_docs = 0;
    // TODO: sparse / set / map
    for (ArrayXXi::Index i = 0; i < valid.size(); i++) {
      if (valid(i) == node->id) {
        if (data(i, min_feature) < min_value) {
          valid(i) = left_id;
          left_docs++;
        } else {
          valid(i) = right_id;
          right_docs++;
        }
      }
    }  // for

    node->left  = new RealNode(left_id);
    node->left->output = min_head.sum() / min_head.size();
    node->left->error = min_left_error;
    node->right = new RealNode(right_id);
    node->right->output = min_tail.sum() / min_tail.size();
    node->right->error = min_right_error;

    if (left_docs >= 2 * q) {
      split_node(node->left, valid, max_id, left_docs, delta, q);
    }
    if (right_docs >= 2 * q) {
      split_node(node->right, valid, max_id, right_docs, delta, q);
    }
  }
}

std::string RegressionTree::str() const {
  std::stringstream ss;
  str_inner(ss, tree, 0);
  return ss.str();
}

void RegressionTree::str_inner(std::stringstream& ss,
                               RealNode* node, size_t level) const {
  for (size_t i = 0; i < level; i++) ss << "  ";
  ss << node->id;
  if (node->left == NULL) {
    ss << ": " << node->output << " (err: " << node->error << ")" << std::endl;
  } else {
    ss << ": " << node->output << " (err: " << node->error << ") $"
       << node->feature_no << " < " << node->feature_val << " ? " << std::endl;
    str_inner(ss, (RealNode*)node->left, level + 1);
    str_inner(ss, (RealNode*)node->right, level + 1);
  }
}

RegressionTree::Node::Node(int id_) : id(id_) {}

bool RegressionTree::Node::is_leaf() const {
  return left == NULL;
}

RegressionTree::Node::~Node() {
  if (left != NULL) {
    delete left;
    delete right;
  }
}

RegressionTree::RealNode::RealNode(int id_) : Node(id_) {}

RegressionTree::Comp::Comp(const ArrayXXd& data_, ArrayXXd::Index column_)
  : data(data_), column(column_) {}

bool RegressionTree::Comp::operator() (int i, int j) const {
  return data(i, column) < data(j, column);
}

void test_regression_tree2() {
  RegressionTree r(1);
  Eigen::ArrayXd f(1);
  f << 1.5;
  r.read_data_item(f, 1);
  f << 1.5;
  r.read_data_item(f, 1);
  f << 3;
  r.read_data_item(f, 1);
  f << 3;
  r.read_data_item(f, 2);
  f << 3;
  r.read_data_item(f, 2);
  f << 3;
  r.read_data_item(f, 2);
  r.finalize_data();
  r.build_tree(0, 1);
  std::cout << r.str();
}

void test_regression_tree() {
  RegressionTree r(3);
  Eigen::ArrayXd f(3);
  f << 1, 1, 8;
  r.read_data_item(f, 1);
  f << 2, 3, 7;
  r.read_data_item(f, 2);
  f << 3, 4, 4;
  r.read_data_item(f, 2);
  f << 4, 2, 3;
  r.read_data_item(f, 1);
  f << 5, 6, 1;
  r.read_data_item(f, 3);
  f << 6, 8, 2;
  r.read_data_item(f, 4);
  f << 7, 5, 5;
  r.read_data_item(f, 3);
  f << 8, 7, 6;
  r.read_data_item(f, 4);
  r.finalize_data();
  r.build_tree(0, 2);
  std::cout << r.str();
}

<|endoftext|>


<commit_before>#include "mock/unittest_utils.hpp"

#include <stdlib.h>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/timing.hpp"
#include "arch/runtime/starter.hpp"
#include "utils.hpp"            // randint

namespace mock {

temp_file_t::temp_file_t(const char *tmpl) {
    size_t len = strlen(tmpl);
    filename.init(len + 1);
    memcpy(filename.data(), tmpl, len+1);
    int fd = mkstemp(filename.data());
    guarantee_err(fd != -1, "Couldn't create a temporary file");
    close(fd);
}

temp_file_t::~temp_file_t() {
    unlink(filename.data());
}

void let_stuff_happen() {
    nap(100);
}

int randport() {
    return 10000 + randint(20000);
}

void run_in_thread_pool(const boost::function<void()>& fun, int num_workers) {
    ::run_in_thread_pool(fun, num_workers);
}

}  // namespace mock
<commit_msg>Make let_stuff_happen() wait longer under valgrind.<commit_after>#include "mock/unittest_utils.hpp"

#include <stdlib.h>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/timing.hpp"
#include "arch/runtime/starter.hpp"
#include "utils.hpp"            // randint

namespace mock {

temp_file_t::temp_file_t(const char *tmpl) {
    size_t len = strlen(tmpl);
    filename.init(len + 1);
    memcpy(filename.data(), tmpl, len+1);
    int fd = mkstemp(filename.data());
    guarantee_err(fd != -1, "Couldn't create a temporary file");
    close(fd);
}

temp_file_t::~temp_file_t() {
    unlink(filename.data());
}

void let_stuff_happen() {
#ifdef VALGRIND
    nap(2000);
#else
    nap(100);
#endif
}

int randport() {
    return 10000 + randint(20000);
}

void run_in_thread_pool(const boost::function<void()>& fun, int num_workers) {
    ::run_in_thread_pool(fun, num_workers);
}

}  // namespace mock
<|endoftext|>


<commit_before>
#include <test.hpp>

TEST_CASE("basic") {

    SECTION("default constructed pbf message is okay") {
        mapbox::util::pbf item;
        REQUIRE(!item.next());
    }

    SECTION("empty buffer is okay") {
        std::string buffer;
        mapbox::util::pbf item(buffer.data(), 0);
        REQUIRE(!item.next());
    }

}

<commit_msg>Add a test.<commit_after>
#include <test.hpp>

TEST_CASE("basic") {

    SECTION("default constructed pbf message is okay") {
        mapbox::util::pbf item;
        REQUIRE(!item.next());
    }

    SECTION("empty buffer is okay") {
        std::string buffer;
        mapbox::util::pbf item(buffer.data(), 0);
        REQUIRE(!item.next());
    }

    SECTION("check every possible value for single byte in buffer") {
        char buffer[1];
        for (int i = 0; i <= 255; ++i) {
            *buffer = static_cast<char>(i);
            mapbox::util::pbf item(buffer, 1);

            REQUIRE_THROWS({
                item.next();
                item.skip();
            });
        }
    }

}

<|endoftext|>