<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 <QTimer>

#include "qhttpsocket.h"
#include "qhttpsocket_p.h"

QHttpSocketPrivate::QHttpSocketPrivate(QHttpSocket *httpSocket, QTcpSocket *baseSocket)
    : q(httpSocket),
      socket(baseSocket),
      httpError(QHttpSocket::NoError),
      requestHeadersRead(false),
      responseStatusCode("200 OK"),
      responseHeaderLength(0),
      responseHeadersWritten(false)
{
    // Re-parent the socket to this class
    socket->setParent(this);

    // Both of these signals must be handled directly since the
    // socket acts as a transport both for headers and for data
    connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
    connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));

    // Next time the event loop is entered, attempt to read data from the socket
    QTimer::singleShot(0, this, SLOT(onReadyRead()));
}

void QHttpSocketPrivate::writeResponseHeaders()
{
    // Use a QByteArray for building the header so that we
    // can later determine exactly how many bytes were written
    QByteArray header;

    // Append the status line
    header.append("HTTP/1.0 ");
    header.append(responseStatusCode.toUtf8());
    header.append("\r\n");

    // Append each of the headers followed by a CRLF
    QMap<QString, QString>::const_iterator i = responseHeaders.constBegin();
    for(; i != responseHeaders.constEnd(); ++i) {
        header.append(i.key().toUtf8());
        header.append(": ");
        header.append(i.value().toUtf8());
        header.append("\r\n");
    }

    // Append an extra CRLF
    header.append("\r\n");

    // Write the header
    socket->write(header);

    responseHeaderLength = header.length();
    responseHeadersWritten = true;
}

void QHttpSocketPrivate::onReadyRead()
{
    // Add the new data to the internal buffer
    buffer.append(socket->readAll());

    // If the request headers have not yet been parsed, check for two CRLFs
    if(!requestHeadersRead) {

        int index = buffer.indexOf("\r\n\r\n");
        if(index != -1) {

            // Parse the headers and remove them from the data
            parseRequestHeaders(buffer.left(index));
            buffer.remove(0, index + 4);

            // Check to see if an error occurred during parsing
            if(httpError != QHttpSocket::NoError) {

                // Set a descriptive error message
                switch(httpError) {
                case QHttpSocket::MalformedRequestLine:
                    q->setErrorString(tr("Malformed request line"));
                    break;
                case QHttpSocket::MalformedRequestHeader:
                    q->setErrorString(tr("Malformed request header"));
                    break;
                case QHttpSocket::InvalidHttpVersion:
                    q->setErrorString(tr("Invalid HTTP version"));
                    break;
                }

                Q_EMIT q->httpErrorChanged(httpError);

            } else {

                // Indicate that the request headers were parsed
                Q_EMIT q->requestHeadersReadChanged(requestHeadersRead = true);
            }

        } else {
            return;
        }
    }

    // If there is data remaining in the buffer, emit the readyRead signal
    if(buffer.length()) {
        Q_EMIT q->readyRead();
    }
}

void QHttpSocketPrivate::onBytesWritten(qint64 bytes)
{
    // Since this signal may be emitted even if no actual data was written,
    // the number of bytes needs to be subtracted from the header length
    if(responseHeaderLength - bytes >= 0) {
        responseHeaderLength -= bytes;
    } else {
        Q_EMIT q->bytesWritten(bytes - responseHeaderLength);
        responseHeaderLength = 0;
    }
}

void QHttpSocketPrivate::parseRequestHeaders(const QString &headers)
{
    // Split the header into individual lines
    QStringList parts = headers.split("\r\n");

    // Parse the first line (the request line)
    parseRequestLine(parts.takeFirst());

    // Parse each of the remaining lines (the headers)
    foreach(const QString &header, parts) {
        parseRequestHeader(header);
    }
}

void QHttpSocketPrivate::parseRequestLine(const QString &line)
{
    // The request line consists of three parts separated by space
    QStringList parts = line.split(" ");

    // If 3 parts are not supplied, then stop parsing the line
    // to avoid invalid array indices later on
    if(parts.count() != 3) {
        httpError = QHttpSocket::MalformedRequestLine;
        return;
    }

    // Only HTTP versions 1.0 and 1.1 are currently supported
    if(parts[2] != "HTTP/1.0" && parts[2] != "HTTP/1.1") {
        httpError = QHttpSocket::InvalidHttpVersion;
    }

    requestMethod = parts[0];
    requestUri = parts[1];
}

void QHttpSocketPrivate::parseRequestHeader(const QString &header)
{
    // Each header consists of the key, ":", and the value
    int index = header.indexOf(":");

    // If the colon was not found, then stop parsing the header
    if(index == -1) {
        httpError = QHttpSocket::MalformedRequestHeader;
        return;
    }

    // Trim each part and add it to the map
    requestHeaders.insert(
        header.left(index).trimmed().toLower(),
        header.mid(index + 1).trimmed()
    );
}

QHttpSocket::QHttpSocket(QTcpSocket *socket, QObject *parent)
    : QIODevice(parent),
      d(new QHttpSocketPrivate(this, socket))
{
    // The device is immediately open for reading
    setOpenMode(QIODevice::ReadWrite);
}

QHttpSocket::~QHttpSocket()
{
    delete d;
}

void QHttpSocket::close()
{
    // Don't do anything if the device was already closed
    if(!isOpen()) {
        return;
    }

    // If the response headers have not yet been written, then do so before closing
    if(!d->responseHeadersWritten) {
        d->writeResponseHeaders();
    }

    QIODevice::close();
}

QHttpSocket::HttpError QHttpSocket::httpError() const
{
    return d->httpError;
}

QString QHttpSocket::requestMethod() const
{
    return d->requestMethod;
}

QString QHttpSocket::requestUri() const
{
    return d->requestUri;
}

QStringList QHttpSocket::requestHeaders() const
{
    return d->requestHeaders.keys();
}

bool QHttpSocket::requestHeadersRead() const
{
    return d->requestHeadersRead;
}

QString QHttpSocket::requestHeader(const QString &header) const
{
    return d->requestHeaders.value(header.toLower());
}

void QHttpSocket::setResponseStatusCode(const QString &statusCode)
{
    d->responseStatusCode = statusCode;
}

void QHttpSocket::setResponseHeader(const QString &header, const QString &value)
{
    d->responseHeaders.insert(header, value);
}

bool QHttpSocket::isSequential() const
{
    return true;
}

qint64 QHttpSocket::readData(char *data, qint64 maxlen)
{
    // Data can only be read from the socket once the request headers are read
    if(!requestHeadersRead()) {
        return -1;
    }

    // Ensure that no more than the requested amount or the size of the buffer is read
    qint64 size = qMin(static_cast<qint64>(d->buffer.size()), maxlen);
    memcpy(data, d->buffer.constData(), size);

    // Remove the amount that was read from the buffer
    d->buffer.remove(0, size);

    return size;
}

qint64 QHttpSocket::writeData(const char *data, qint64 len)
{
    // If the response headers have not yet been written, they
    // must immediately be written before the data can be
    if(!d->responseHeadersWritten) {
        d->writeResponseHeaders();
    }

    return d->socket->write(data, len);
}
<commit_msg>Ensured that closing the device closes the socket.<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 <QTimer>

#include "qhttpsocket.h"
#include "qhttpsocket_p.h"

QHttpSocketPrivate::QHttpSocketPrivate(QHttpSocket *httpSocket, QTcpSocket *baseSocket)
    : q(httpSocket),
      socket(baseSocket),
      httpError(QHttpSocket::NoError),
      requestHeadersRead(false),
      responseStatusCode("200 OK"),
      responseHeaderLength(0),
      responseHeadersWritten(false)
{
    // Re-parent the socket to this class
    socket->setParent(this);

    // Both of these signals must be handled directly since the
    // socket acts as a transport both for headers and for data
    connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
    connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));

    // Next time the event loop is entered, attempt to read data from the socket
    QTimer::singleShot(0, this, SLOT(onReadyRead()));
}

void QHttpSocketPrivate::writeResponseHeaders()
{
    // Use a QByteArray for building the header so that we
    // can later determine exactly how many bytes were written
    QByteArray header;

    // Append the status line
    header.append("HTTP/1.0 ");
    header.append(responseStatusCode.toUtf8());
    header.append("\r\n");

    // Append each of the headers followed by a CRLF
    QMap<QString, QString>::const_iterator i = responseHeaders.constBegin();
    for(; i != responseHeaders.constEnd(); ++i) {
        header.append(i.key().toUtf8());
        header.append(": ");
        header.append(i.value().toUtf8());
        header.append("\r\n");
    }

    // Append an extra CRLF
    header.append("\r\n");

    // Write the header
    socket->write(header);

    responseHeaderLength = header.length();
    responseHeadersWritten = true;
}

void QHttpSocketPrivate::onReadyRead()
{
    // Add the new data to the internal buffer
    buffer.append(socket->readAll());

    // If the request headers have not yet been parsed, check for two CRLFs
    if(!requestHeadersRead) {

        int index = buffer.indexOf("\r\n\r\n");
        if(index != -1) {

            // Parse the headers and remove them from the data
            parseRequestHeaders(buffer.left(index));
            buffer.remove(0, index + 4);

            // Check to see if an error occurred during parsing
            if(httpError != QHttpSocket::NoError) {

                // Set a descriptive error message
                switch(httpError) {
                case QHttpSocket::MalformedRequestLine:
                    q->setErrorString(tr("Malformed request line"));
                    break;
                case QHttpSocket::MalformedRequestHeader:
                    q->setErrorString(tr("Malformed request header"));
                    break;
                case QHttpSocket::InvalidHttpVersion:
                    q->setErrorString(tr("Invalid HTTP version"));
                    break;
                }

                Q_EMIT q->httpErrorChanged(httpError);

            } else {

                // Indicate that the request headers were parsed
                Q_EMIT q->requestHeadersReadChanged(requestHeadersRead = true);
            }

        } else {
            return;
        }
    }

    // If there is data remaining in the buffer, emit the readyRead signal
    if(buffer.length()) {
        Q_EMIT q->readyRead();
    }
}

void QHttpSocketPrivate::onBytesWritten(qint64 bytes)
{
    // Since this signal may be emitted even if no actual data was written,
    // the number of bytes needs to be subtracted from the header length
    if(responseHeaderLength - bytes >= 0) {
        responseHeaderLength -= bytes;
    } else {
        Q_EMIT q->bytesWritten(bytes - responseHeaderLength);
        responseHeaderLength = 0;
    }
}

void QHttpSocketPrivate::parseRequestHeaders(const QString &headers)
{
    // Split the header into individual lines
    QStringList parts = headers.split("\r\n");

    // Parse the first line (the request line)
    parseRequestLine(parts.takeFirst());

    // Parse each of the remaining lines (the headers)
    foreach(const QString &header, parts) {
        parseRequestHeader(header);
    }
}

void QHttpSocketPrivate::parseRequestLine(const QString &line)
{
    // The request line consists of three parts separated by space
    QStringList parts = line.split(" ");

    // If 3 parts are not supplied, then stop parsing the line
    // to avoid invalid array indices later on
    if(parts.count() != 3) {
        httpError = QHttpSocket::MalformedRequestLine;
        return;
    }

    // Only HTTP versions 1.0 and 1.1 are currently supported
    if(parts[2] != "HTTP/1.0" && parts[2] != "HTTP/1.1") {
        httpError = QHttpSocket::InvalidHttpVersion;
    }

    requestMethod = parts[0];
    requestUri = parts[1];
}

void QHttpSocketPrivate::parseRequestHeader(const QString &header)
{
    // Each header consists of the key, ":", and the value
    int index = header.indexOf(":");

    // If the colon was not found, then stop parsing the header
    if(index == -1) {
        httpError = QHttpSocket::MalformedRequestHeader;
        return;
    }

    // Trim each part and add it to the map
    requestHeaders.insert(
        header.left(index).trimmed().toLower(),
        header.mid(index + 1).trimmed()
    );
}

QHttpSocket::QHttpSocket(QTcpSocket *socket, QObject *parent)
    : QIODevice(parent),
      d(new QHttpSocketPrivate(this, socket))
{
    // The device is immediately open for reading
    setOpenMode(QIODevice::ReadWrite);
}

QHttpSocket::~QHttpSocket()
{
    delete d;
}

void QHttpSocket::close()
{
    // Don't do anything if the device was already closed
    if(!isOpen()) {
        return;
    }

    // If the response headers have not yet been written, then do so before closing
    if(!d->responseHeadersWritten) {
        d->writeResponseHeaders();
    }

    d->socket->close();
    QIODevice::close();
}

QHttpSocket::HttpError QHttpSocket::httpError() const
{
    return d->httpError;
}

QString QHttpSocket::requestMethod() const
{
    return d->requestMethod;
}

QString QHttpSocket::requestUri() const
{
    return d->requestUri;
}

QStringList QHttpSocket::requestHeaders() const
{
    return d->requestHeaders.keys();
}

bool QHttpSocket::requestHeadersRead() const
{
    return d->requestHeadersRead;
}

QString QHttpSocket::requestHeader(const QString &header) const
{
    return d->requestHeaders.value(header.toLower());
}

void QHttpSocket::setResponseStatusCode(const QString &statusCode)
{
    d->responseStatusCode = statusCode;
}

void QHttpSocket::setResponseHeader(const QString &header, const QString &value)
{
    d->responseHeaders.insert(header, value);
}

bool QHttpSocket::isSequential() const
{
    return true;
}

qint64 QHttpSocket::readData(char *data, qint64 maxlen)
{
    // Data can only be read from the socket once the request headers are read
    if(!requestHeadersRead()) {
        return -1;
    }

    // Ensure that no more than the requested amount or the size of the buffer is read
    qint64 size = qMin(static_cast<qint64>(d->buffer.size()), maxlen);
    memcpy(data, d->buffer.constData(), size);

    // Remove the amount that was read from the buffer
    d->buffer.remove(0, size);

    return size;
}

qint64 QHttpSocket::writeData(const char *data, qint64 len)
{
    // If the response headers have not yet been written, they
    // must immediately be written before the data can be
    if(!d->responseHeadersWritten) {
        d->writeResponseHeaders();
    }

    return d->socket->write(data, len);
}
<|endoftext|>


<commit_before>#include "queueloader.h"

#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <libgen.h>
#include <unistd.h>

#include "config.h"
#include "configcontainer.h"
#include "logger.h"
#include "stflpp.h"
#include "strprintf.h"
#include "utils.h"

using namespace newsboat;

namespace podboat {

QueueLoader::QueueLoader(const std::string& file, PbController* c)
	: queuefile(file)
	, ctrl(c)
{
}

void QueueLoader::reload(std::vector<Download>& downloads, bool remove_unplayed)
{
	std::vector<Download> dltemp;
	std::vector<Download> deletion_list;
	std::fstream f;

	for (const auto& dl : downloads) {
		// we are not allowed to reload if a download is in progress!
		if (dl.status() == DlStatus::DOWNLOADING) {
			LOG(Level::INFO,
				"QueueLoader::reload: aborting reload due to "
				"DlStatus::DOWNLOADING status");
			return;
		}
		bool keep_entry = false;
		switch (dl.status()) {
		case DlStatus::QUEUED:
		case DlStatus::CANCELLED:
		case DlStatus::FAILED:
		case DlStatus::ALREADY_DOWNLOADED:
		case DlStatus::READY:
			LOG(Level::DEBUG,
				"QueueLoader::reload: storing %s to new vector",
				dl.url());
			keep_entry = true;
			break;
		case DlStatus::PLAYED:
		case DlStatus::FINISHED:
			if (!remove_unplayed) {
				LOG(Level::DEBUG,
					"QueueLoader::reload: storing %s to "
					"new "
					"vector",
					dl.url());
				keep_entry = true;
			}
			break;
		default:
			break;
		}

		if (keep_entry) {
			dltemp.push_back(dl);
		} else {
			deletion_list.push_back(dl);
		}
	}

	f.open(queuefile.c_str(), std::fstream::in);
	bool comments_ignored = false;
	if (f.is_open()) {
		std::string line;
		do {
			std::getline(f, line);
			if (!f.eof() && line.length() > 0) {
				LOG(Level::DEBUG,
					"QueueLoader::reload: loaded `%s' from "
					"queue file",
					line);
				std::vector<std::string> fields =
					utils::tokenize_quoted(line);
				bool url_found = false;

				if (fields.empty()) {
					if (!comments_ignored) {
						std::cout << strprintf::fmt(
								_("WARNING: Comment found "
									"in %s. The queue file is regenerated "
									"when podboat exits and comments will "
									"be deleted. Press Enter to continue or "
									"Ctrl+C to abort"),
								queuefile)
							<< std::endl;
						std::cin.ignore();
						comments_ignored = true;
					}
					continue;
				}

				for (const auto& dl : dltemp) {
					if (fields[0] == dl.url()) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' in old "
							"vector",
							fields[0]);
						url_found = true;
						break;
					}
				}

				for (const auto& dl : deletion_list) {
					if (fields[0] == dl.url()) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' in scheduled for deletion "
							"vector",
							fields[0]);
						url_found = true;
						break;
					}
				}

				if (!url_found) {
					LOG(Level::INFO,
						"QueueLoader::reload: found "
						"`%s' "
						"nowhere -> storing to new "
						"vector",
						line);
					Download d(ctrl);
					std::string fn;
					if (fields.size() == 1) {
						fn = get_filename(fields[0]);
					} else {
						fn = fields[1];
					}
					d.set_filename(fn);
					if (access(fn.c_str(), F_OK) == 0) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' on file "
							"system "
							"-> mark as already "
							"downloaded",
							fn);
						if (fields.size() >= 3) {
							if (fields[2] ==
								"downloaded")
								d.set_status(
									DlStatus::
									READY);
							if (fields[2] ==
								"played")
								d.set_status(
									DlStatus::
									PLAYED);
							if (fields[2] ==
								"finished")
								d.set_status(
									DlStatus::
									FINISHED);
						} else
							d.set_status(DlStatus::
								ALREADY_DOWNLOADED); // TODO: scrap DlStatus::ALREADY_DOWNLOADED state
					} else if (
						access((fn +
								ConfigContainer::
								PARTIAL_FILE_SUFFIX)
							.c_str(),
							F_OK) == 0) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' on file "
							"system "
							"-> mark as partially "
							"downloaded",
							fn +
							ConfigContainer::
							PARTIAL_FILE_SUFFIX);
						d.set_status(DlStatus::
							ALREADY_DOWNLOADED);
					}

					d.set_url(fields[0]);
					dltemp.push_back(d);
				}
			}
		} while (!f.eof());
		f.close();
	}

	f.open(queuefile.c_str(), std::fstream::out);
	if (f.is_open()) {
		for (const auto& dl : dltemp) {
			f << dl.url() << " " << utils::quote(dl.filename());
			if (dl.status() == DlStatus::READY) {
				f << " downloaded";
			}
			if (dl.status() == DlStatus::PLAYED) {
				f << " played";
			}
			if (dl.status() == DlStatus::FINISHED) {
				f << " finished";
			}
			f << std::endl;
		}
		f.close();
	}

	downloads = dltemp;
}

std::string QueueLoader::get_filename(const std::string& str)
{
	std::string fn = ctrl->get_dlpath();

	if (fn[fn.length() - 1] != NEWSBEUTER_PATH_SEP[0]) {
		fn.append(NEWSBEUTER_PATH_SEP);
	}
	char buf[1024];
	snprintf(buf, sizeof(buf), "%s", str.c_str());
	char* base = basename(buf);
	if (!base || strlen(base) == 0) {
		time_t t = time(nullptr);
		fn.append(utils::mt_strf_localtime("%Y-%b-%d-%H%M%S.unknown", t));
	} else {
		fn.append(utils::replace_all(base, "'", "%27"));
	}
	return fn;
}

} // namespace podboat
<commit_msg>PB queueloader: Delete files marked for deletion during reload<commit_after>#include "queueloader.h"

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <libgen.h>
#include <unistd.h>

#include "config.h"
#include "configcontainer.h"
#include "logger.h"
#include "stflpp.h"
#include "strprintf.h"
#include "utils.h"

using namespace newsboat;

namespace podboat {

QueueLoader::QueueLoader(const std::string& file, PbController* c)
	: queuefile(file)
	, ctrl(c)
{
}

void QueueLoader::reload(std::vector<Download>& downloads, bool remove_unplayed)
{
	std::vector<Download> dltemp;
	std::vector<Download> deletion_list;
	std::fstream f;

	for (const auto& dl : downloads) {
		// we are not allowed to reload if a download is in progress!
		if (dl.status() == DlStatus::DOWNLOADING) {
			LOG(Level::INFO,
				"QueueLoader::reload: aborting reload due to "
				"DlStatus::DOWNLOADING status");
			return;
		}
		bool keep_entry = false;
		switch (dl.status()) {
		case DlStatus::QUEUED:
		case DlStatus::CANCELLED:
		case DlStatus::FAILED:
		case DlStatus::ALREADY_DOWNLOADED:
		case DlStatus::READY:
			LOG(Level::DEBUG,
				"QueueLoader::reload: storing %s to new vector",
				dl.url());
			keep_entry = true;
			break;
		case DlStatus::PLAYED:
		case DlStatus::FINISHED:
			if (!remove_unplayed) {
				LOG(Level::DEBUG,
					"QueueLoader::reload: storing %s to "
					"new "
					"vector",
					dl.url());
				keep_entry = true;
			}
			break;
		default:
			break;
		}

		if (keep_entry) {
			dltemp.push_back(dl);
		} else {
			deletion_list.push_back(dl);
		}
	}

	f.open(queuefile.c_str(), std::fstream::in);
	bool comments_ignored = false;
	if (f.is_open()) {
		std::string line;
		do {
			std::getline(f, line);
			if (!f.eof() && line.length() > 0) {
				LOG(Level::DEBUG,
					"QueueLoader::reload: loaded `%s' from "
					"queue file",
					line);
				std::vector<std::string> fields =
					utils::tokenize_quoted(line);
				bool url_found = false;

				if (fields.empty()) {
					if (!comments_ignored) {
						std::cout << strprintf::fmt(
								_("WARNING: Comment found "
									"in %s. The queue file is regenerated "
									"when podboat exits and comments will "
									"be deleted. Press Enter to continue or "
									"Ctrl+C to abort"),
								queuefile)
							<< std::endl;
						std::cin.ignore();
						comments_ignored = true;
					}
					continue;
				}

				for (const auto& dl : dltemp) {
					if (fields[0] == dl.url()) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' in old "
							"vector",
							fields[0]);
						url_found = true;
						break;
					}
				}

				for (const auto& dl : deletion_list) {
					if (fields[0] == dl.url()) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' in scheduled for deletion "
							"vector",
							fields[0]);
						url_found = true;
						break;
					}
				}

				if (!url_found) {
					LOG(Level::INFO,
						"QueueLoader::reload: found "
						"`%s' "
						"nowhere -> storing to new "
						"vector",
						line);
					Download d(ctrl);
					std::string fn;
					if (fields.size() == 1) {
						fn = get_filename(fields[0]);
					} else {
						fn = fields[1];
					}
					d.set_filename(fn);
					if (access(fn.c_str(), F_OK) == 0) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' on file "
							"system "
							"-> mark as already "
							"downloaded",
							fn);
						if (fields.size() >= 3) {
							if (fields[2] ==
								"downloaded")
								d.set_status(
									DlStatus::
									READY);
							if (fields[2] ==
								"played")
								d.set_status(
									DlStatus::
									PLAYED);
							if (fields[2] ==
								"finished")
								d.set_status(
									DlStatus::
									FINISHED);
						} else
							d.set_status(DlStatus::
								ALREADY_DOWNLOADED); // TODO: scrap DlStatus::ALREADY_DOWNLOADED state
					} else if (
						access((fn +
								ConfigContainer::
								PARTIAL_FILE_SUFFIX)
							.c_str(),
							F_OK) == 0) {
						LOG(Level::INFO,
							"QueueLoader::reload: "
							"found `%s' on file "
							"system "
							"-> mark as partially "
							"downloaded",
							fn +
							ConfigContainer::
							PARTIAL_FILE_SUFFIX);
						d.set_status(DlStatus::
							ALREADY_DOWNLOADED);
					}

					d.set_url(fields[0]);
					dltemp.push_back(d);
				}
			}
		} while (!f.eof());
		f.close();
	}

	f.open(queuefile.c_str(), std::fstream::out);
	if (f.is_open()) {
		for (const auto& dl : dltemp) {
			f << dl.url() << " " << utils::quote(dl.filename());
			if (dl.status() == DlStatus::READY) {
				f << " downloaded";
			}
			if (dl.status() == DlStatus::PLAYED) {
				f << " played";
			}
			if (dl.status() == DlStatus::FINISHED) {
				f << " finished";
			}
			f << std::endl;
		}
		f.close();
	}

	for (const auto& dl : deletion_list) {
		std::string filename = dl.filename();
		if (access(filename.c_str(), F_OK) == 0) {
			LOG(Level::INFO,
				"Deleting file %s",
				filename);
			if (std::remove(filename.c_str()) != 0) {
				LOG(Level::ERROR,
					"Failed to delete file %s",
					filename);
			}
		}
	}

	downloads = dltemp;
}

std::string QueueLoader::get_filename(const std::string& str)
{
	std::string fn = ctrl->get_dlpath();

	if (fn[fn.length() - 1] != NEWSBEUTER_PATH_SEP[0]) {
		fn.append(NEWSBEUTER_PATH_SEP);
	}
	char buf[1024];
	snprintf(buf, sizeof(buf), "%s", str.c_str());
	char* base = basename(buf);
	if (!base || strlen(base) == 0) {
		time_t t = time(nullptr);
		fn.append(utils::mt_strf_localtime("%Y-%b-%d-%H%M%S.unknown", t));
	} else {
		fn.append(utils::replace_all(base, "'", "%27"));
	}
	return fn;
}

} // namespace podboat
<|endoftext|>


<commit_before>#include "regularizer.hpp"
#include <iostream>

namespace deconvolution {

void incrementBase(const std::vector<int>& extents, int subproblem, std::vector<int>& base) {
    for (int pos = 0; pos < int(extents.size()); ++pos) {
        if (pos == subproblem)
            continue;
        base[pos]++;
        if (base[pos] < extents[pos])
            return;
        else
            base[pos] = 0;
    }
}

template <int D>
double GridRegularizer<D>::evaluate(int subproblem, const double* lambda_a, double smoothing, double lambdaScale, double* gradient) const {
    assert(subproblem >= 0 && subproblem < D);
    double objective = 0;

    std::vector<int> lambdaExtents = _extents;
    lambdaExtents.push_back(numLabels());
    assert(lambdaExtents.size() == D+1);
    auto L = boost::const_multi_array_ref<double, D+1>{lambda_a, lambdaExtents};
    auto G = boost::multi_array_ref<double, D+1>{gradient, lambdaExtents};

    int width = _extents[subproblem]; // Length along this dimension of the grid
    std::vector<int> base(D, 0);
    int numBases = 1;
    for (int i = 0; i < D; ++i)
        numBases *= (i == subproblem) ? 1 : _extents[i];

    std::vector<double> lambdaSlice(_numLabels*width, 0);
    std::vector<double> m_L(_numLabels*width, 0);
    std::vector<double> m_R(_numLabels*width, 0);
    std::vector<double> logMarg(_numLabels, 0);
    std::vector<double> labelCosts(_numLabels, 0);
    const double smoothingMult = 1.0/smoothing;
    for (int countBase = 0; countBase < numBases; ++countBase, incrementBase(_extents, subproblem, base)) {
        int baseIdx = 0;
        for (int i = 0; i < D; ++i) baseIdx += base[i]*L.strides()[i];
        int stride = L.strides()[subproblem];
        assert(L.strides()[D] == 1);
        /*
        std::cout << "\tbase: ";
        for (auto idx : base) std::cout << idx << " ";
        std::cout << "\n";
        */

        for (int j = 0; j < width; ++j)
            for (int l = 0; l < _numLabels; ++l)
                lambdaSlice[j*_numLabels + l] = L.data()[baseIdx + j*stride + l];

        // Compute log m_L
        // Base step
        for (int l = 0; l < _numLabels; ++l)
            m_L[l] = lambdaScale*smoothingMult*lambdaSlice[l];
        // Inductive step
        for (int j = 1; j < width; ++j) {
            for (int lCurr = 0; lCurr < _numLabels; ++lCurr) {
                double maxMessage = std::numeric_limits<double>::lowest();
                double domainLCurr = _getLabel(baseIdx+j*stride, lCurr);
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev) {
                    double domainLPrev = _getLabel(j-1, lPrev);
                    labelCosts[lPrev] = -_edgeFn(domainLPrev, domainLCurr)*smoothingMult + m_L[(j-1)*_numLabels+lPrev];
                    maxMessage = std::max(maxMessage, labelCosts[lPrev]);
                }
                double sumExp = 0;
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev)
                    sumExp += exp(labelCosts[lPrev] - maxMessage);
                m_L[j*_numLabels+lCurr] = lambdaScale*lambdaSlice[j*_numLabels+lCurr]*smoothingMult + maxMessage + log(sumExp);
            }
        }

        // Compute log m_R
        for (int lCurr = 0; lCurr < _numLabels; ++lCurr)
            m_R[(width-1)*_numLabels+lCurr] = 0.0;
        for (int j = width-2; j >= 0; --j) {
            for (int lCurr = 0; lCurr < _numLabels; ++lCurr) {
                double maxMessage = std::numeric_limits<double>::lowest();
                double domainLCurr = _getLabel(j, lCurr);
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev) {
                    double domainLPrev = _getLabel(j+1, lPrev);
                    labelCosts[lPrev] = -(_edgeFn(domainLCurr, domainLPrev) - lambdaScale*lambdaSlice[(j+1)*_numLabels+lPrev])*smoothingMult + m_R[(j+1)*_numLabels+lPrev];
                    maxMessage = std::max(maxMessage, labelCosts[lPrev]);
                }
                double sumExp = 0;
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev)
                    sumExp += exp(labelCosts[lPrev] - maxMessage);
                m_R[j*_numLabels+lCurr] = maxMessage + log(sumExp);
            }
        }

        // Compute marginals, put them in G
        double logSumExp = 0;
        for (int j = 0; j < width; ++j) {
            double maxMarg = std::numeric_limits<double>::lowest();
            for (int l = 0; l < _numLabels; ++l) {
                logMarg[l] = m_L[j*_numLabels+l] + m_R[j*_numLabels+l];
                maxMarg = std::max(maxMarg, logMarg[l]);
            }
            double sumExp = 0;
            for (int l = 0; l < _numLabels; ++l)
                sumExp += exp(logMarg[l] - maxMarg);
            logSumExp = maxMarg + log(sumExp);
            for (int l = 0; l < _numLabels; ++l)
                G.data()[baseIdx + j*stride + l] = -lambdaScale*exp(logMarg[l] - logSumExp);
        }
        objective += -smoothing*logSumExp;
    }
    return objective;
}

template <int D>
double GridRegularizer<D>::primal(const double* x) const {
    double objective = 0;
    const auto X = boost::const_multi_array_ref<double, D>{x, _extents};

    for (int subproblem = 0; subproblem < D; ++subproblem) {
        int width = _extents[subproblem]; // Length along this dimension of the grid
        std::vector<int> base(D, 0);
        int numBases = 1;
        for (int i = 0; i < D; ++i)
            numBases *= (i == subproblem) ? 1 : _extents[i];

        for (int countBase = 0; countBase < numBases; ++countBase, incrementBase(_extents, subproblem, base)) {
            int baseIdx = 0;
            for (int i = 0; i < D; ++i) baseIdx += base[i]*X.strides()[i];
            int stride = X.strides()[subproblem];
            for (int i = 0; i < width-1; ++i) {
                objective += _edgeFn(x[baseIdx+i*stride], x[baseIdx+(i+1)*stride]);
            }
        }
    }
    return objective;
}

#define INSTANTIATE_DECONVOLVE_REGULARIZER(d) \
    template class GridRegularizer<d>;
INSTANTIATE_DECONVOLVE_REGULARIZER(1)
INSTANTIATE_DECONVOLVE_REGULARIZER(2)
INSTANTIATE_DECONVOLVE_REGULARIZER(3)
#undef INSTANTIATE_DECONVOLVE_REGULARIZER

}
<commit_msg>Fixing bug in _getLabel calls<commit_after>#include "regularizer.hpp"
#include <iostream>

namespace deconvolution {

void incrementBase(const std::vector<int>& extents, int subproblem, std::vector<int>& base) {
    for (int pos = 0; pos < int(extents.size()); ++pos) {
        if (pos == subproblem)
            continue;
        base[pos]++;
        if (base[pos] < extents[pos])
            return;
        else
            base[pos] = 0;
    }
}

template <int D>
double GridRegularizer<D>::evaluate(int subproblem, const double* lambda_a, double smoothing, double lambdaScale, double* gradient) const {
    assert(subproblem >= 0 && subproblem < D);
    double objective = 0;

    std::vector<int> lambdaExtents = _extents;
    lambdaExtents.push_back(numLabels());
    assert(lambdaExtents.size() == D+1);
    auto L = boost::const_multi_array_ref<double, D+1>{lambda_a, lambdaExtents};
    auto G = boost::multi_array_ref<double, D+1>{gradient, lambdaExtents};

    int width = _extents[subproblem]; // Length along this dimension of the grid
    std::vector<int> base(D, 0);
    int numBases = 1;
    for (int i = 0; i < D; ++i)
        numBases *= (i == subproblem) ? 1 : _extents[i];

    std::vector<double> lambdaSlice(_numLabels*width, 0);
    std::vector<double> m_L(_numLabels*width, 0);
    std::vector<double> m_R(_numLabels*width, 0);
    std::vector<double> logMarg(_numLabels, 0);
    std::vector<double> labelCosts(_numLabels, 0);
    const double smoothingMult = 1.0/smoothing;
    for (int countBase = 0; countBase < numBases; ++countBase, incrementBase(_extents, subproblem, base)) {
        int baseIdx = 0;
        for (int i = 0; i < D; ++i) baseIdx += base[i]*L.strides()[i];
        int stride = L.strides()[subproblem];
        assert(L.strides()[D] == 1);
        /*
        std::cout << "\tbase: ";
        for (auto idx : base) std::cout << idx << " ";
        std::cout << "\n";
        */

        for (int j = 0; j < width; ++j)
            for (int l = 0; l < _numLabels; ++l)
                lambdaSlice[j*_numLabels + l] = L.data()[baseIdx + j*stride + l];

        // Compute log m_L
        // Base step
        for (int l = 0; l < _numLabels; ++l)
            m_L[l] = lambdaScale*smoothingMult*lambdaSlice[l];
        // Inductive step
        for (int j = 1; j < width; ++j) {
            int idx = baseIdx+j*stride;
            for (int lCurr = 0; lCurr < _numLabels; ++lCurr) {
                double maxMessage = std::numeric_limits<double>::lowest();
                double domainLCurr = _getLabel(idx, lCurr);
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev) {
                    double domainLPrev = _getLabel(idx-stride, lPrev);
                    labelCosts[lPrev] = -_edgeFn(domainLPrev, domainLCurr)*smoothingMult + m_L[(j-1)*_numLabels+lPrev];
                    maxMessage = std::max(maxMessage, labelCosts[lPrev]);
                }
                double sumExp = 0;
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev)
                    sumExp += exp(labelCosts[lPrev] - maxMessage);
                m_L[j*_numLabels+lCurr] = lambdaScale*lambdaSlice[j*_numLabels+lCurr]*smoothingMult + maxMessage + log(sumExp);
            }
        }

        // Compute log m_R
        for (int lCurr = 0; lCurr < _numLabels; ++lCurr)
            m_R[(width-1)*_numLabels+lCurr] = 0.0;
        for (int j = width-2; j >= 0; --j) {
            int idx = baseIdx+j*stride;
            for (int lCurr = 0; lCurr < _numLabels; ++lCurr) {
                double maxMessage = std::numeric_limits<double>::lowest();
                double domainLCurr = _getLabel(idx, lCurr);
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev) {
                    double domainLPrev = _getLabel(idx+stride, lPrev);
                    labelCosts[lPrev] = -(_edgeFn(domainLCurr, domainLPrev) - lambdaScale*lambdaSlice[(j+1)*_numLabels+lPrev])*smoothingMult + m_R[(j+1)*_numLabels+lPrev];
                    maxMessage = std::max(maxMessage, labelCosts[lPrev]);
                }
                double sumExp = 0;
                for (int lPrev = 0; lPrev < _numLabels; ++lPrev)
                    sumExp += exp(labelCosts[lPrev] - maxMessage);
                m_R[j*_numLabels+lCurr] = maxMessage + log(sumExp);
            }
        }

        // Compute marginals, put them in G
        double logSumExp = 0;
        for (int j = 0; j < width; ++j) {
            double maxMarg = std::numeric_limits<double>::lowest();
            for (int l = 0; l < _numLabels; ++l) {
                logMarg[l] = m_L[j*_numLabels+l] + m_R[j*_numLabels+l];
                maxMarg = std::max(maxMarg, logMarg[l]);
            }
            double sumExp = 0;
            for (int l = 0; l < _numLabels; ++l)
                sumExp += exp(logMarg[l] - maxMarg);
            logSumExp = maxMarg + log(sumExp);
            for (int l = 0; l < _numLabels; ++l)
                G.data()[baseIdx + j*stride + l] = -lambdaScale*exp(logMarg[l] - logSumExp);
        }
        objective += -smoothing*logSumExp;
    }
    return objective;
}

template <int D>
double GridRegularizer<D>::primal(const double* x) const {
    double objective = 0;
    const auto X = boost::const_multi_array_ref<double, D>{x, _extents};

    for (int subproblem = 0; subproblem < D; ++subproblem) {
        int width = _extents[subproblem]; // Length along this dimension of the grid
        std::vector<int> base(D, 0);
        int numBases = 1;
        for (int i = 0; i < D; ++i)
            numBases *= (i == subproblem) ? 1 : _extents[i];

        for (int countBase = 0; countBase < numBases; ++countBase, incrementBase(_extents, subproblem, base)) {
            int baseIdx = 0;
            for (int i = 0; i < D; ++i) baseIdx += base[i]*X.strides()[i];
            int stride = X.strides()[subproblem];
            for (int i = 0; i < width-1; ++i) {
                objective += _edgeFn(x[baseIdx+i*stride], x[baseIdx+(i+1)*stride]);
            }
        }
    }
    return objective;
}

#define INSTANTIATE_DECONVOLVE_REGULARIZER(d) \
    template class GridRegularizer<d>;
INSTANTIATE_DECONVOLVE_REGULARIZER(1)
INSTANTIATE_DECONVOLVE_REGULARIZER(2)
INSTANTIATE_DECONVOLVE_REGULARIZER(3)
#undef INSTANTIATE_DECONVOLVE_REGULARIZER

}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may 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.
//
// Author: nadavs@google.com <Nadav Samet>

#include "rpcz/reactor.hpp"
#include <signal.h>
#include <vector>
#include "rpcz/callback.hpp"
#include "rpcz/clock.hpp"
#include "rpcz/logging.hpp"
#include "rpcz/macros.hpp"
#include "zmq.hpp"

namespace rpcz {
namespace {
static bool g_interrupted = false;
void signal_handler(int signal_value) {
  g_interrupted = true;
}
}  // unnamed namespace

reactor::reactor() : should_quit_(false) {
};

reactor::~reactor() {
  delete_container_pair_pointers(sockets_.begin(), sockets_.end());
  for (closure_run_map::const_iterator it = closure_run_map_.begin();
       it != closure_run_map_.end(); ++it) {
    delete_container_pointers(it->second.begin(), it->second.end());
  }
}

void reactor::add_socket(zmq::socket_t* socket, closure* closure) {
  sockets_.push_back(std::make_pair(socket, closure));
  is_dirty_ = true;
}

namespace {
void rebuild_poll_items(
    const std::vector<std::pair<zmq::socket_t*, closure*> >& sockets,
    std::vector<zmq::pollitem_t>* pollitems) {
  pollitems->resize(sockets.size());
  for (size_t i = 0; i < sockets.size(); ++i) {
    zmq::socket_t& socket = *sockets[i].first;
    zmq::pollitem_t pollitem = {socket, 0, ZMQ_POLLIN, 0};
    (*pollitems)[i] = pollitem;
  }
}
}  // namespace

void reactor::run_closure_at(uint64 timestamp, closure* closure) {
  closure_run_map_[timestamp].push_back(closure);
}

int reactor::loop() {
  while (!should_quit_ || !closure_run_map_.empty()) {
    if (is_dirty_) {
      rebuild_poll_items(sockets_, &pollitems_);
      is_dirty_ = false;
    }
    long poll_timeout = process_closure_run_map();

    if (should_quit_) continue;
    int rc = zmq_poll(&pollitems_[0], pollitems_.size(), poll_timeout);
    if (rc == -1) {
      int zmq_err = zmq_errno();
      CHECK_NE(zmq_err, EFAULT);
      if (zmq_err == ETERM) {
        return -1;
      }
    }
    for (size_t i = 0; i < pollitems_.size(); ++i) {
      if (!pollitems_[i].revents & ZMQ_POLLIN) {
        continue;
      }
      pollitems_[i].revents = 0;
      sockets_[i].second->run();
    }
  }
  if (g_interrupted) {
    return -1;
  } else {
    return 0;
  }
}

long reactor::process_closure_run_map() {
  uint64 now = zclock_time();
  closure_run_map::iterator ub(closure_run_map_.upper_bound(now));
  for (closure_run_map::const_iterator it = closure_run_map_.begin();
       it != ub;
       ++it) {
    for (std::vector<closure*>::const_iterator vit = it->second.begin();
         vit != it->second.end(); ++vit) {
      (*vit)->run();
    }
  }
  long poll_timeout = -1;
  if (ub != closure_run_map_.end()) {
    poll_timeout = 1000 * (ub->first - now);
  }
  closure_run_map_.erase(closure_run_map_.begin(), ub);
  return poll_timeout;
}

void reactor::set_should_quit() {
  should_quit_ = true;
}

void install_signal_handler() {
  struct sigaction action;
  action.sa_handler = signal_handler;
  action.sa_flags = 0;
  sigemptyset(&action.sa_mask);
  sigaction(SIGINT, &action, NULL);
  sigaction(SIGTERM, &action, NULL);
}
}  // namespace rpcz
<commit_msg>make reactor quit even if it has unprocessed closures<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may 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.
//
// Author: nadavs@google.com <Nadav Samet>

#include "rpcz/reactor.hpp"
#include <signal.h>
#include <vector>
#include "rpcz/callback.hpp"
#include "rpcz/clock.hpp"
#include "rpcz/logging.hpp"
#include "rpcz/macros.hpp"
#include "zmq.hpp"

namespace rpcz {
namespace {
static bool g_interrupted = false;
void signal_handler(int signal_value) {
  g_interrupted = true;
}
}  // unnamed namespace

reactor::reactor() : should_quit_(false) {
};

reactor::~reactor() {
  delete_container_pair_pointers(sockets_.begin(), sockets_.end());
  for (closure_run_map::const_iterator it = closure_run_map_.begin();
       it != closure_run_map_.end(); ++it) {
    delete_container_pointers(it->second.begin(), it->second.end());
  }
}

void reactor::add_socket(zmq::socket_t* socket, closure* closure) {
  sockets_.push_back(std::make_pair(socket, closure));
  is_dirty_ = true;
}

namespace {
void rebuild_poll_items(
    const std::vector<std::pair<zmq::socket_t*, closure*> >& sockets,
    std::vector<zmq::pollitem_t>* pollitems) {
  pollitems->resize(sockets.size());
  for (size_t i = 0; i < sockets.size(); ++i) {
    zmq::socket_t& socket = *sockets[i].first;
    zmq::pollitem_t pollitem = {socket, 0, ZMQ_POLLIN, 0};
    (*pollitems)[i] = pollitem;
  }
}
}  // namespace

void reactor::run_closure_at(uint64 timestamp, closure* closure) {
  closure_run_map_[timestamp].push_back(closure);
}

int reactor::loop() {
  while (!should_quit_) {
    if (is_dirty_) {
      rebuild_poll_items(sockets_, &pollitems_);
      is_dirty_ = false;
    }
    long poll_timeout = process_closure_run_map();
    int rc = zmq_poll(&pollitems_[0], pollitems_.size(), poll_timeout);

    if (rc == -1) {
      int zmq_err = zmq_errno();
      CHECK_NE(zmq_err, EFAULT);
      if (zmq_err == ETERM) {
        return -1;
      }
    }
    for (size_t i = 0; i < pollitems_.size(); ++i) {
      if (!pollitems_[i].revents & ZMQ_POLLIN) {
        continue;
      }
      pollitems_[i].revents = 0;
      sockets_[i].second->run();
    }
  }
  if (g_interrupted) {
    return -1;
  } else {
    return 0;
  }
}

long reactor::process_closure_run_map() {
  uint64 now = zclock_time();
  closure_run_map::iterator ub(closure_run_map_.upper_bound(now));
  for (closure_run_map::const_iterator it = closure_run_map_.begin();
       it != ub;
       ++it) {
    for (std::vector<closure*>::const_iterator vit = it->second.begin();
         vit != it->second.end(); ++vit) {
      (*vit)->run();
    }
  }
  long poll_timeout = -1;
  if (ub != closure_run_map_.end()) {
    poll_timeout = 1000 * (ub->first - now);
  }
  closure_run_map_.erase(closure_run_map_.begin(), ub);
  return poll_timeout;
}

void reactor::set_should_quit() {
  should_quit_ = true;
}

void install_signal_handler() {
  struct sigaction action;
  action.sa_handler = signal_handler;
  action.sa_flags = 0;
  sigemptyset(&action.sa_mask);
  sigaction(SIGINT, &action, NULL);
  sigaction(SIGTERM, &action, NULL);
}
}  // namespace rpcz
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jack Maloney. All Rights Reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "voltz-internal.h"

double StartupTime;

int main(int argc, const char** argv) {

    clock_t begin, end;
    begin = clock();

    vz_bootstrap_runtime(argc, argv);

    end = clock();

    StartupTime = (end - begin) / CLOCKS_PER_SEC;

#ifdef VOLTZ_DEBUG
    printf("Took %f seconds to startup.\n", StartupTime);
#endif

    vz_linker_entry(nil, nil);

}
<commit_msg>Add needed header for travis-ci build<commit_after>// Copyright (C) 2015 Jack Maloney. All Rights Reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "voltz-internal.h"
#include <ctime>
#include <cstdio>

double StartupTime;

int main(int argc, const char** argv) {

    clock_t begin, end;
    begin = clock();

    vz_bootstrap_runtime(argc, argv);

    end = clock();

    StartupTime = (end - begin) / CLOCKS_PER_SEC;

#ifdef VOLTZ_DEBUG
    printf("Took %f seconds to startup.\n", StartupTime);
#endif

    vz_linker_entry(nil, nil);

}
<|endoftext|>


<commit_before>/**
 *  \file
 *  \remark This file is part of VITA.
 *
 *  \copyright Copyright (C) 2015-2017 EOS di Manlio Morini.
 *
 *  \license
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this file,
 *  You can obtain one at http://mozilla.org/MPL/2.0/
 */

#include <cstdlib>
#include <sstream>

#include "kernel/ga/evaluator.h"
#include "kernel/ga/i_de.h"
#include "kernel/ga/search.h"
#include "kernel/evolution.h"
#include "kernel/problem.h"

#if !defined(MASTER_TEST_SET)
#define BOOST_TEST_MODULE t_de_perf
#include <boost/test/unit_test.hpp>

using namespace boost;

#include "factory_fixture5.h"
#endif

BOOST_FIXTURE_TEST_SUITE(t_de7, F_FACTORY5_NO_INIT)

// Test problem 7 from "An Efficient Constraint Handling Method for Genetic
// Algorithms"
BOOST_AUTO_TEST_CASE(Search_TestProblem7, * boost::unit_test::tolerance(1.0))
{
  vita::print.verbosity(vita::log::L_WARNING);

  vita::problem prob;
  prob.env.individuals = 100;
  prob.env.generations = 2000;
  prob.env.threshold.fitness = {0, 0};
  prob.env.stat.dir = ".";
  prob.env.stat.layers = true;
  prob.sset.insert(vita::ga::parameter(0, -2.3, 2.3));
  prob.sset.insert(vita::ga::parameter(1, -2.3, 2.3));
  prob.sset.insert(vita::ga::parameter(2, -3.2, 3.2));
  prob.sset.insert(vita::ga::parameter(3, -3.2, 3.2));
  prob.sset.insert(vita::ga::parameter(4, -3.2, 3.2));

  auto f = [](const std::vector<double> &x)
           {
             return -std::exp(x[0] * x[1] * x[2] * x[3] * x[4]);
           };

  auto p = [](const vita::i_de &prg)
    {
      auto h1 = [](const std::vector<double> &x)
      {
        return x[0] * x[0] + x[1] * x[1] + x[2] * x[2] + x[3] * x[3] +
               x[4] * x[4] - 10.0;
      };
      auto h2 = [](const std::vector<double> &x)
      {
        return x[1] * x[2] - 5.0 * x[3] * x[4];
      };
      auto h3 = [](const std::vector<double> &x)
      {
        return x[0] * x[0] * x[0] + x[1] * x[1] * x[1] + 1.0;
      };

      const double delta(0.01);

      double r(0.0);

      const auto c1(std::abs(h1(prg)));
      if (c1 > delta)
        r += c1;

      const auto c2(std::abs(h2(prg)));
      if (c2 > delta)
        r += c2;

      const auto c3(std::abs(h3(prg)));
      if (c3 > delta)
        r += c3;

      for (const auto &pi : prg)
      {
        if (pi < -2.3)
          r += -2.3 - pi;
        else if (pi > 3.2)
          r += pi - 3.2;
      }

      return r;
    };

  vita::ga_search<vita::i_de, vita::de_es, decltype(f)> s(prob, f, p);
  BOOST_TEST(s.debug());
  const auto res(s.run(10).best.solution);

  BOOST_TEST(-f(res) == 0.053950);
  BOOST_TEST(res[0] == -1.717143);
  BOOST_TEST(res[1] == 1.595709);
  BOOST_TEST(res[2] == 1.827247);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>[FIX] ga_perf compilation error<commit_after>/**
 *  \file
 *  \remark This file is part of VITA.
 *
 *  \copyright Copyright (C) 2015-2017 EOS di Manlio Morini.
 *
 *  \license
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this file,
 *  You can obtain one at http://mozilla.org/MPL/2.0/
 */

#include <cstdlib>
#include <sstream>

#include "kernel/ga/evaluator.h"
#include "kernel/ga/i_de.h"
#include "kernel/ga/search.h"
#include "kernel/evolution.h"
#include "kernel/problem.h"

#if !defined(MASTER_TEST_SET)
#define BOOST_TEST_MODULE t_de_perf
#include <boost/test/unit_test.hpp>

using namespace boost;

#include "factory_fixture5.h"
#endif

BOOST_FIXTURE_TEST_SUITE(t_de7, F_FACTORY5_NO_INIT)

// Test problem 7 from "An Efficient Constraint Handling Method for Genetic
// Algorithms"
BOOST_AUTO_TEST_CASE(Search_TestProblem7, * boost::unit_test::tolerance(1.0))
{
  vita::print.verbosity(vita::log::L_WARNING);

  prob.env.individuals = 100;
  prob.env.generations = 2000;
  prob.env.threshold.fitness = {0, 0};
  prob.sset.insert(vita::ga::parameter(0, -2.3, 2.3));
  prob.sset.insert(vita::ga::parameter(1, -2.3, 2.3));
  prob.sset.insert(vita::ga::parameter(2, -3.2, 3.2));
  prob.sset.insert(vita::ga::parameter(3, -3.2, 3.2));
  prob.sset.insert(vita::ga::parameter(4, -3.2, 3.2));

  auto f = [](const std::vector<double> &x)
  {
    return -std::exp(x[0] * x[1] * x[2] * x[3] * x[4]);
  };

  auto p = [](const vita::i_de &prg)
  {
    auto h1 = [](const std::vector<double> &x)
    {
      return x[0] * x[0] + x[1] * x[1] + x[2] * x[2] + x[3] * x[3] +
      x[4] * x[4] - 10.0;
    };
    auto h2 = [](const std::vector<double> &x)
    {
      return x[1] * x[2] - 5.0 * x[3] * x[4];
    };
    auto h3 = [](const std::vector<double> &x)
    {
      return x[0] * x[0] * x[0] + x[1] * x[1] * x[1] + 1.0;
    };

    const double delta(0.01);

    double r(0.0);

    const auto c1(std::abs(h1(prg)));
    if (c1 > delta)
      r += c1;

    const auto c2(std::abs(h2(prg)));
    if (c2 > delta)
      r += c2;

    const auto c3(std::abs(h3(prg)));
    if (c3 > delta)
      r += c3;

    for (const auto &pi : prg)
    {
      if (pi < -2.3)
        r += -2.3 - pi;
      else if (pi > 3.2)
        r += pi - 3.2;
    }

    return r;
  };

  vita::ga_search<vita::i_de, vita::de_es, decltype(f)> s(prob, f, p);
  BOOST_TEST(s.debug());
  const auto res(s.run(10).best.solution);

  BOOST_TEST(-f(res) == 0.053950);
  BOOST_TEST(res[0] == -1.717143);
  BOOST_TEST(res[1] == 1.595709);
  BOOST_TEST(res[2] == 1.827247);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/**
 *  @file   string_util.cpp
 *  @brief  Utility function for string handling
 *
 *  @author Christophe Ecabert
 *  @date   26/08/16
 *  Copyright © 2016 Christophe Ecabert. All rights reserved.
 */

#include "facekit/core/string_util.hpp"

/**
 *  @namespace  FaceKit
 *  @brief      Development space
 */
namespace FaceKit {

/*
 *  @name Split
 *  @fn static void Split(const std::string& string,
                         const std::string delimiter,
                         std::vector<std::string>* parts);
 *  @brief  Split a given \p string into parts for a specific delimiter
 *  @param[in]  string    String to split
 *  @param[in]  delimiter Delimiter
 *  @param[out] parts     Splitted parts
 */
void StringUtil::Split(const std::string& string,
                       const std::string delimiter,
                       std::vector<std::string>* parts) {
  std::size_t from = 0;
  std::size_t idx;
  do {
    idx = string.find(delimiter, from);
    if (idx != std::string::npos) {
      parts->push_back(string.substr(from, idx - from));
      from = idx + delimiter.length();
    } else {
      parts->push_back(string.substr(from, string.length() - from));
    }
  } while(idx != std::string::npos);
}

/*
 *  @name ExtractDirectory
 *  @fn
 *  @brief  Split path into directory + extension
 *  @param[in]  path  Path where to extract data
 *  @param[out] dir   Extracted directory
 *  @param[out] ext   Extracted extension
 */
void StringUtil::ExtractDirectory(const std::string& path,
                                  std::string* dir,
                                  std::string* file,
                                  std::string* ext) {
  auto pdir = path.rfind("/");
  if (pdir != std::string::npos) {
    pdir += 1;
    *dir = path.substr(0, pdir);
  } else {
    pdir = 0;
  }
  auto pext = path.rfind(".");
  if (pext != std::string::npos) {
    *file = path.substr(pdir, pext - pdir);
    *ext = path.substr(pext + 1, path.length() - pext - 1);
  } else {
    *file = path.substr(pdir);
  }
}

/*
 *  @name   LeadingZero
 *  @fn     static std::string LeadingZero(const T number, const size_t N)
 *  @brief  Convert a number to string and complete it with leading zeros if
 *          needed
 *  @param[in]  number  Number to convert to string
 *  @param[in]  N       Number total of char wanted (i.e. N=3, number=12
 *                      -> 012)
 *  @tparam T Data type
 */
template<typename T>
std::string StringUtil::LeadingZero(const T number, const size_t N) {
  std::string num = std::to_string(number);
  return std::string(N - num.length(), '0') + num;
}

template std::string StringUtil::LeadingZero(const int8_t, size_t);
template std::string StringUtil::LeadingZero(const uint8_t, size_t);
template std::string StringUtil::LeadingZero(const int16_t, size_t);
template std::string StringUtil::LeadingZero(const uint16_t, size_t);
template std::string StringUtil::LeadingZero(const int32_t, size_t);
template std::string StringUtil::LeadingZero(const uint32_t, size_t);
template std::string StringUtil::LeadingZero(const int64_t, size_t);
template std::string StringUtil::LeadingZero(const uint64_t, size_t);
template std::string StringUtil::LeadingZero(const size_t, size_t);

}  // namespace FaceKit
<commit_msg>CHG: Remove int64_t from StringUtil::LeadingZero(...)<commit_after>/**
 *  @file   string_util.cpp
 *  @brief  Utility function for string handling
 *
 *  @author Christophe Ecabert
 *  @date   26/08/16
 *  Copyright © 2016 Christophe Ecabert. All rights reserved.
 */

#include "facekit/core/string_util.hpp"

/**
 *  @namespace  FaceKit
 *  @brief      Development space
 */
namespace FaceKit {

/*
 *  @name Split
 *  @fn static void Split(const std::string& string,
                         const std::string delimiter,
                         std::vector<std::string>* parts);
 *  @brief  Split a given \p string into parts for a specific delimiter
 *  @param[in]  string    String to split
 *  @param[in]  delimiter Delimiter
 *  @param[out] parts     Splitted parts
 */
void StringUtil::Split(const std::string& string,
                       const std::string delimiter,
                       std::vector<std::string>* parts) {
  std::size_t from = 0;
  std::size_t idx;
  do {
    idx = string.find(delimiter, from);
    if (idx != std::string::npos) {
      parts->push_back(string.substr(from, idx - from));
      from = idx + delimiter.length();
    } else {
      parts->push_back(string.substr(from, string.length() - from));
    }
  } while(idx != std::string::npos);
}

/*
 *  @name ExtractDirectory
 *  @fn
 *  @brief  Split path into directory + extension
 *  @param[in]  path  Path where to extract data
 *  @param[out] dir   Extracted directory
 *  @param[out] ext   Extracted extension
 */
void StringUtil::ExtractDirectory(const std::string& path,
                                  std::string* dir,
                                  std::string* file,
                                  std::string* ext) {
  auto pdir = path.rfind("/");
  if (pdir != std::string::npos) {
    pdir += 1;
    *dir = path.substr(0, pdir);
  } else {
    pdir = 0;
  }
  auto pext = path.rfind(".");
  if (pext != std::string::npos) {
    *file = path.substr(pdir, pext - pdir);
    *ext = path.substr(pext + 1, path.length() - pext - 1);
  } else {
    *file = path.substr(pdir);
  }
}

/*
 *  @name   LeadingZero
 *  @fn     static std::string LeadingZero(const T number, const size_t N)
 *  @brief  Convert a number to string and complete it with leading zeros if
 *          needed
 *  @param[in]  number  Number to convert to string
 *  @param[in]  N       Number total of char wanted (i.e. N=3, number=12
 *                      -> 012)
 *  @tparam T Data type
 */
template<typename T>
std::string StringUtil::LeadingZero(const T number, const size_t N) {
  std::string num = std::to_string(number);
  return std::string(N - num.length(), '0') + num;
}

template std::string StringUtil::LeadingZero(const int8_t, size_t);
template std::string StringUtil::LeadingZero(const uint8_t, size_t);
template std::string StringUtil::LeadingZero(const int16_t, size_t);
template std::string StringUtil::LeadingZero(const uint16_t, size_t);
template std::string StringUtil::LeadingZero(const int32_t, size_t);
template std::string StringUtil::LeadingZero(const uint32_t, size_t);
template std::string StringUtil::LeadingZero(const size_t, size_t);

}  // namespace FaceKit
<|endoftext|>


<commit_before>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#include "test_precomp.hpp"

using namespace cv;

namespace {

static const char * const keys =
    "{ h help    |       | print help }"
    "{ i info    | false | print info }"
    "{ t true    | true  | true value }"
    "{ n unused  |       | dummy }"
;

TEST(CommandLineParser, testFailure)
{
    const char* argv[] = {"<bin>", "-q"};
    const int argc = 2;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_ANY_THROW(parser.has("q"));
    EXPECT_ANY_THROW(parser.get<bool>("q"));
    EXPECT_ANY_THROW(parser.get<bool>(0));

    parser.get<bool>("h");
    EXPECT_FALSE(parser.check());
}
TEST(CommandLineParser, testHas_noValues)
{
    const char* argv[] = {"<bin>", "-h", "--info"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_TrueValues)
{
    const char* argv[] = {"<bin>", "-h=TRUE", "--info=true"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_TrueValues1)
{
    const char* argv[] = {"<bin>", "-h=1", "--info=1"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_FalseValues0)
{
    const char* argv[] = {"<bin>", "-h=0", "--info=0"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}

TEST(CommandLineParser, testBoolOption_noArgs)
{
    const char* argv[] = {"<bin>"};
    const int argc = 1;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_FALSE(parser.get<bool>("help"));
    EXPECT_FALSE(parser.get<bool>("h"));
    EXPECT_FALSE(parser.get<bool>("info"));
    EXPECT_FALSE(parser.get<bool>("i"));
    EXPECT_TRUE(parser.get<bool>("true")); // default is true
    EXPECT_TRUE(parser.get<bool>("t"));
}

TEST(CommandLineParser, testBoolOption_noValues)
{
    const char* argv[] = {"<bin>", "-h", "--info"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.get<bool>("help"));
    EXPECT_TRUE(parser.get<bool>("h"));
    EXPECT_TRUE(parser.get<bool>("info"));
    EXPECT_TRUE(parser.get<bool>("i"));
}

TEST(CommandLineParser, testBoolOption_TrueValues)
{
    const char* argv[] = {"<bin>", "-h=TRUE", "--info=true"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    //EXPECT_TRUE(parser.get<bool>("help"));
    //EXPECT_TRUE(parser.get<bool>("h"));
    EXPECT_TRUE(parser.get<bool>("info"));
    EXPECT_TRUE(parser.get<bool>("i"));
    EXPECT_FALSE(parser.get<bool>("unused"));
    EXPECT_FALSE(parser.get<bool>("n"));
}

TEST(CommandLineParser, testBoolOption_FalseValues)
{
    const char* argv[] = {"<bin>", "--help=FALSE", "-i=false"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_FALSE(parser.get<bool>("help"));
    EXPECT_FALSE(parser.get<bool>("h"));
    EXPECT_FALSE(parser.get<bool>("info"));
    EXPECT_FALSE(parser.get<bool>("i"));
}

static const char * const keys2 =
    "{ h help    |          | print help }"
    "{ @arg1     | default1 | param1 }"
    "{ @arg2     |          | param2 }"
    "{ n unused  |          | dummy }"
;

TEST(CommandLineParser, testPositional_noArgs)
{
    const char* argv[] = {"<bin>"};
    const int argc = 1;
    cv::CommandLineParser parser(argc, argv, keys2);
    //EXPECT_FALSE(parser.has("arg1"));
    //EXPECT_FALSE(parser.has("arg2"));
    //EXPECT_EQ("default1", parser.get<String>("arg1"));
    EXPECT_EQ("default1", parser.get<String>(0));
    //??? EXPECT_ANY_THROW(parser.get<String>("arg2"));
    //??? EXPECT_ANY_THROW(parser.get<String>(1));
}

TEST(CommandLineParser, testPositional_default)
{
    const char* argv[] = {"<bin>", "test1", "test2"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys2);
    //EXPECT_TRUE(parser.has("arg1"));
    //EXPECT_TRUE(parser.has("arg2"));
    //EXPECT_EQ("test1", parser.get<String>("arg1"));
    //EXPECT_EQ("test2", parser.get<String>("arg2"));
    EXPECT_EQ("test1", parser.get<String>(0));
    EXPECT_EQ("test2", parser.get<String>(1));
}

TEST(CommandLineParser, testPositional_withFlagsBefore)
{
    const char* argv[] = {"<bin>", "-h", "test1", "test2"};
    const int argc = 4;
    cv::CommandLineParser parser(argc, argv, keys2);
    //EXPECT_TRUE(parser.has("arg1"));
    //EXPECT_TRUE(parser.has("arg2"));
    //EXPECT_EQ("test1", parser.get<String>("arg1"));
    //EXPECT_EQ("test2", parser.get<String>("arg2"));
    EXPECT_EQ("test1", parser.get<String>(0));
    EXPECT_EQ("test2", parser.get<String>(1));
}

TEST(CommandLineParser, testPositional_withFlagsAfter)
{
    const char* argv[] = {"<bin>", "test1", "test2", "-h"};
    const int argc = 4;
    cv::CommandLineParser parser(argc, argv, keys2);
    //EXPECT_TRUE(parser.has("arg1"));
    //EXPECT_TRUE(parser.has("arg2"));
    //EXPECT_EQ("test1", parser.get<String>("arg1"));
    //EXPECT_EQ("test2", parser.get<String>("arg2"));
    EXPECT_EQ("test1", parser.get<String>(0));
    EXPECT_EQ("test2", parser.get<String>(1));
}

} // namespace
<commit_msg>enable additional CommandLineParser tests<commit_after>// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.

#include "test_precomp.hpp"

using namespace cv;

namespace {

static const char * const keys =
    "{ h help    |       | print help }"
    "{ i info    | false | print info }"
    "{ t true    | true  | true value }"
    "{ n unused  |       | dummy }"
;

TEST(CommandLineParser, testFailure)
{
    const char* argv[] = {"<bin>", "-q"};
    const int argc = 2;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_ANY_THROW(parser.has("q"));
    EXPECT_ANY_THROW(parser.get<bool>("q"));
    EXPECT_ANY_THROW(parser.get<bool>(0));

    parser.get<bool>("h");
    EXPECT_FALSE(parser.check());
}
TEST(CommandLineParser, testHas_noValues)
{
    const char* argv[] = {"<bin>", "-h", "--info"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_TrueValues)
{
    const char* argv[] = {"<bin>", "-h=TRUE", "--info=true"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_TrueValues1)
{
    const char* argv[] = {"<bin>", "-h=1", "--info=1"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}
TEST(CommandLineParser, testHas_FalseValues0)
{
    const char* argv[] = {"<bin>", "-h=0", "--info=0"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.has("help"));
    EXPECT_TRUE(parser.has("h"));
    EXPECT_TRUE(parser.has("info"));
    EXPECT_TRUE(parser.has("i"));
    EXPECT_FALSE(parser.has("n"));
    EXPECT_FALSE(parser.has("unused"));
}

TEST(CommandLineParser, testBoolOption_noArgs)
{
    const char* argv[] = {"<bin>"};
    const int argc = 1;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_FALSE(parser.get<bool>("help"));
    EXPECT_FALSE(parser.get<bool>("h"));
    EXPECT_FALSE(parser.get<bool>("info"));
    EXPECT_FALSE(parser.get<bool>("i"));
    EXPECT_TRUE(parser.get<bool>("true")); // default is true
    EXPECT_TRUE(parser.get<bool>("t"));
}

TEST(CommandLineParser, testBoolOption_noValues)
{
    const char* argv[] = {"<bin>", "-h", "--info"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_TRUE(parser.get<bool>("help"));
    EXPECT_TRUE(parser.get<bool>("h"));
    EXPECT_TRUE(parser.get<bool>("info"));
    EXPECT_TRUE(parser.get<bool>("i"));
}

TEST(CommandLineParser, testBoolOption_TrueValues)
{
    const char* argv[] = {"<bin>", "-h=TRUE", "--info=true"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    //EXPECT_TRUE(parser.get<bool>("help"));
    //EXPECT_TRUE(parser.get<bool>("h"));
    EXPECT_TRUE(parser.get<bool>("info"));
    EXPECT_TRUE(parser.get<bool>("i"));
    EXPECT_FALSE(parser.get<bool>("unused"));
    EXPECT_FALSE(parser.get<bool>("n"));
}

TEST(CommandLineParser, testBoolOption_FalseValues)
{
    const char* argv[] = {"<bin>", "--help=FALSE", "-i=false"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys);
    EXPECT_FALSE(parser.get<bool>("help"));
    EXPECT_FALSE(parser.get<bool>("h"));
    EXPECT_FALSE(parser.get<bool>("info"));
    EXPECT_FALSE(parser.get<bool>("i"));
}

static const char * const keys2 =
    "{ h help    |          | print help }"
    "{ @arg1     | default1 | param1 }"
    "{ @arg2     |          | param2 }"
    "{ n unused  |          | dummy }"
;

TEST(CommandLineParser, testPositional_noArgs)
{
    const char* argv[] = {"<bin>"};
    const int argc = 1;
    cv::CommandLineParser parser(argc, argv, keys2);
    EXPECT_TRUE(parser.has("@arg1"));
    EXPECT_FALSE(parser.has("@arg2"));
    EXPECT_EQ("default1", parser.get<String>("@arg1"));
    EXPECT_EQ("default1", parser.get<String>(0));

    parser.get<String>("@arg2");
    parser.get<String>(1);
    EXPECT_TRUE(parser.check());
}

TEST(CommandLineParser, testPositional_default)
{
    const char* argv[] = {"<bin>", "test1", "test2"};
    const int argc = 3;
    cv::CommandLineParser parser(argc, argv, keys2);
    EXPECT_TRUE(parser.has("@arg1"));
    EXPECT_TRUE(parser.has("@arg2"));
    EXPECT_EQ("test1", parser.get<String>("@arg1"));
    EXPECT_EQ("test2", parser.get<String>("@arg2"));
    EXPECT_EQ("test1", parser.get<String>(0));
    EXPECT_EQ("test2", parser.get<String>(1));
}

TEST(CommandLineParser, testPositional_withFlagsBefore)
{
    const char* argv[] = {"<bin>", "-h", "test1", "test2"};
    const int argc = 4;
    cv::CommandLineParser parser(argc, argv, keys2);
    EXPECT_TRUE(parser.has("@arg1"));
    EXPECT_TRUE(parser.has("@arg2"));
    EXPECT_EQ("test1", parser.get<String>("@arg1"));
    EXPECT_EQ("test2", parser.get<String>("@arg2"));
    EXPECT_EQ("test1", parser.get<String>(0));
    EXPECT_EQ("test2", parser.get<String>(1));
}

TEST(CommandLineParser, testPositional_withFlagsAfter)
{
    const char* argv[] = {"<bin>", "test1", "test2", "-h"};
    const int argc = 4;
    cv::CommandLineParser parser(argc, argv, keys2);
    EXPECT_TRUE(parser.has("@arg1"));
    EXPECT_TRUE(parser.has("@arg2"));
    EXPECT_EQ("test1", parser.get<String>("@arg1"));
    EXPECT_EQ("test2", parser.get<String>("@arg2"));
    EXPECT_EQ("test1", parser.get<String>(0));
    EXPECT_EQ("test2", parser.get<String>(1));
}

} // namespace
<|endoftext|>


<commit_before><commit_msg>C++11-only stdint.h SIZE_MAX -> std::numeric_limits<commit_after><|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

#define VERIFY_TRSM(TRI,XB) { \
    (XB).setRandom(); ref = (XB); \
    (TRI).solveInPlace(XB); \
    VERIFY_IS_APPROX((TRI).toDenseMatrix() * (XB), ref); \
  }

#define VERIFY_TRSM_ONTHERIGHT(TRI,XB) { \
    (XB).setRandom(); ref = (XB); \
    (TRI).transpose().template solveInPlace<OnTheRight>(XB.transpose()); \
    VERIFY_IS_APPROX((XB).transpose() * (TRI).transpose().toDenseMatrix(), ref.transpose()); \
  }

template<typename Scalar,int Size, int Cols> void trsolve(int size=Size,int cols=Cols)
{
  typedef typename NumTraits<Scalar>::Real RealScalar;

  Matrix<Scalar,Size,Size,ColMajor> cmLhs(size,size);
  Matrix<Scalar,Size,Size,RowMajor> rmLhs(size,size);

  enum {  colmajor = Size==1 ? RowMajor : ColMajor,
          rowmajor = Cols==1 ? ColMajor : RowMajor };
  Matrix<Scalar,Size,Cols,colmajor> cmRhs(size,cols), ref(size,cols);
  Matrix<Scalar,Size,Cols,rowmajor> rmRhs(size,cols);

  cmLhs.setRandom(); cmLhs *= static_cast<RealScalar>(0.1); cmLhs.diagonal().array() += static_cast<RealScalar>(1);
  rmLhs.setRandom(); rmLhs *= static_cast<RealScalar>(0.1); rmLhs.diagonal().array() += static_cast<RealScalar>(1);

  VERIFY_TRSM(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM(cmLhs            .template triangularView<Upper>(), cmRhs);
  VERIFY_TRSM(cmLhs            .template triangularView<Lower>(), rmRhs);
  VERIFY_TRSM(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);

  VERIFY_TRSM(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
  VERIFY_TRSM(cmLhs            .template triangularView<UnitUpper>(), rmRhs);

  VERIFY_TRSM(rmLhs            .template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);

  VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs            .template triangularView<Upper>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs            .template triangularView<Lower>(), rmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);

  VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs            .template triangularView<UnitUpper>(), rmRhs);

  VERIFY_TRSM_ONTHERIGHT(rmLhs            .template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);

  int c = internal::random<int>(0,cols-1);
  VERIFY_TRSM(rmLhs.template triangularView<Lower>(), rmRhs.col(c));
  VERIFY_TRSM(cmLhs.template triangularView<Lower>(), rmRhs.col(c));
}

void test_product_trsolve()
{
  for(int i = 0; i < g_repeat ; i++)
  {
    // matrices
    CALL_SUBTEST_1((trsolve<float,Dynamic,Dynamic>(internal::random<int>(1,320),internal::random<int>(1,320))));
    CALL_SUBTEST_2((trsolve<double,Dynamic,Dynamic>(internal::random<int>(1,320),internal::random<int>(1,320))));
    CALL_SUBTEST_3((trsolve<std::complex<float>,Dynamic,Dynamic>(internal::random<int>(1,200),internal::random<int>(1,200))));
    CALL_SUBTEST_4((trsolve<std::complex<double>,Dynamic,Dynamic>(internal::random<int>(1,200),internal::random<int>(1,200))));

    // vectors
    CALL_SUBTEST_1((trsolve<float,Dynamic,1>(internal::random<int>(1,320))));
    CALL_SUBTEST_5((trsolve<std::complex<double>,Dynamic,1>(internal::random<int>(1,320))));
    CALL_SUBTEST_6((trsolve<float,1,1>()));
    CALL_SUBTEST_7((trsolve<float,1,2>()));
    CALL_SUBTEST_8((trsolve<std::complex<float>,4,1>()));
  }
}
<commit_msg>extend unit test to cover previous bug<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

#define VERIFY_TRSM(TRI,XB) { \
    (XB).setRandom(); ref = (XB); \
    (TRI).solveInPlace(XB); \
    VERIFY_IS_APPROX((TRI).toDenseMatrix() * (XB), ref); \
  }

#define VERIFY_TRSM_ONTHERIGHT(TRI,XB) { \
    (XB).setRandom(); ref = (XB); \
    (TRI).transpose().template solveInPlace<OnTheRight>(XB.transpose()); \
    VERIFY_IS_APPROX((XB).transpose() * (TRI).transpose().toDenseMatrix(), ref.transpose()); \
  }

template<typename Scalar,int Size, int Cols> void trsolve(int size=Size,int cols=Cols)
{
  typedef typename NumTraits<Scalar>::Real RealScalar;

  Matrix<Scalar,Size,Size,ColMajor> cmLhs(size,size);
  Matrix<Scalar,Size,Size,RowMajor> rmLhs(size,size);

  enum {  colmajor = Size==1 ? RowMajor : ColMajor,
          rowmajor = Cols==1 ? ColMajor : RowMajor };
  Matrix<Scalar,Size,Cols,colmajor> cmRhs(size,cols), ref(size,cols);
  Matrix<Scalar,Size,Cols,rowmajor> rmRhs(size,cols);

  cmLhs.setRandom(); cmLhs *= static_cast<RealScalar>(0.1); cmLhs.diagonal().array() += static_cast<RealScalar>(1);
  rmLhs.setRandom(); rmLhs *= static_cast<RealScalar>(0.1); rmLhs.diagonal().array() += static_cast<RealScalar>(1);

  VERIFY_TRSM(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM(cmLhs.adjoint()  .template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM(cmLhs            .template triangularView<Upper>(), cmRhs);
  VERIFY_TRSM(cmLhs            .template triangularView<Lower>(), rmRhs);
  VERIFY_TRSM(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);
  VERIFY_TRSM(cmLhs.adjoint()  .template triangularView<Upper>(), rmRhs);

  VERIFY_TRSM(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
  VERIFY_TRSM(cmLhs            .template triangularView<UnitUpper>(), rmRhs);

  VERIFY_TRSM(rmLhs            .template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);

  VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs            .template triangularView<Upper>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs            .template triangularView<Lower>(), rmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<Upper>(), rmRhs);

  VERIFY_TRSM_ONTHERIGHT(cmLhs.conjugate().template triangularView<UnitLower>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(cmLhs            .template triangularView<UnitUpper>(), rmRhs);

  VERIFY_TRSM_ONTHERIGHT(rmLhs            .template triangularView<Lower>(), cmRhs);
  VERIFY_TRSM_ONTHERIGHT(rmLhs.conjugate().template triangularView<UnitUpper>(), rmRhs);

  int c = internal::random<int>(0,cols-1);
  VERIFY_TRSM(rmLhs.template triangularView<Lower>(), rmRhs.col(c));
  VERIFY_TRSM(cmLhs.template triangularView<Lower>(), rmRhs.col(c));
}

void test_product_trsolve()
{
  for(int i = 0; i < g_repeat ; i++)
  {
    // matrices
    CALL_SUBTEST_1((trsolve<float,Dynamic,Dynamic>(internal::random<int>(1,320),internal::random<int>(1,320))));
    CALL_SUBTEST_2((trsolve<double,Dynamic,Dynamic>(internal::random<int>(1,320),internal::random<int>(1,320))));
    CALL_SUBTEST_3((trsolve<std::complex<float>,Dynamic,Dynamic>(internal::random<int>(1,200),internal::random<int>(1,200))));
    CALL_SUBTEST_4((trsolve<std::complex<double>,Dynamic,Dynamic>(internal::random<int>(1,200),internal::random<int>(1,200))));

    // vectors
    CALL_SUBTEST_1((trsolve<float,Dynamic,1>(internal::random<int>(1,320))));
    CALL_SUBTEST_5((trsolve<std::complex<double>,Dynamic,1>(internal::random<int>(1,320))));
    CALL_SUBTEST_6((trsolve<float,1,1>()));
    CALL_SUBTEST_7((trsolve<float,1,2>()));
    CALL_SUBTEST_8((trsolve<std::complex<float>,4,1>()));
  }
}
<|endoftext|>


<commit_before><commit_msg>implementation of ini lexer<commit_after><|endoftext|>


<commit_before><commit_msg>Fix include guard<commit_after><|endoftext|>


<commit_before><commit_msg>#96588# bootstrap-variable pathes are now interpreted relative to the current working directory<commit_after><|endoftext|>


<commit_before>#include <windows.h>
#include <stdio.h>
#include "Thread.h"
#include "Mutex.h"
#include "CriticalSection.h"
#include "Condition.h"
#include "ThreadPool.h"
#include "../common/Log.h"

#include "Catch/single_include/catch.hpp"

TEST_CASE("ThreadTest", "[thread]")
{
	class TestThreadBase : public thread::ThreadBase
	{
	public:
		TestThreadBase() : ThreadBase(__FUNCTION__)
		{
			m_OnStartPassed =
			m_OnStopPassed =
			m_OnProcessStartedPassed =
			m_OnProcessStoppedPassed = false;
		}

		virtual void OnStart()
		{
			m_OnStartPassed = true;
		}

		virtual void Process()
		{
			m_OnProcessStartedPassed = true;
			while (!m_Stop)
			{
				thread::Thread::Sleep(100);
			}
			m_OnProcessStoppedPassed = true;
		}

		virtual void OnStop()
		{
			m_OnStopPassed = true;
		}

		volatile bool m_OnStartPassed;
		volatile bool m_OnStopPassed;
		volatile bool m_OnProcessStartedPassed;
		volatile bool m_OnProcessStoppedPassed;
	};

	SECTION("ThreadBase")
	{
		TestThreadBase th1;
		th1.SetName("TestThreadBase");
		REQUIRE((th1.m_OnStartPassed == false && th1.m_OnStopPassed == false && th1.m_OnProcessStartedPassed == false && th1.m_OnProcessStoppedPassed == false) == true);
		REQUIRE(th1.Create());
		thread::Thread::Sleep(200);
		REQUIRE(th1.GetName() == "TestThreadBase");
		REQUIRE((th1.m_OnStartPassed == true && th1.m_OnStopPassed == false && th1.m_OnProcessStartedPassed == true && th1.m_OnProcessStoppedPassed == false) == true);
		th1.Stop();
		REQUIRE(th1.Join());
		REQUIRE((th1.m_OnStartPassed == true && th1.m_OnStopPassed == true && th1.m_OnProcessStartedPassed == true && th1.m_OnProcessStoppedPassed == true) == true);
	}

	class TestThread : public thread::Thread, public thread::ThreadEventListener
	{
	public:
		TestThread() : Thread(__FUNCTION__)
		{
			m_OnStartPassed =
			m_OnStopPassed =
			m_OnProcessStartedPassed =
			m_OnProcessStoppedPassed =
			m_OnStartEventPassed =
			m_OnStopEventPassed = false;

			Listen(this);
		}

		virtual void OnStart()
		{
			Thread::OnStart();
			m_OnStartPassed = true;
		}

		virtual void Process()
		{
			m_OnProcessStartedPassed = true;
			while (!m_Stop)
			{
				thread::Thread::Sleep(100);
			}
			m_OnProcessStoppedPassed = true;
		}

		virtual void OnStop()
		{
			Thread::OnStop();
			m_OnStopPassed = true;
		}

		void OnStartEvent(Thread* thread)
		{
			if (thread == this)
			{
				m_OnStartEventPassed = true;
			}
		}

		void OnStopEvent(Thread* thread)
		{
			if (thread == this)
			{
				m_OnStopEventPassed = true;
			}
		}

		volatile bool m_OnStartPassed;
		volatile bool m_OnStopPassed;
		volatile bool m_OnProcessStartedPassed;
		volatile bool m_OnProcessStoppedPassed;
		volatile bool m_OnStartEventPassed;
		volatile bool m_OnStopEventPassed;
	};

	SECTION("Thread")
	{
		TestThread th1;
		th1.SetName("TestThread");
		REQUIRE(th1.m_OnStartPassed == false);
		REQUIRE(th1.m_OnStopPassed == false);
		REQUIRE(th1.m_OnProcessStartedPassed == false);
		REQUIRE(th1.m_OnProcessStoppedPassed == false);
		REQUIRE(th1.m_OnStartEventPassed == false);
		REQUIRE(th1.m_OnStopEventPassed == false);
		REQUIRE(th1.Create());
		thread::Thread::Sleep(200);
		REQUIRE(th1.GetName() == "TestThread");
		REQUIRE(th1.m_OnStartPassed == true);
		REQUIRE(th1.m_OnStopPassed == false);
		REQUIRE(th1.m_OnProcessStartedPassed == true);
		REQUIRE(th1.m_OnProcessStoppedPassed == false);
		REQUIRE(th1.m_OnStartEventPassed == true);
		REQUIRE(th1.m_OnStopEventPassed == false);
		th1.Stop();
		REQUIRE(th1.Join());
		REQUIRE(th1.m_OnStartPassed == true);
		REQUIRE(th1.m_OnStopPassed == true);
		REQUIRE(th1.m_OnProcessStartedPassed == true);
		REQUIRE(th1.m_OnProcessStoppedPassed == true);
		REQUIRE(th1.m_OnStartEventPassed == true);
		REQUIRE(th1.m_OnStopEventPassed == true);
	}

	class TestThreadPool : public thread::ThreadPool<TestThread>
	{
	public:
		TestThreadPool(size_t size) : ThreadPool(size) {}
	};

	SECTION("ThreadPool")
	{
		const size_t ttpSize = 4;
		TestThreadPool ttp(ttpSize);

		for (size_t i = 0; i < ttpSize; ++i)
		{
			REQUIRE(ttp.Create() != nullptr);
		}
		REQUIRE(ttp.Create() == nullptr);
		Sleep(200); //!!Barrier
		ttp.StopAll();
		ttp.WaitAll();
		ttp.JoinAll();

		for (size_t i = 0; i < ttpSize; ++i)
		{
			REQUIRE(ttp.Create() != nullptr);
		}
		REQUIRE(ttp.Create() == nullptr);
	}

}
template <class sync_type>
class SyncTestThread : public thread::ThreadBase
{
public:
	SyncTestThread(sync_type& syncVar, unsigned int& counter)
		: ThreadBase(__FUNCTION__)
		, m_SyncVar(syncVar)
		, m_Counter(counter)
	{   }
private:
	void Process()
	{
		thread::Thread::Sleep(0);
		for (size_t i = 0; i < 1024; ++i)
		{
			m_SyncVar.Lock();
			++m_Counter;
			m_SyncVar.Unlock();
			thread::Thread::Sleep(0);
		}
		for (size_t i = 0; i < 1024; ++i)
		{
			while (!m_SyncVar.TryLock())
			{
				thread::Thread::Sleep(0);
			}
			++m_Counter;
			m_SyncVar.Unlock();
		}
	}
	sync_type& m_SyncVar;
	unsigned int& m_Counter;
};

template <class sync_type>
bool SyncTestFunc()
{
	static sync_type sync;
	static unsigned int syncCount = 0;
	SyncTestThread<sync_type>* threads[32];
	for (size_t i = 0; i < 32; ++i) {
		threads[i] = new SyncTestThread<sync_type>(sync, syncCount);
	}
	for (size_t i = 0; i < 32; ++i) {
		threads[i]->Create();
	}
	for (size_t i = 0; i < 32; ++i) {
		threads[i]->Join();
	}
	for (size_t i = 0; i < 32; ++i) {
		delete threads[i];
	}
	return syncCount == 2 * 32 * 1024;
}

TEST_CASE("SyncTest", "[thread]")
{
	class NoLock
	{
	public:
		bool TryLock() { return true; }
		void Lock() { }
		void Unlock() { }
	};

	SECTION("NoLock")
	{
		REQUIRE(SyncTestFunc<NoLock>() == false);
	}

	SECTION("Mutex")
	{
		REQUIRE(SyncTestFunc<thread::Mutex>() == true);
	}

	SECTION("CriticalSection")
	{
		REQUIRE(SyncTestFunc<thread::CriticalSection>() == true);
	}

}
<commit_msg>More thread tests<commit_after>#include <windows.h>
#include <stdio.h>
#include "Thread.h"
#include "Mutex.h"
#include "CriticalSection.h"
#include "Condition.h"
#include "ThreadPool.h"
#include "../common/Log.h"

#include "Catch/single_include/catch.hpp"

TEST_CASE("ThreadTest", "[thread]")
{
	class TestThreadBase : public thread::ThreadBase
	{
	public:
		TestThreadBase() : ThreadBase(__FUNCTION__)
		{
			m_OnStartPassed =
			m_OnStopPassed =
			m_OnProcessStartedPassed =
			m_OnProcessStoppedPassed = false;
		}

		virtual void OnStart()
		{
			m_OnStartPassed = true;
		}

		virtual void Process()
		{
			m_OnProcessStartedPassed = true;
			while (!m_Stop)
			{
				thread::Thread::Sleep(100);
			}
			m_OnProcessStoppedPassed = true;
		}

		virtual void OnStop()
		{
			m_OnStopPassed = true;
		}

		volatile bool m_OnStartPassed;
		volatile bool m_OnStopPassed;
		volatile bool m_OnProcessStartedPassed;
		volatile bool m_OnProcessStoppedPassed;
	};

	SECTION("ThreadBase")
	{
		TestThreadBase th1;
		th1.SetName("TestThreadBase");
		REQUIRE((th1.m_OnStartPassed == false && th1.m_OnStopPassed == false && th1.m_OnProcessStartedPassed == false && th1.m_OnProcessStoppedPassed == false) == true);
		REQUIRE(th1.Create());
		thread::Thread::Sleep(200);
		REQUIRE(th1.GetName() == "TestThreadBase");
		REQUIRE((th1.m_OnStartPassed == true && th1.m_OnStopPassed == false && th1.m_OnProcessStartedPassed == true && th1.m_OnProcessStoppedPassed == false) == true);
		th1.Stop();
		REQUIRE(th1.Join());
		REQUIRE((th1.m_OnStartPassed == true && th1.m_OnStopPassed == true && th1.m_OnProcessStartedPassed == true && th1.m_OnProcessStoppedPassed == true) == true);
	}

	class TestThread : public thread::Thread, public thread::ThreadEventListener
	{
	public:
		TestThread() : Thread(__FUNCTION__)
		{
			m_OnStartPassed =
			m_OnStopPassed =
			m_OnProcessStartedPassed =
			m_OnProcessStoppedPassed =
			m_OnStartEventPassed =
			m_OnStopEventPassed = false;

			Listen(this);
		}

		virtual void OnStart()
		{
			Thread::OnStart();
			m_OnStartPassed = true;
		}

		virtual void Process()
		{
			m_OnProcessStartedPassed = true;
			while (!m_Stop)
			{
				thread::Thread::Sleep(100);
			}
			m_OnProcessStoppedPassed = true;
		}

		virtual void OnStop()
		{
			Thread::OnStop();
			m_OnStopPassed = true;
		}

		void OnStartEvent(Thread* thread)
		{
			if (thread == this)
			{
				m_OnStartEventPassed = true;
			}
		}

		void OnStopEvent(Thread* thread)
		{
			if (thread == this)
			{
				m_OnStopEventPassed = true;
			}
		}

		volatile bool m_OnStartPassed;
		volatile bool m_OnStopPassed;
		volatile bool m_OnProcessStartedPassed;
		volatile bool m_OnProcessStoppedPassed;
		volatile bool m_OnStartEventPassed;
		volatile bool m_OnStopEventPassed;
	};

	SECTION("Thread")
	{
		TestThread th1;
		th1.SetName("TestThread");
		REQUIRE(th1.m_OnStartPassed == false);
		REQUIRE(th1.m_OnStopPassed == false);
		REQUIRE(th1.m_OnProcessStartedPassed == false);
		REQUIRE(th1.m_OnProcessStoppedPassed == false);
		REQUIRE(th1.m_OnStartEventPassed == false);
		REQUIRE(th1.m_OnStopEventPassed == false);
		REQUIRE(th1.Create());
		thread::Thread::Sleep(200);
		REQUIRE(th1.GetName() == "TestThread");
		REQUIRE(th1.m_OnStartPassed == true);
		REQUIRE(th1.m_OnStopPassed == false);
		REQUIRE(th1.m_OnProcessStartedPassed == true);
		REQUIRE(th1.m_OnProcessStoppedPassed == false);
		REQUIRE(th1.m_OnStartEventPassed == true);
		REQUIRE(th1.m_OnStopEventPassed == false);
		th1.Stop();
		REQUIRE(th1.Join());
		REQUIRE(th1.m_OnStartPassed == true);
		REQUIRE(th1.m_OnStopPassed == true);
		REQUIRE(th1.m_OnProcessStartedPassed == true);
		REQUIRE(th1.m_OnProcessStoppedPassed == true);
		REQUIRE(th1.m_OnStartEventPassed == true);
		REQUIRE(th1.m_OnStopEventPassed == true);
	}

	class TestThreadPool : public thread::ThreadPool<TestThread>
	{
	public:
		TestThreadPool(size_t size) : ThreadPool(size) {}
	};

	SECTION("ThreadPool")
	{
		const size_t ttpSize = 4;
		TestThreadPool ttp(ttpSize);

		for (size_t i = 0; i < ttpSize; ++i)
		{
			REQUIRE(ttp.Create() != nullptr);
		}
		REQUIRE(ttp.Create() == nullptr);
		Sleep(200); //!!Barrier
		ttp.StopAll();
		ttp.WaitAll();
		ttp.JoinAll();

		for (size_t i = 0; i < ttpSize; ++i)
		{
			REQUIRE(ttp.Create() != nullptr);
		}
		REQUIRE(ttp.Create() == nullptr);
	}

}
template <class sync_type>
class SyncTestThread : public thread::ThreadBase
{
public:
	SyncTestThread(sync_type& syncVar, unsigned int& counter)
		: ThreadBase(__FUNCTION__)
		, m_SyncVar(syncVar)
		, m_Counter(counter)
	{   }
private:
	void Process()
	{
		thread::Thread::Sleep(0);
		for (size_t i = 0; i < 1024; ++i)
		{
			m_SyncVar.Lock();
			++m_Counter;
			m_SyncVar.Unlock();
			thread::Thread::Sleep(0);
		}
		for (size_t i = 0; i < 1024; ++i)
		{
			while (!m_SyncVar.TryLock())
			{
				thread::Thread::Sleep(0);
			}
			++m_Counter;
			m_SyncVar.Unlock();
		}
	}
	sync_type& m_SyncVar;
	unsigned int& m_Counter;
};

template <class sync_type>
bool SyncTestFunc()
{
	static sync_type sync;
	static unsigned int syncCount = 0;
	const size_t threadsNum = 32;
	SyncTestThread<sync_type>* threads[threadsNum];
	for (size_t i = 0; i < threadsNum; ++i) {
		threads[i] = new SyncTestThread<sync_type>(sync, syncCount);
	}
	for (size_t i = 0; i < threadsNum; ++i) {
		threads[i]->Create();
	}
	for (size_t i = 0; i < threadsNum; ++i) {
		threads[i]->Join();
	}
	for (size_t i = 0; i < threadsNum; ++i) {
		delete threads[i];
	}
	return syncCount == 2 * threadsNum * 1024;
}

TEST_CASE("SyncTest", "[thread]")
{
	class NoLock
	{
	public:
		bool TryLock() { return true; }
		void Lock() { }
		void Unlock() { }
	};

	SECTION("NoLock")
	{
		REQUIRE(SyncTestFunc<NoLock>() == false);
	}

	SECTION("Mutex")
	{
		REQUIRE(SyncTestFunc<thread::Mutex>() == true);
	}

	SECTION("CriticalSection")
	{
		REQUIRE(SyncTestFunc<thread::CriticalSection>() == true);
	}

	SECTION("Condition")
	{
		class TestConditionThread : public thread::ThreadBase
		{
		public:
			TestConditionThread(thread::Condition& condition) : ThreadBase(__FUNCTION__), m_Condition(condition)
			{
				m_OnStartPassed =
					m_OnStopPassed =
					m_OnProcessStartedPassed =
					m_OnProcessStoppedPassed = false;
			}

			virtual void OnStart()
			{
				m_Condition.Lock();
				m_OnStartPassed = true;
			}

			virtual void Process()
			{
				m_OnProcessStartedPassed = true;
				m_Condition.Wait();
				m_OnProcessStoppedPassed = true;
			}

			virtual void OnStop()
			{
				m_OnStopPassed = true;
				m_Condition.Unlock();
			}

			volatile bool m_OnStartPassed;
			volatile bool m_OnStopPassed;
			volatile bool m_OnProcessStartedPassed;
			volatile bool m_OnProcessStoppedPassed;

			thread::Condition& m_Condition;
		};

		thread::Condition condition;
		TestConditionThread tct(condition);
		tct.Create();
		thread::Thread::Sleep(200);
		condition.Lock();
		REQUIRE((
			tct.m_OnStartPassed == true &&
			tct.m_OnStopPassed == false &&
			tct.m_OnProcessStartedPassed == true &&
			tct.m_OnProcessStoppedPassed == false) == true);
		condition.Signal();
		condition.Unlock();
		tct.Join();
	}
}
<|endoftext|>