<commit_before>#include <Poco/Clock.h>
#include <Poco/Exception.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Logger.h>

#include "di/Injectable.h"
#include "gws/GatewayScanController.h"
#include "util/LambdaTimerTask.h"

BEEEON_OBJECT_BEGIN(BeeeOn, GatewayScanController)
BEEEON_OBJECT_CASTABLE(StoppableLoop)
BEEEON_OBJECT_PROPERTY("gatewayRPC", &GatewayScanController::setGatewayRPC)
BEEEON_OBJECT_PROPERTY("defaultDuration", &GatewayScanController::setDefaultDuration)
BEEEON_OBJECT_PROPERTY("cleanupInterval", &GatewayScanController::setCleanupInterval)
BEEEON_OBJECT_PROPERTY("cleanupOlderThan", &GatewayScanController::setCleanupOlderThan)
BEEEON_OBJECT_END(BeeeOn, GatewayScanController)

using namespace std;
using namespace Poco;
using namespace BeeeOn;

const static Timespan MAX_SCAN_DURATION = 10 * Timespan::MINUTES;

GatewayScanController::ScanHandler::ScanHandler(const GatewayID &id):
	m_id(id)
{
}

const GatewayScan &GatewayScanController::ScanHandler::scan() const
{
	ScopedLock guard(const_cast<ScanHandler&>(*this));
	return m_scan;
}

GatewayScan &GatewayScanController::ScanHandler::scan()
{
	ScopedLock guard(const_cast<ScanHandler&>(*this));
	return m_scan;
}

void GatewayScanController::ScanHandler::onPending(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.information("scanning " + m_id.toString() + " requested",
			__FILE__, __LINE__);
	m_scan.changeState(GatewayScan::SCAN_PROCESSING);
}

void GatewayScanController::ScanHandler::onAccepted(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.information("scanning " + m_id.toString() + " is starting",
			__FILE__, __LINE__);
	m_scan.changeState(GatewayScan::SCAN_PROCESSING);
}

void GatewayScanController::ScanHandler::onSuccess(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.information("scanning " + m_id.toString() + " in progress",
			__FILE__, __LINE__);
	m_scan.changeState(GatewayScan::SCAN_PROCESSING);
}

void GatewayScanController::ScanHandler::onFailed(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.error("scanning " + m_id.toString() + " has failed",
			__FILE__, __LINE__);

	m_scan.changeState(GatewayScan::SCAN_FAILED);
}

void GatewayScanController::ScanHandler::onTimeout(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.error("scanning " + m_id.toString() + " did not start on time",
			__FILE__, __LINE__);

	m_scan.changeState(GatewayScan::SCAN_FAILED);
}

void GatewayScanController::ScanHandler::onNotConnected(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.error("scanning " + m_id.toString() + " failed, not connected",
			__FILE__, __LINE__);

	m_scan.changeState(GatewayScan::SCAN_FAILED);
}

GatewayScanController::CleanUpTask::CleanUpTask(
		FastMutex &lock,
		GatewayScanController::ScanMap &scanMap):
	m_olderThen(30 * Timespan::MINUTES),
	m_lock(lock),
	m_scanMap(scanMap)
{
}

void GatewayScanController::CleanUpTask::setOlderThan(
		const Poco::Timespan &olderThen)
{
	if (olderThen < 0)
		throw InvalidArgumentException("cleanup older-than timeout must be positive");

	m_olderThen = olderThen;
}

void GatewayScanController::CleanUpTask::run()
{
	FastMutex::ScopedLock guard(m_lock);
	const Clock started;
	const size_t total = m_scanMap.size();
	size_t count = 0;

	logger().information("cleaning up scan records ("
			+ to_string(total) + ")",
			__FILE__, __LINE__);

	for (auto it = m_scanMap.begin(); it != m_scanMap.end();) {
		ScanHandler::Ptr context = it->second;
		ScanHandler::ScopedLock guard(*context);

		if (logger().debug()) {
			logger().debug("cleaning up scan record for "
					+ it->first.toString(),
					__FILE__, __LINE__);
		}

		const auto &started = context->scan().started();
		const auto &duration = context->scan().duration();
		const Timestamp now;

		switch (context->scan().state()) {
		case GatewayScan::SCAN_IDLE:
			it = m_scanMap.erase(it);
			count += 1;
			break;

		case GatewayScan::SCAN_FINISHED:
		case GatewayScan::SCAN_FAILED:
			if (started + duration < now - m_olderThen) {
				it = m_scanMap.erase(it);
				count += 1;
			}
			else {
				++it;
			}

			break;

		case GatewayScan::SCAN_WAITING:
		case GatewayScan::SCAN_PROCESSING:
			if (started + duration < now) {
				logger().warning("scan record for " + it->first.toString()
						+ " was not stopped on time, marking as failed",
						__FILE__, __LINE__);
				context->scan().changeState(GatewayScan::SCAN_FAILED);
			}

			++it;
			break;

		default:
			++it;
		}
	}

	logger().notice("cleaned up "
			+ to_string(count) + "/" + to_string(total)
			+ " scan records in "
			+ to_string(started.elapsed()) + "us",
			__FILE__, __LINE__);
}

GatewayScanController::GatewayScanController():
	m_defaultDuration(2 * Timespan::MINUTES),
	m_cleanupInterval(15 * Timespan::MINUTES),
	m_cleanupTask(new CleanUpTask(m_lock, m_scanMap))
{
}

void GatewayScanController::setDefaultDuration(const Poco::Timespan &duration)
{
	if (duration.totalSeconds() <= 0)
		throw InvalidArgumentException("duration must be at least a second");

	if (duration > MAX_SCAN_DURATION)
		throw InvalidArgumentException("too long default duration");

	m_defaultDuration = duration;
}

void GatewayScanController::setCleanupInterval(const Timespan &interval)
{
	if (interval.totalMilliseconds() <= 0)
		throw InvalidArgumentException("cleanup interval must be at least a millisecond");

	m_cleanupInterval = interval;
}

void GatewayScanController::setCleanupOlderThan(const Timespan &time)
{
	m_cleanupTask->setOlderThan(time);
}

void GatewayScanController::setGatewayRPC(GatewayRPC::Ptr rpc)
{
	m_rpc = rpc;
}

void GatewayScanController::start()
{
	logger().information("starting gateway scan controller");

	m_timer.scheduleAtFixedRate(
		m_cleanupTask,
		m_cleanupInterval.totalMilliseconds(),
		m_cleanupInterval.totalMilliseconds());
}

void GatewayScanController::stop()
{
	logger().information("stopping gateway scan controller");

	m_timer.cancel(true);

	FastMutex::ScopedLock guard(m_lock);
	m_scanMap.clear();
}

GatewayScan GatewayScanController::scan(const Gateway &gateway, const Timespan &timeout)
{
	const Timespan &duration = timeout <= 0? m_defaultDuration : timeout;

	if (duration > MAX_SCAN_DURATION)
		throw InvalidArgumentException("too big scanning timeout given");

	const auto id = gateway.id();

	ScopedLockWithUnlock<FastMutex> guard(m_lock);

	ScanHandler::Ptr context;

	auto it = m_scanMap.find(id);
	if (it != m_scanMap.end()) {
		context = it->second;

		const GatewayScan scan = context->scan();

		switch (scan.state()) {
		case GatewayScan::SCAN_PROCESSING:
		case GatewayScan::SCAN_WAITING:
			return scan;
		default:
			// restart scan
			break;
		}
	}
	else {
		context = new ScanHandler(id);
		m_scanMap.emplace(id, context);
	}

	ScanHandler::ScopedLock scanGuard(*context);
	guard.unlock();

	context->scan().setDuration(duration);
	context->scan().changeState(GatewayScan::SCAN_WAITING);

	const Clock start;

	m_rpc->sendListen(
		context,
		gateway,
		duration
	);

	m_timer.schedule(new LambdaTimerTask([start, id, context]() mutable
		{
			Logger &logger = Loggable::forClass(typeid(GatewayScanController));

			ScanHandler::ScopedLock guard(*context);
			GatewayScan &scan = context->scan();

			const Timespan &duration = scan.started().elapsed();

			switch (scan.state()) {
			case GatewayScan::SCAN_FINISHED:
				logger.warning("scanning of "
						+ id.toString()
						+ " is already finished",
						__FILE__, __LINE__);
				break;

			case GatewayScan::SCAN_WAITING:
			case GatewayScan::SCAN_PROCESSING:
				logger.information("scanning of "
						+ id.toString()
						+ " was finished after "
						+ DateTimeFormatter::format(duration),
						__FILE__, __LINE__);

				scan.changeState(GatewayScan::SCAN_FINISHED);
				break;

			default:
				if (logger.debug()) {
					logger.debug("skipping explicit finish of "
							+ id.toString() + " scan",
							__FILE__, __LINE__);
				}
				break;
			}
		}),
		start + duration.totalMicroseconds());

	return context->scan();
}

GatewayScan GatewayScanController::find(const Gateway &gateway)
{
	FastMutex::ScopedLock guard(m_lock);

	auto it = m_scanMap.find(gateway.id());
	if (it != m_scanMap.end())
		return it->second->scan();

	return GatewayScan::createIdle();
}
<commit_msg>GatewayScanController: fix missing update of timestamp<commit_after>#include <Poco/Clock.h>
#include <Poco/Exception.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Logger.h>

#include "di/Injectable.h"
#include "gws/GatewayScanController.h"
#include "util/LambdaTimerTask.h"

BEEEON_OBJECT_BEGIN(BeeeOn, GatewayScanController)
BEEEON_OBJECT_CASTABLE(StoppableLoop)
BEEEON_OBJECT_PROPERTY("gatewayRPC", &GatewayScanController::setGatewayRPC)
BEEEON_OBJECT_PROPERTY("defaultDuration", &GatewayScanController::setDefaultDuration)
BEEEON_OBJECT_PROPERTY("cleanupInterval", &GatewayScanController::setCleanupInterval)
BEEEON_OBJECT_PROPERTY("cleanupOlderThan", &GatewayScanController::setCleanupOlderThan)
BEEEON_OBJECT_END(BeeeOn, GatewayScanController)

using namespace std;
using namespace Poco;
using namespace BeeeOn;

const static Timespan MAX_SCAN_DURATION = 10 * Timespan::MINUTES;

GatewayScanController::ScanHandler::ScanHandler(const GatewayID &id):
	m_id(id)
{
}

const GatewayScan &GatewayScanController::ScanHandler::scan() const
{
	ScopedLock guard(const_cast<ScanHandler&>(*this));
	return m_scan;
}

GatewayScan &GatewayScanController::ScanHandler::scan()
{
	ScopedLock guard(const_cast<ScanHandler&>(*this));
	return m_scan;
}

void GatewayScanController::ScanHandler::onPending(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.information("scanning " + m_id.toString() + " requested",
			__FILE__, __LINE__);
	m_scan.changeState(GatewayScan::SCAN_PROCESSING);
}

void GatewayScanController::ScanHandler::onAccepted(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.information("scanning " + m_id.toString() + " is starting",
			__FILE__, __LINE__);
	m_scan.changeState(GatewayScan::SCAN_PROCESSING);
}

void GatewayScanController::ScanHandler::onSuccess(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.information("scanning " + m_id.toString() + " in progress",
			__FILE__, __LINE__);
	m_scan.changeState(GatewayScan::SCAN_PROCESSING);
}

void GatewayScanController::ScanHandler::onFailed(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.error("scanning " + m_id.toString() + " has failed",
			__FILE__, __LINE__);

	m_scan.changeState(GatewayScan::SCAN_FAILED);
}

void GatewayScanController::ScanHandler::onTimeout(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.error("scanning " + m_id.toString() + " did not start on time",
			__FILE__, __LINE__);

	m_scan.changeState(GatewayScan::SCAN_FAILED);
}

void GatewayScanController::ScanHandler::onNotConnected(GatewayRPCResult::Ptr r)
{
	ScanHandler::ScopedLock guard(*this);

	Logger &logger = Loggable::forClass(typeid(GatewayScanController));
	logger.error("scanning " + m_id.toString() + " failed, not connected",
			__FILE__, __LINE__);

	m_scan.changeState(GatewayScan::SCAN_FAILED);
}

GatewayScanController::CleanUpTask::CleanUpTask(
		FastMutex &lock,
		GatewayScanController::ScanMap &scanMap):
	m_olderThen(30 * Timespan::MINUTES),
	m_lock(lock),
	m_scanMap(scanMap)
{
}

void GatewayScanController::CleanUpTask::setOlderThan(
		const Poco::Timespan &olderThen)
{
	if (olderThen < 0)
		throw InvalidArgumentException("cleanup older-than timeout must be positive");

	m_olderThen = olderThen;
}

void GatewayScanController::CleanUpTask::run()
{
	FastMutex::ScopedLock guard(m_lock);
	const Clock started;
	const size_t total = m_scanMap.size();
	size_t count = 0;

	logger().information("cleaning up scan records ("
			+ to_string(total) + ")",
			__FILE__, __LINE__);

	for (auto it = m_scanMap.begin(); it != m_scanMap.end();) {
		ScanHandler::Ptr context = it->second;
		ScanHandler::ScopedLock guard(*context);

		if (logger().debug()) {
			logger().debug("cleaning up scan record for "
					+ it->first.toString(),
					__FILE__, __LINE__);
		}

		const auto &started = context->scan().started();
		const auto &duration = context->scan().duration();
		const Timestamp now;

		switch (context->scan().state()) {
		case GatewayScan::SCAN_IDLE:
			it = m_scanMap.erase(it);
			count += 1;
			break;

		case GatewayScan::SCAN_FINISHED:
		case GatewayScan::SCAN_FAILED:
			if (started + duration < now - m_olderThen) {
				it = m_scanMap.erase(it);
				count += 1;
			}
			else {
				++it;
			}

			break;

		case GatewayScan::SCAN_WAITING:
		case GatewayScan::SCAN_PROCESSING:
			if (started + duration < now) {
				logger().warning("scan record for " + it->first.toString()
						+ " was not stopped on time, marking as failed",
						__FILE__, __LINE__);
				context->scan().changeState(GatewayScan::SCAN_FAILED);
			}

			++it;
			break;

		default:
			++it;
		}
	}

	logger().notice("cleaned up "
			+ to_string(count) + "/" + to_string(total)
			+ " scan records in "
			+ to_string(started.elapsed()) + "us",
			__FILE__, __LINE__);
}

GatewayScanController::GatewayScanController():
	m_defaultDuration(2 * Timespan::MINUTES),
	m_cleanupInterval(15 * Timespan::MINUTES),
	m_cleanupTask(new CleanUpTask(m_lock, m_scanMap))
{
}

void GatewayScanController::setDefaultDuration(const Poco::Timespan &duration)
{
	if (duration.totalSeconds() <= 0)
		throw InvalidArgumentException("duration must be at least a second");

	if (duration > MAX_SCAN_DURATION)
		throw InvalidArgumentException("too long default duration");

	m_defaultDuration = duration;
}

void GatewayScanController::setCleanupInterval(const Timespan &interval)
{
	if (interval.totalMilliseconds() <= 0)
		throw InvalidArgumentException("cleanup interval must be at least a millisecond");

	m_cleanupInterval = interval;
}

void GatewayScanController::setCleanupOlderThan(const Timespan &time)
{
	m_cleanupTask->setOlderThan(time);
}

void GatewayScanController::setGatewayRPC(GatewayRPC::Ptr rpc)
{
	m_rpc = rpc;
}

void GatewayScanController::start()
{
	logger().information("starting gateway scan controller");

	m_timer.scheduleAtFixedRate(
		m_cleanupTask,
		m_cleanupInterval.totalMilliseconds(),
		m_cleanupInterval.totalMilliseconds());
}

void GatewayScanController::stop()
{
	logger().information("stopping gateway scan controller");

	m_timer.cancel(true);

	FastMutex::ScopedLock guard(m_lock);
	m_scanMap.clear();
}

GatewayScan GatewayScanController::scan(const Gateway &gateway, const Timespan &timeout)
{
	const Timespan &duration = timeout <= 0? m_defaultDuration : timeout;

	if (duration > MAX_SCAN_DURATION)
		throw InvalidArgumentException("too big scanning timeout given");

	const auto id = gateway.id();

	ScopedLockWithUnlock<FastMutex> guard(m_lock);

	ScanHandler::Ptr context;

	auto it = m_scanMap.find(id);
	if (it != m_scanMap.end()) {
		context = it->second;

		const GatewayScan scan = context->scan();

		switch (scan.state()) {
		case GatewayScan::SCAN_PROCESSING:
		case GatewayScan::SCAN_WAITING:
			return scan;
		default:
			// restart scan
			break;
		}
	}
	else {
		context = new ScanHandler(id);
		m_scanMap.emplace(id, context);
	}

	ScanHandler::ScopedLock scanGuard(*context);
	guard.unlock();

	context->scan().setStarted({});
	context->scan().setDuration(duration);
	context->scan().changeState(GatewayScan::SCAN_WAITING);

	const Clock start;

	m_rpc->sendListen(
		context,
		gateway,
		duration
	);

	m_timer.schedule(new LambdaTimerTask([start, id, context]() mutable
		{
			Logger &logger = Loggable::forClass(typeid(GatewayScanController));

			ScanHandler::ScopedLock guard(*context);
			GatewayScan &scan = context->scan();

			const Timespan &duration = scan.started().elapsed();

			switch (scan.state()) {
			case GatewayScan::SCAN_FINISHED:
				logger.warning("scanning of "
						+ id.toString()
						+ " is already finished",
						__FILE__, __LINE__);
				break;

			case GatewayScan::SCAN_WAITING:
			case GatewayScan::SCAN_PROCESSING:
				logger.information("scanning of "
						+ id.toString()
						+ " was finished after "
						+ DateTimeFormatter::format(duration),
						__FILE__, __LINE__);

				scan.changeState(GatewayScan::SCAN_FINISHED);
				break;

			default:
				if (logger.debug()) {
					logger.debug("skipping explicit finish of "
							+ id.toString() + " scan",
							__FILE__, __LINE__);
				}
				break;
			}
		}),
		start + duration.totalMicroseconds());

	return context->scan();
}

GatewayScan GatewayScanController::find(const Gateway &gateway)
{
	FastMutex::ScopedLock guard(m_lock);

	auto it = m_scanMap.find(gateway.id());
	if (it != m_scanMap.end())
		return it->second->scan();

	return GatewayScan::createIdle();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "deflate_compressor.h"

std::string zerr(int ret)
{
	switch (ret) {
		case Z_ERRNO:
			return "There is an error reading or writing the files";
		case Z_STREAM_ERROR:
			return "invalid compression level";
		case Z_DATA_ERROR:
			return "invalid or incomplete deflate data";
		case Z_MEM_ERROR:
			return "memory could not be allocated for processing (out of memory)";
		case Z_VERSION_ERROR:
			return "zlib version mismatch!";
		}
	return std::string();
}

int DeflateCompressData::FINISH_COMPRESS = Z_FINISH;

/*
 * Constructor compress with data
 */
DeflateCompressData::DeflateCompressData(const char* data_, size_t data_size_)
	: DeflateData(data_, data_size_),
	  DeflateBlockStreaming() { }

DeflateCompressData::~DeflateCompressData()
{
	deflateEnd(&strm);
}

std::string
DeflateCompressData::init(bool start)
{
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	stream = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	if (start && data) {
		return next();
	}
	return std::string();
}

std::string
DeflateCompressData::next(const char* input, size_t input_size, int flush)
{
	std::unique_ptr<char[]> out = std::make_unique<char[]>(input_size);
	strm.avail_in = input_size;
	strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(input));

	std::string result;
	do {
		strm.avail_out = input_size;
		strm.next_out = reinterpret_cast<Bytef*>(out.get());
		stream = deflate(&strm, flush);    // no bad return value
		int compress_size = input_size - strm.avail_out;
		result.append(std::string(out.get(), compress_size));
	} while (strm.avail_out == 0);

	return result;
}

std::string
DeflateCompressData::next()
{
	int flush;
	if (data_offset > data_size) {
		state = DeflateState::END;
		return std::string();
	}

	if (data_offset < data_size) {
		strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data + data_offset));
	}

	auto remain_size = data_size - data_offset;
	if ( remain_size > DEFLATE_BLOCK_SIZE) {
		strm.avail_in = DEFLATE_BLOCK_SIZE;
		flush = Z_NO_FLUSH;
	} else {
		strm.avail_in = remain_size;
		flush = Z_FINISH;
	}

	std::string result;
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(cmpBuf);
		stream = deflate(&strm, flush);    // no bad return value
		int compress_size = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(cmpBuf, compress_size));
	} while (strm.avail_out == 0);

	data_offset += DEFLATE_BLOCK_SIZE;
	return result;
}

/*
 * Constructor decompress with data
 */
DeflateDecompressData::DeflateDecompressData(const char* data_, size_t data_size_)
	: DeflateData(data_, data_size_),
	  DeflateBlockStreaming() { }

DeflateDecompressData::~DeflateDecompressData()
{
	inflateEnd(&strm);
}

std::string
DeflateDecompressData::init()
{
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	stream = inflateInit(&strm);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	return next();
}

std::string
DeflateDecompressData::next()
{
	if (data_offset > data_size) {
		state = DeflateState::END;
		return std::string();
	}

	if (data_offset < data_size) {
		strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data + data_offset));
	}

	auto remain_size = data_size - data_offset;
	if ( remain_size > DEFLATE_BLOCK_SIZE) {
		strm.avail_in = DEFLATE_BLOCK_SIZE;
	} else {
		strm.avail_in = remain_size;
	}

	std::string result;
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(buffer);
		stream = inflate(&strm, Z_NO_FLUSH);
		if (stream != Z_OK && stream != Z_STREAM_END && stream != Z_BUF_ERROR) {
			THROW(DeflateException, zerr(stream));
		}
		auto bytes_decompressed = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(buffer, bytes_decompressed));
	} while (strm.avail_out == 0);

	data_offset += DEFLATE_BLOCK_SIZE;
	return result;
}

/*
 * Construct for file name
 */
DeflateCompressFile::DeflateCompressFile(const std::string& filename)
	: DeflateFile(filename),
	  DeflateBlockStreaming() { }

/*
 * Construct for file descriptor
 */
DeflateCompressFile::DeflateCompressFile(int fd_, off_t fd_offset_, off_t fd_nbytes_)
	: DeflateFile(fd_, fd_offset_, fd_nbytes_),
	  DeflateBlockStreaming() { }

DeflateCompressFile::~DeflateCompressFile()
{
	deflateEnd(&strm);
}

std::string
DeflateCompressFile::init()
{
	if (fd_offset != -1 && io::lseek(fd, fd_offset, SEEK_SET) != static_cast<off_t>(fd_offset)) {
		THROW(DeflateIOError, "IO error: lseek");
	}

	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	stream = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	io::lseek(fd, 0, SEEK_END);
	size_file = io::lseek(fd, 0, SEEK_CUR);
	io::lseek(fd, 0, SEEK_SET);

	return next();
}

std::string
DeflateCompressFile::next()
{
	int inpBytes = static_cast<int>(io::read(fd, buffer, DEFLATE_BLOCK_SIZE));
	if (inpBytes <= 0) {
		if (stream == Z_STREAM_END) {
			state = DeflateState::END;
			return std::string();
		} else {
			THROW(DeflateIOError, "IO error: read");
		}
	}
	strm.avail_in = inpBytes;
	bytes_readed+=strm.avail_in;

	int flush;
	if (bytes_readed == size_file) {
		flush = Z_FINISH;
	} else {
		flush = Z_NO_FLUSH;
	}

	std::string result;
	strm.next_in = reinterpret_cast<Bytef*>(buffer);
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(cmpBuf);
		stream = deflate(&strm, flush);    /* no bad return value */
		auto bytes_compressed = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(cmpBuf, bytes_compressed));
	} while (strm.avail_out == 0);

	return result;
}

DeflateDecompressFile::DeflateDecompressFile(const std::string& filename)
	: DeflateFile(filename),
	  DeflateBlockStreaming() { }

DeflateDecompressFile::DeflateDecompressFile(int fd_, off_t fd_offset_, off_t fd_nbytes_)
	: DeflateFile(fd_, fd_offset_, fd_nbytes_),
	  DeflateBlockStreaming() { }

DeflateDecompressFile::~DeflateDecompressFile()
{
	inflateEnd(&strm);
}

std::string
DeflateDecompressFile::init()
{
	if (fd_offset != -1 && io::lseek(fd, fd_offset, SEEK_SET) != static_cast<off_t>(fd_offset)) {
		THROW(DeflateIOError, "IO error: lseek");
	}

	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	stream = inflateInit(&strm);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	return next();
}

std::string
DeflateDecompressFile::next()
{
	int inpBytes = io::read(fd, cmpBuf, DEFLATE_BLOCK_SIZE);
	if (inpBytes <= 0) {
		if (stream == Z_STREAM_END) {
			state = DeflateState::END;
			return std::string();
		} else {
			THROW(DeflateIOError, "IO error: read");
		}
	}
	strm.avail_in = inpBytes;
	strm.next_in = reinterpret_cast<Bytef*>(cmpBuf);

	std::string result;
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(buffer);
		stream = inflate(&strm, Z_NO_FLUSH);
		if (stream != Z_OK && stream != Z_STREAM_END && stream != Z_BUF_ERROR) {
			THROW(DeflateException, zerr(stream));
		}
		auto bytes_decompressed = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(buffer, bytes_decompressed));
	} while (strm.avail_out == 0);

	return result;
}
<commit_msg>Code format<commit_after>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "deflate_compressor.h"

std::string zerr(int ret)
{
	switch (ret) {
		case Z_ERRNO:
			return "There is an error reading or writing the files";
		case Z_STREAM_ERROR:
			return "invalid compression level";
		case Z_DATA_ERROR:
			return "invalid or incomplete deflate data";
		case Z_MEM_ERROR:
			return "memory could not be allocated for processing (out of memory)";
		case Z_VERSION_ERROR:
			return "zlib version mismatch!";
		}
	return std::string();
}

int DeflateCompressData::FINISH_COMPRESS = Z_FINISH;

/*
 * Constructor compress with data
 */
DeflateCompressData::DeflateCompressData(const char* data_, size_t data_size_)
	: DeflateData(data_, data_size_),
	  DeflateBlockStreaming() { }

DeflateCompressData::~DeflateCompressData()
{
	deflateEnd(&strm);
}

std::string
DeflateCompressData::init(bool start)
{
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	stream = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	if (start && data) {
		return next();
	}
	return std::string();
}

std::string
DeflateCompressData::next(const char* input, size_t input_size, int flush)
{
	std::unique_ptr<char[]> out = std::make_unique<char[]>(input_size);
	strm.avail_in = input_size;
	strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(input));

	std::string result;
	do {
		strm.avail_out = input_size;
		strm.next_out = reinterpret_cast<Bytef*>(out.get());
		stream = deflate(&strm, flush);    // no bad return value
		int compress_size = input_size - strm.avail_out;
		result.append(std::string(out.get(), compress_size));
	} while (strm.avail_out == 0);

	return result;
}

std::string
DeflateCompressData::next()
{
	int flush;
	if (data_offset > data_size) {
		state = DeflateState::END;
		return std::string();
	}

	if (data_offset < data_size) {
		strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data + data_offset));
	}

	auto remain_size = data_size - data_offset;
	if ( remain_size > DEFLATE_BLOCK_SIZE) {
		strm.avail_in = DEFLATE_BLOCK_SIZE;
		flush = Z_NO_FLUSH;
	} else {
		strm.avail_in = remain_size;
		flush = Z_FINISH;
	}

	std::string result;
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(cmpBuf);
		stream = deflate(&strm, flush);    // no bad return value
		int compress_size = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(cmpBuf, compress_size));
	} while (strm.avail_out == 0);

	data_offset += DEFLATE_BLOCK_SIZE;
	return result;
}

/*
 * Constructor decompress with data
 */
DeflateDecompressData::DeflateDecompressData(const char* data_, size_t data_size_)
	: DeflateData(data_, data_size_),
	  DeflateBlockStreaming() { }

DeflateDecompressData::~DeflateDecompressData()
{
	inflateEnd(&strm);
}

std::string
DeflateDecompressData::init()
{
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	stream = inflateInit(&strm);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	return next();
}

std::string
DeflateDecompressData::next()
{
	if (data_offset > data_size) {
		state = DeflateState::END;
		return std::string();
	}

	if (data_offset < data_size) {
		strm.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data + data_offset));
	}

	auto remain_size = data_size - data_offset;
	if ( remain_size > DEFLATE_BLOCK_SIZE) {
		strm.avail_in = DEFLATE_BLOCK_SIZE;
	} else {
		strm.avail_in = remain_size;
	}

	std::string result;
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(buffer);
		stream = inflate(&strm, Z_NO_FLUSH);
		if (stream != Z_OK && stream != Z_STREAM_END && stream != Z_BUF_ERROR) {
			THROW(DeflateException, zerr(stream));
		}
		auto bytes_decompressed = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(buffer, bytes_decompressed));
	} while (strm.avail_out == 0);

	data_offset += DEFLATE_BLOCK_SIZE;
	return result;
}

/*
 * Construct for file name
 */
DeflateCompressFile::DeflateCompressFile(const std::string& filename)
	: DeflateFile(filename),
	  DeflateBlockStreaming() { }

/*
 * Construct for file descriptor
 */
DeflateCompressFile::DeflateCompressFile(int fd_, off_t fd_offset_, off_t fd_nbytes_)
	: DeflateFile(fd_, fd_offset_, fd_nbytes_),
	  DeflateBlockStreaming() { }

DeflateCompressFile::~DeflateCompressFile()
{
	deflateEnd(&strm);
}

std::string
DeflateCompressFile::init()
{
	if (fd_offset != -1 && io::lseek(fd, fd_offset, SEEK_SET) != static_cast<off_t>(fd_offset)) {
		THROW(DeflateIOError, "IO error: lseek");
	}

	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;

	stream = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	io::lseek(fd, 0, SEEK_END);
	size_file = io::lseek(fd, 0, SEEK_CUR);
	io::lseek(fd, 0, SEEK_SET);

	return next();
}

std::string
DeflateCompressFile::next()
{
	int inpBytes = static_cast<int>(io::read(fd, buffer, DEFLATE_BLOCK_SIZE));
	if (inpBytes <= 0) {
		if (stream == Z_STREAM_END) {
			state = DeflateState::END;
			return std::string();
		} else {
			THROW(DeflateIOError, "IO error: read");
		}
	}
	strm.avail_in = inpBytes;
	bytes_readed+=strm.avail_in;

	int flush;
	if (bytes_readed == size_file) {
		flush = Z_FINISH;
	} else {
		flush = Z_NO_FLUSH;
	}

	std::string result;
	strm.next_in = reinterpret_cast<Bytef*>(buffer);
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(cmpBuf);
		stream = deflate(&strm, flush);    /* no bad return value */
		auto bytes_compressed = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(cmpBuf, bytes_compressed));
	} while (strm.avail_out == 0);

	return result;
}

DeflateDecompressFile::DeflateDecompressFile(const std::string& filename)
	: DeflateFile(filename),
	  DeflateBlockStreaming() { }

DeflateDecompressFile::DeflateDecompressFile(int fd_, off_t fd_offset_, off_t fd_nbytes_)
	: DeflateFile(fd_, fd_offset_, fd_nbytes_),
	  DeflateBlockStreaming() { }

DeflateDecompressFile::~DeflateDecompressFile()
{
	inflateEnd(&strm);
}

std::string
DeflateDecompressFile::init()
{
	if (fd_offset != -1 && io::lseek(fd, fd_offset, SEEK_SET) != static_cast<off_t>(fd_offset)) {
		THROW(DeflateIOError, "IO error: lseek");
	}

	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	stream = inflateInit(&strm);
	if(stream != Z_OK) {
		THROW(DeflateException, zerr(stream));
	}

	return next();
}

std::string
DeflateDecompressFile::next()
{
	int inpBytes = io::read(fd, cmpBuf, DEFLATE_BLOCK_SIZE);
	if (inpBytes <= 0) {
		if (stream == Z_STREAM_END) {
			state = DeflateState::END;
			return std::string();
		} else {
			THROW(DeflateIOError, "IO error: read");
		}
	}
	strm.avail_in = inpBytes;
	strm.next_in = reinterpret_cast<Bytef*>(cmpBuf);

	std::string result;
	do {
		strm.avail_out = DEFLATE_BLOCK_SIZE;
		strm.next_out = reinterpret_cast<Bytef*>(buffer);
		stream = inflate(&strm, Z_NO_FLUSH);
		if (stream != Z_OK && stream != Z_STREAM_END && stream != Z_BUF_ERROR) {
			THROW(DeflateException, zerr(stream));
		}
		auto bytes_decompressed = DEFLATE_BLOCK_SIZE - strm.avail_out;
		result.append(std::string(buffer, bytes_decompressed));
	} while (strm.avail_out == 0);

	return result;
}
<|endoftext|>


<commit_before>/**
 * @file compressed_file_writer.cpp
 * @author Sean Massung
 */

#include <cmath>
#include <cstring>
#include <limits>
#include "io/compressed_file_writer.h"

namespace meta {
namespace io {

compressed_file_writer::compressed_file_writer(const std::string & filename,
        std::function<uint64_t(uint64_t)> mapping):
    _outfile{fopen(filename.c_str(), "w")},
    _char_cursor{0},
    _bit_cursor{0},
    _buffer_size{1024 * 1024 * 64}, // 64 MB
    _buffer{new unsigned char[_buffer_size]},
    _mapping{std::move(mapping)},
    _bit_location{0},
    _closed{false}
{
    // disable buffering
    if(setvbuf(_outfile, nullptr, _IONBF, 0) != 0)
        throw compressed_file_writer_exception(
                "error disabling buffering (setvbuf)");

    // zero out, we'll only write ones
    memset(_buffer, 0, _buffer_size);
}

void compressed_file_writer::write(const std::string & str)
{
    uint64_t length = str.size();
    write(length);
    for(auto & ch: str)
        write(static_cast<uint64_t>(ch));
}

uint64_t compressed_file_writer::bit_location() const
{
    return _bit_location;
}

compressed_file_writer::~compressed_file_writer()
{
    if(!_closed)
        close();
}

void compressed_file_writer::close()
{
    if(!_closed)
    {
        // write the remaining bits, up to the nearest byte
        fwrite(_buffer, 1, _char_cursor + 1, _outfile);
        delete [] _buffer;
        fclose(_outfile);

        _closed = true;
    }
}

void compressed_file_writer::write(uint64_t value)
{
    uint64_t cvalue = _mapping(value);
    uint64_t length = std::log2(cvalue);

    for(uint64_t bit = 0; bit < length; ++bit)
        write_bit(false);

    write_bit(true);

    for(int64_t bit = length - 1; bit >= 0; --bit)
        write_bit(cvalue & 1 << bit);
}

void compressed_file_writer::write_bit(bool bit)
{
    ++_bit_location;

    if(bit)
        _buffer[_char_cursor] |= (1 << (7 - _bit_cursor));

    if(++_bit_cursor == 8)
    {
        _bit_cursor = 0;
        if(++_char_cursor == _buffer_size)
        {
            _char_cursor = 0;
            write_buffer();
        }
    }
}

void compressed_file_writer::write_buffer() const
{
    if(fwrite(_buffer, 1, _buffer_size, _outfile) != _buffer_size)
        throw compressed_file_writer_exception("error writing to file");
    memset(_buffer, 0, _buffer_size);
}

uint64_t default_compression_writer_func(uint64_t key)
{
    if(key == std::numeric_limits<uint64_t>::max()) // delimiter
        return uint64_t{1};
    return key + 2;
}

}
}
<commit_msg>Fix issue with writing strings in io::compressed_file_writer.<commit_after>/**
 * @file compressed_file_writer.cpp
 * @author Sean Massung
 */

#include <cmath>
#include <cstring>
#include <limits>
#include "io/compressed_file_writer.h"

namespace meta {
namespace io {

compressed_file_writer::compressed_file_writer(const std::string & filename,
        std::function<uint64_t(uint64_t)> mapping):
    _outfile{fopen(filename.c_str(), "w")},
    _char_cursor{0},
    _bit_cursor{0},
    _buffer_size{1024 * 1024 * 64}, // 64 MB
    _buffer{new unsigned char[_buffer_size]},
    _mapping{std::move(mapping)},
    _bit_location{0},
    _closed{false}
{
    // disable buffering
    if(setvbuf(_outfile, nullptr, _IONBF, 0) != 0)
        throw compressed_file_writer_exception(
                "error disabling buffering (setvbuf)");

    // zero out, we'll only write ones
    memset(_buffer, 0, _buffer_size);
}

void compressed_file_writer::write(const std::string & str)
{
    uint64_t length = str.size();
    write(length);
    for(auto & ch: str)
    {
        auto uch = static_cast<uint8_t>(ch);
        write(static_cast<uint64_t>(uch));
    }
}

uint64_t compressed_file_writer::bit_location() const
{
    return _bit_location;
}

compressed_file_writer::~compressed_file_writer()
{
    if(!_closed)
        close();
}

void compressed_file_writer::close()
{
    if(!_closed)
    {
        // write the remaining bits, up to the nearest byte
        fwrite(_buffer, 1, _char_cursor + 1, _outfile);
        delete [] _buffer;
        fclose(_outfile);

        _closed = true;
    }
}

void compressed_file_writer::write(uint64_t value)
{
    uint64_t cvalue = _mapping(value);
    uint64_t length = std::log2(cvalue);

    for(uint64_t bit = 0; bit < length; ++bit)
        write_bit(false);

    write_bit(true);

    for(int64_t bit = length - 1; bit >= 0; --bit)
        write_bit(cvalue & 1 << bit);
}

void compressed_file_writer::write_bit(bool bit)
{
    ++_bit_location;

    if(bit)
        _buffer[_char_cursor] |= (1 << (7 - _bit_cursor));

    if(++_bit_cursor == 8)
    {
        _bit_cursor = 0;
        if(++_char_cursor == _buffer_size)
        {
            _char_cursor = 0;
            write_buffer();
        }
    }
}

void compressed_file_writer::write_buffer() const
{
    if(fwrite(_buffer, 1, _buffer_size, _outfile) != _buffer_size)
        throw compressed_file_writer_exception("error writing to file");
    memset(_buffer, 0, _buffer_size);
}

uint64_t default_compression_writer_func(uint64_t key)
{
    if(key == std::numeric_limits<uint64_t>::max()) // delimiter
        return uint64_t{1};
    return key + 2;
}

}
}
<|endoftext|>


<commit_before>#include <QCommandLineParser>

#include "../DataLayer/DataContainer.h"
#include "../CommunicationLayer/CommunicationContainer.h"
#include "../BusinessLayer/BusinessContainer.h"
#include "../PresenterLayer/PresenterContainer.h"
#include "../ViewLayer/ViewContainer.h"
#include "../InfrastructureLayer/InfrastructureContainer.h"
#include "EpsilonDashboard.h"
#include "../ViewLayer/FontLoader/FontLoader.h"

#include <QString>

namespace
{
    const char* RACE_QUEUE = "raceQueue";
    const char* DISPLAY_QUEUE = "displayQueue";
    const char* DEBUG_QUEUE = "debugQueue";
}

EpsilonDashboard::EpsilonDashboard(int& argc, char** argv)
    : QApplication(argc, argv)
    , infrastructureContainer_(new InfrastructureContainer())
    , dataContainer_(new DataContainer())
    , businessContainer_(new BusinessContainer(*dataContainer_))
    , presenterContainer_(new PresenterContainer(*dataContainer_))
    , fontLoader_(new FontLoader)
{
    QCommandLineParser parser;
    QCommandLineOption raceModeOption("r");
    QCommandLineOption debugModeOption("d");
    QCommandLineOption isWindowedMode("w");
    parser.addOption(raceModeOption);
    parser.addOption(debugModeOption);
    parser.addOption(isWindowedMode);

    parser.process(*this);
    Mode mode = Mode::DISPLAY;
    bool isWindowed = false;

    if (parser.isSet(isWindowedMode))
    {
        isWindowed = true;
    }

    if (parser.isSet(raceModeOption))
    {
        mode = Mode::RACE;
        infrastructureContainer_->setQueueName(RACE_QUEUE);
    }
    else if (parser.isSet(debugModeOption))
    {
        mode = Mode::DEBUG;
        infrastructureContainer_->setQueueName(DEBUG_QUEUE);
    }
    else
    {
        infrastructureContainer_->setQueueName(DISPLAY_QUEUE);
    }

    Q_INIT_RESOURCE(fontresources);

    QApplication::setFont(fontLoader_->loadFont(Font::LCD));

    viewContainer_.reset(new ViewContainer(*presenterContainer_, mode, isWindowed)); //pass in a third boolean variable
    communicationContainer_.reset(new CommunicationContainer(*businessContainer_, *infrastructureContainer_));
}

EpsilonDashboard::~EpsilonDashboard()
{
}
<commit_msg>Change font to use BURLINGAME<commit_after>#include <QCommandLineParser>

#include "../DataLayer/DataContainer.h"
#include "../CommunicationLayer/CommunicationContainer.h"
#include "../BusinessLayer/BusinessContainer.h"
#include "../PresenterLayer/PresenterContainer.h"
#include "../ViewLayer/ViewContainer.h"
#include "../InfrastructureLayer/InfrastructureContainer.h"
#include "EpsilonDashboard.h"
#include "../ViewLayer/FontLoader/FontLoader.h"

#include <QString>

namespace
{
    const char* RACE_QUEUE = "raceQueue";
    const char* DISPLAY_QUEUE = "displayQueue";
    const char* DEBUG_QUEUE = "debugQueue";
}

EpsilonDashboard::EpsilonDashboard(int& argc, char** argv)
    : QApplication(argc, argv)
    , infrastructureContainer_(new InfrastructureContainer())
    , dataContainer_(new DataContainer())
    , businessContainer_(new BusinessContainer(*dataContainer_))
    , presenterContainer_(new PresenterContainer(*dataContainer_))
    , fontLoader_(new FontLoader)
{
    QCommandLineParser parser;
    QCommandLineOption raceModeOption("r");
    QCommandLineOption debugModeOption("d");
    QCommandLineOption isWindowedMode("w");
    parser.addOption(raceModeOption);
    parser.addOption(debugModeOption);
    parser.addOption(isWindowedMode);

    parser.process(*this);
    Mode mode = Mode::DISPLAY;
    bool isWindowed = false;

    if (parser.isSet(isWindowedMode))
    {
        isWindowed = true;
    }

    if (parser.isSet(raceModeOption))
    {
        mode = Mode::RACE;
        infrastructureContainer_->setQueueName(RACE_QUEUE);
    }
    else if (parser.isSet(debugModeOption))
    {
        mode = Mode::DEBUG;
        infrastructureContainer_->setQueueName(DEBUG_QUEUE);
    }
    else
    {
        infrastructureContainer_->setQueueName(DISPLAY_QUEUE);
    }

    Q_INIT_RESOURCE(fontresources);

    QApplication::setFont(fontLoader_->loadFont(Font::BURLINGAME));

    viewContainer_.reset(new ViewContainer(*presenterContainer_, mode, isWindowed)); //pass in a third boolean variable
    communicationContainer_.reset(new CommunicationContainer(*businessContainer_, *infrastructureContainer_));
}

EpsilonDashboard::~EpsilonDashboard()
{
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2011-2012, John Haddon. All rights reserved.
//  Copyright (c) 2011-2014, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/bind.hpp"
#include "boost/bind/placeholders.hpp"

#include "Gaffer/UndoContext.h"
#include "Gaffer/ScriptNode.h"
#include "Gaffer/StandardSet.h"
#include "Gaffer/Metadata.h"
#include "Gaffer/Dot.h"

#include "GafferUI/StandardConnectionGadget.h"
#include "GafferUI/Style.h"
#include "GafferUI/Nodule.h"
#include "GafferUI/NodeGadget.h"

using namespace std;
using namespace Imath;
using namespace Gaffer;
using namespace GafferUI;

IE_CORE_DEFINERUNTIMETYPED( StandardConnectionGadget );

ConnectionGadget::ConnectionGadgetTypeDescription<StandardConnectionGadget> StandardConnectionGadget::g_connectionGadgetTypeDescription( Gaffer::Plug::staticTypeId() );

static IECore::InternedString g_colorKey( "connectionGadget:color" );

StandardConnectionGadget::StandardConnectionGadget( GafferUI::NodulePtr srcNodule, GafferUI::NodulePtr dstNodule )
	:	ConnectionGadget( srcNodule, dstNodule ), m_dragEnd( Gaffer::Plug::Invalid ), m_hovering( false )
{
	enterSignal().connect( boost::bind( &StandardConnectionGadget::enter, this, ::_2 ) );
	mouseMoveSignal().connect( boost::bind( &StandardConnectionGadget::mouseMove, this, ::_2 ) );
	leaveSignal().connect( boost::bind( &StandardConnectionGadget::leave, this, ::_2 ) );
	buttonPressSignal().connect( boost::bind( &StandardConnectionGadget::buttonPress, this,  ::_2 ) );
	dragBeginSignal().connect( boost::bind( &StandardConnectionGadget::dragBegin, this, ::_2 ) );
	dragEnterSignal().connect( boost::bind( &StandardConnectionGadget::dragEnter, this, ::_2 ) );
	dragMoveSignal().connect( boost::bind( &StandardConnectionGadget::dragMove, this, ::_2 ) );
	dragEndSignal().connect( boost::bind( &StandardConnectionGadget::dragEnd, this, ::_2 ) );

	Metadata::plugValueChangedSignal().connect( boost::bind( &StandardConnectionGadget::plugMetadataChanged, this, ::_1, ::_2, ::_3, ::_4 ) );

	updateUserColor();
}

StandardConnectionGadget::~StandardConnectionGadget()
{
}

void StandardConnectionGadget::setNodules( GafferUI::NodulePtr srcNodule, GafferUI::NodulePtr dstNodule )
{
	ConnectionGadget::setNodules( srcNodule, dstNodule );
	setPositionsFromNodules();
}

void StandardConnectionGadget::setPositionsFromNodules()
{
	const Gadget *p = parent<Gadget>();
	if( !p )
	{
		return;
	}

	if( dstNodule() && m_dragEnd!=Gaffer::Plug::In )
	{
		Gadget *dstNodeGadget = dstNodule()->ancestor<NodeGadget>();
		if( dstNodeGadget )
		{
			/// \todo
			/// this is a hack. we're calling bound() to trigger
			/// recomputation of the child positions within
			/// the nodule row - this is currently necessary when a
			/// nodule has just been added as connections are
			/// rendered before nodules and the nodule transforms
			/// would otherwise not be updated in time. see the todo item
			/// in Gadget.h which suggests that transforms are returned from
			/// a childTransform() virtual method - this would mean the
			/// container could update the transform as we request it.
			dstNodeGadget->bound();
		}
		M44f m = dstNodule()->fullTransform( p );
		m_dstPos = V3f( 0 ) * m;

		const NodeGadget *dstNoduleNodeGadget = dstNodule()->ancestor<NodeGadget>();
		m_dstTangent = dstNoduleNodeGadget ? dstNoduleNodeGadget->noduleTangent( dstNodule() ) : V3f( 0, 1, 0 );
	}

	if( srcNodule() && m_dragEnd!=Gaffer::Plug::Out )
	{
		Gadget *srcNodeGadget = srcNodule()->ancestor<NodeGadget>();
		if( srcNodeGadget )
		{
			/// \todo See above.
			srcNodeGadget->bound();
		}
		M44f m = srcNodule()->fullTransform( p );
		m_srcPos = V3f( 0 ) * m;

		const NodeGadget *srcNoduleNodeGadget = srcNodule()->ancestor<NodeGadget>();
		m_srcTangent = srcNoduleNodeGadget ? srcNoduleNodeGadget->noduleTangent( srcNodule() ) : V3f( 0, -1, 0 );
	}
	else if( m_dragEnd != Gaffer::Plug::Out )
	{
		// not dragging and don't have a source nodule.
		// we're a dangling connection because the source
		// node is hidden.
		m_srcPos = m_dstPos + m_dstTangent * 1.5f;
		m_srcTangent = -m_dstTangent;
	}

}

Imath::Box3f StandardConnectionGadget::bound() const
{
	const_cast<StandardConnectionGadget *>( this )->setPositionsFromNodules();
	Box3f r;
	r.extendBy( m_srcPos );
	r.extendBy( m_dstPos );
	return r;
}

void StandardConnectionGadget::updateDragEndPoint( const Imath::V3f position, const Imath::V3f &tangent )
{
	if( m_dragEnd==Gaffer::Plug::Out )
	{
		m_srcPos = position;
		m_srcTangent = tangent;
	}
	else if( m_dragEnd==Gaffer::Plug::In )
	{
		m_dstPos = position;
		m_dstTangent = tangent;
	}
	else
	{
		throw IECore::Exception( "Not dragging" );
	}
 	requestRender();
}

void StandardConnectionGadget::doRender( const Style *style ) const
{
	const_cast<StandardConnectionGadget *>( this )->setPositionsFromNodules();

	Style::State state = m_hovering ? Style::HighlightedState : Style::NormalState;
	if( state != Style::HighlightedState )
	{
		if( nodeSelected( srcNodule() ) || nodeSelected( dstNodule() ) )
		{
			state = Style::HighlightedState;
		}
	}

	V3f adjustedSrcPos = m_srcPos;
	V3f adjustedSrcTangent = m_srcTangent;
	if( getMinimised() && state != Style::HighlightedState )
	{
		adjustedSrcPos = m_dstPos + m_dstTangent * 1.5f;
		adjustedSrcTangent = -m_dstTangent;
	}

	style->renderConnection( adjustedSrcPos, adjustedSrcTangent, m_dstPos, m_dstTangent, state, m_userColor.get_ptr() );
}

Gaffer::Plug::Direction StandardConnectionGadget::endAt( const IECore::LineSegment3f &line )
{
	const float length = ( m_srcPos - m_dstPos ).length();

	const float dSrc = line.distanceTo( m_srcPos );
	const float dDst = line.distanceTo( m_dstPos );

	if( min( dSrc, dDst ) < length / 3.0f )
	{
		// close enough to the ends to consider
		if( dSrc < dDst )
		{
			return Gaffer::Plug::Out;
		}
		else
		{
			return Gaffer::Plug::In;
		}
	}

	return Gaffer::Plug::Invalid;

}

bool StandardConnectionGadget::buttonPress( const ButtonEvent &event )
{
	// We have to accept button presses so we can initiate dragging.
	return event.buttons==ButtonEvent::Left && m_hovering;
}

IECore::RunTimeTypedPtr StandardConnectionGadget::dragBegin( const DragDropEvent &event )
{
	setPositionsFromNodules();
	m_dragEnd = endAt( event.line );
	switch( m_dragEnd )
	{
		case Gaffer::Plug::Out :
			return dstNodule()->plug();
		case Gaffer::Plug::In :
			return dstNodule()->plug()->getInput<Gaffer::Plug>();
		default :
			return NULL;
	}
}

bool StandardConnectionGadget::dragEnter( const DragDropEvent &event )
{
	if( event.sourceGadget == this )
	{
		return true;
	}
	return false;
}

bool StandardConnectionGadget::dragMove( const DragDropEvent &event )
{
	updateDragEndPoint( event.line.p0, V3f( 0 ) );
	return true;
}

bool StandardConnectionGadget::dragEnd( const DragDropEvent &event )
{
	if( !event.destinationGadget || event.destinationGadget == this )
	{
		// noone wanted the drop so we'll disconnect
		Gaffer::UndoContext undoEnabler( dstNodule()->plug()->ancestor<Gaffer::ScriptNode>() );
		dstNodule()->plug()->setInput( 0 );
	}
	else
	{
		// we let the Nodule do all the work when a drop has actually landed
	}

	m_dragEnd = Gaffer::Plug::Invalid;
 	requestRender();
	return true;
}

std::string StandardConnectionGadget::getToolTip( const IECore::LineSegment3f &line ) const
{
	std::string result = Gadget::getToolTip( line );
	if( result.size() )
	{
		return result;
	}

	if( !dstNodule() )
	{
		return result;
	}

	const Gaffer::Plug *dstPlug = dstNodule()->plug();

	int numSkippedDots = 0;
	const Gaffer::Plug *srcPlug = dstPlug->getInput<Gaffer::Plug>();
	while( const Dot *dot = IECore::runTimeCast<const Gaffer::Dot>( srcPlug->node() ) )
	{
		const Gaffer::Plug *inPlug = srcPlug->getInput<Gaffer::Plug>();
		if(
			srcPlug == dot->outPlug<Gaffer::Plug>() &&
			inPlug == dot->inPlug<Gaffer::Plug>() &&
			inPlug->getInput<Gaffer::Plug>()
		)
		{
			srcPlug = inPlug->getInput<Gaffer::Plug>();
			numSkippedDots += 1;
		}
		else
		{
			break;
		}
	}

	const Gaffer::GraphComponent *ancestor = srcPlug->commonAncestor<Gaffer::GraphComponent>( dstPlug );

	std::string srcName;
	std::string dstName;
	if( ancestor )
	{
		srcName = srcPlug->relativeName( ancestor );
		dstName = dstPlug->relativeName( ancestor );
	}
	else
	{
		srcName = srcPlug->fullName();
		dstName = dstPlug->fullName();
	}

	result = srcName + " -> " + dstName;
	if( numSkippedDots )
	{
		result += boost::str(
			boost::format( " (via %d dot%s)" ) % numSkippedDots % ( numSkippedDots > 1 ? "s" : "" )
		);
	}
	return result;
}

void StandardConnectionGadget::enter( const ButtonEvent &event )
{
	m_hovering = endAt( event.line ) != Plug::Invalid;
	requestRender();
}

bool StandardConnectionGadget::mouseMove( const ButtonEvent &event )
{
	m_hovering = endAt( event.line ) != Plug::Invalid;
 	requestRender();
	return false;
}

void StandardConnectionGadget::leave( const ButtonEvent &event )
{
	m_hovering = false;
	requestRender();
}

bool StandardConnectionGadget::nodeSelected( const Nodule *nodule ) const
{
	if( !nodule )
	{
		return false;
	}

	const Gaffer::Node *node = nodule->plug()->node();
	if( !node )
	{
		return false;
	}

	const Gaffer::ScriptNode *script = node->scriptNode();
	return script && script->selection()->contains( node );
}

void StandardConnectionGadget::plugMetadataChanged( IECore::TypeId nodeTypeId, const Gaffer::MatchPattern &plugPath, IECore::InternedString key, const Gaffer::Plug *plug )
{
	const Plug *dstPlug = dstNodule()->plug();
	if( plug && plug != dstPlug )
	{
		return;
	}

	const Node *node = dstPlug->node();
	if(
		key != g_colorKey ||
		!node->isInstanceOf( nodeTypeId ) ||
		!match( dstPlug->relativeName( node ), plugPath )
	)
	{
		return;
	}

	if( updateUserColor() )
	{
 		requestRender();
	}
}

bool StandardConnectionGadget::updateUserColor()
{
	boost::optional<Color3f> c;
	if( IECore::ConstColor3fDataPtr d = Metadata::plugValue<IECore::Color3fData>( dstNodule()->plug(), g_colorKey ) )
	{
		c = d->readable();
	}

	if( c == m_userColor )
	{
		return false;
	}

	m_userColor = c;
	return true;
}
<commit_msg>StandardConnectionGadget : Clamp threshold for dragging connection ends.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2011-2012, John Haddon. All rights reserved.
//  Copyright (c) 2011-2014, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/bind.hpp"
#include "boost/bind/placeholders.hpp"

#include "OpenEXR/ImathFun.h"

#include "Gaffer/UndoContext.h"
#include "Gaffer/ScriptNode.h"
#include "Gaffer/StandardSet.h"
#include "Gaffer/Metadata.h"
#include "Gaffer/Dot.h"

#include "GafferUI/StandardConnectionGadget.h"
#include "GafferUI/Style.h"
#include "GafferUI/Nodule.h"
#include "GafferUI/NodeGadget.h"

using namespace std;
using namespace Imath;
using namespace Gaffer;
using namespace GafferUI;

IE_CORE_DEFINERUNTIMETYPED( StandardConnectionGadget );

ConnectionGadget::ConnectionGadgetTypeDescription<StandardConnectionGadget> StandardConnectionGadget::g_connectionGadgetTypeDescription( Gaffer::Plug::staticTypeId() );

static IECore::InternedString g_colorKey( "connectionGadget:color" );

StandardConnectionGadget::StandardConnectionGadget( GafferUI::NodulePtr srcNodule, GafferUI::NodulePtr dstNodule )
	:	ConnectionGadget( srcNodule, dstNodule ), m_dragEnd( Gaffer::Plug::Invalid ), m_hovering( false )
{
	enterSignal().connect( boost::bind( &StandardConnectionGadget::enter, this, ::_2 ) );
	mouseMoveSignal().connect( boost::bind( &StandardConnectionGadget::mouseMove, this, ::_2 ) );
	leaveSignal().connect( boost::bind( &StandardConnectionGadget::leave, this, ::_2 ) );
	buttonPressSignal().connect( boost::bind( &StandardConnectionGadget::buttonPress, this,  ::_2 ) );
	dragBeginSignal().connect( boost::bind( &StandardConnectionGadget::dragBegin, this, ::_2 ) );
	dragEnterSignal().connect( boost::bind( &StandardConnectionGadget::dragEnter, this, ::_2 ) );
	dragMoveSignal().connect( boost::bind( &StandardConnectionGadget::dragMove, this, ::_2 ) );
	dragEndSignal().connect( boost::bind( &StandardConnectionGadget::dragEnd, this, ::_2 ) );

	Metadata::plugValueChangedSignal().connect( boost::bind( &StandardConnectionGadget::plugMetadataChanged, this, ::_1, ::_2, ::_3, ::_4 ) );

	updateUserColor();
}

StandardConnectionGadget::~StandardConnectionGadget()
{
}

void StandardConnectionGadget::setNodules( GafferUI::NodulePtr srcNodule, GafferUI::NodulePtr dstNodule )
{
	ConnectionGadget::setNodules( srcNodule, dstNodule );
	setPositionsFromNodules();
}

void StandardConnectionGadget::setPositionsFromNodules()
{
	const Gadget *p = parent<Gadget>();
	if( !p )
	{
		return;
	}

	if( dstNodule() && m_dragEnd!=Gaffer::Plug::In )
	{
		Gadget *dstNodeGadget = dstNodule()->ancestor<NodeGadget>();
		if( dstNodeGadget )
		{
			/// \todo
			/// this is a hack. we're calling bound() to trigger
			/// recomputation of the child positions within
			/// the nodule row - this is currently necessary when a
			/// nodule has just been added as connections are
			/// rendered before nodules and the nodule transforms
			/// would otherwise not be updated in time. see the todo item
			/// in Gadget.h which suggests that transforms are returned from
			/// a childTransform() virtual method - this would mean the
			/// container could update the transform as we request it.
			dstNodeGadget->bound();
		}
		M44f m = dstNodule()->fullTransform( p );
		m_dstPos = V3f( 0 ) * m;

		const NodeGadget *dstNoduleNodeGadget = dstNodule()->ancestor<NodeGadget>();
		m_dstTangent = dstNoduleNodeGadget ? dstNoduleNodeGadget->noduleTangent( dstNodule() ) : V3f( 0, 1, 0 );
	}

	if( srcNodule() && m_dragEnd!=Gaffer::Plug::Out )
	{
		Gadget *srcNodeGadget = srcNodule()->ancestor<NodeGadget>();
		if( srcNodeGadget )
		{
			/// \todo See above.
			srcNodeGadget->bound();
		}
		M44f m = srcNodule()->fullTransform( p );
		m_srcPos = V3f( 0 ) * m;

		const NodeGadget *srcNoduleNodeGadget = srcNodule()->ancestor<NodeGadget>();
		m_srcTangent = srcNoduleNodeGadget ? srcNoduleNodeGadget->noduleTangent( srcNodule() ) : V3f( 0, -1, 0 );
	}
	else if( m_dragEnd != Gaffer::Plug::Out )
	{
		// not dragging and don't have a source nodule.
		// we're a dangling connection because the source
		// node is hidden.
		m_srcPos = m_dstPos + m_dstTangent * 1.5f;
		m_srcTangent = -m_dstTangent;
	}

}

Imath::Box3f StandardConnectionGadget::bound() const
{
	const_cast<StandardConnectionGadget *>( this )->setPositionsFromNodules();
	Box3f r;
	r.extendBy( m_srcPos );
	r.extendBy( m_dstPos );
	return r;
}

void StandardConnectionGadget::updateDragEndPoint( const Imath::V3f position, const Imath::V3f &tangent )
{
	if( m_dragEnd==Gaffer::Plug::Out )
	{
		m_srcPos = position;
		m_srcTangent = tangent;
	}
	else if( m_dragEnd==Gaffer::Plug::In )
	{
		m_dstPos = position;
		m_dstTangent = tangent;
	}
	else
	{
		throw IECore::Exception( "Not dragging" );
	}
 	requestRender();
}

void StandardConnectionGadget::doRender( const Style *style ) const
{
	const_cast<StandardConnectionGadget *>( this )->setPositionsFromNodules();

	Style::State state = ( m_hovering || m_dragEnd ) ? Style::HighlightedState : Style::NormalState;
	if( state != Style::HighlightedState )
	{
		if( nodeSelected( srcNodule() ) || nodeSelected( dstNodule() ) )
		{
			state = Style::HighlightedState;
		}
	}

	V3f adjustedSrcPos = m_srcPos;
	V3f adjustedSrcTangent = m_srcTangent;
	if( getMinimised() && state != Style::HighlightedState )
	{
		adjustedSrcPos = m_dstPos + m_dstTangent * 1.5f;
		adjustedSrcTangent = -m_dstTangent;
	}

	style->renderConnection( adjustedSrcPos, adjustedSrcTangent, m_dstPos, m_dstTangent, state, m_userColor.get_ptr() );
}

Gaffer::Plug::Direction StandardConnectionGadget::endAt( const IECore::LineSegment3f &line )
{
	const float length = ( m_srcPos - m_dstPos ).length();
	const float threshold = clamp( length / 4.0f, 2.5f, 25.0f );

	const float dSrc = line.distanceTo( m_srcPos );
	const float dDst = line.distanceTo( m_dstPos );

	if( min( dSrc, dDst ) < threshold )
	{
		// close enough to the ends to consider
		if( dSrc < dDst )
		{
			return Gaffer::Plug::Out;
		}
		else
		{
			return Gaffer::Plug::In;
		}
	}

	return Gaffer::Plug::Invalid;

}

bool StandardConnectionGadget::buttonPress( const ButtonEvent &event )
{
	// We have to accept button presses so we can initiate dragging.
	return event.buttons==ButtonEvent::Left && m_hovering;
}

IECore::RunTimeTypedPtr StandardConnectionGadget::dragBegin( const DragDropEvent &event )
{
	setPositionsFromNodules();
	m_dragEnd = endAt( event.line );
	switch( m_dragEnd )
	{
		case Gaffer::Plug::Out :
			return dstNodule()->plug();
		case Gaffer::Plug::In :
			return dstNodule()->plug()->getInput<Gaffer::Plug>();
		default :
			return NULL;
	}
}

bool StandardConnectionGadget::dragEnter( const DragDropEvent &event )
{
	if( event.sourceGadget == this )
	{
		return true;
	}
	return false;
}

bool StandardConnectionGadget::dragMove( const DragDropEvent &event )
{
	updateDragEndPoint( event.line.p0, V3f( 0 ) );
	return true;
}

bool StandardConnectionGadget::dragEnd( const DragDropEvent &event )
{
	if( !event.destinationGadget || event.destinationGadget == this )
	{
		// noone wanted the drop so we'll disconnect
		Gaffer::UndoContext undoEnabler( dstNodule()->plug()->ancestor<Gaffer::ScriptNode>() );
		dstNodule()->plug()->setInput( 0 );
	}
	else
	{
		// we let the Nodule do all the work when a drop has actually landed
	}

	m_dragEnd = Gaffer::Plug::Invalid;
 	requestRender();
	return true;
}

std::string StandardConnectionGadget::getToolTip( const IECore::LineSegment3f &line ) const
{
	std::string result = Gadget::getToolTip( line );
	if( result.size() )
	{
		return result;
	}

	if( !dstNodule() )
	{
		return result;
	}

	const Gaffer::Plug *dstPlug = dstNodule()->plug();

	int numSkippedDots = 0;
	const Gaffer::Plug *srcPlug = dstPlug->getInput<Gaffer::Plug>();
	while( const Dot *dot = IECore::runTimeCast<const Gaffer::Dot>( srcPlug->node() ) )
	{
		const Gaffer::Plug *inPlug = srcPlug->getInput<Gaffer::Plug>();
		if(
			srcPlug == dot->outPlug<Gaffer::Plug>() &&
			inPlug == dot->inPlug<Gaffer::Plug>() &&
			inPlug->getInput<Gaffer::Plug>()
		)
		{
			srcPlug = inPlug->getInput<Gaffer::Plug>();
			numSkippedDots += 1;
		}
		else
		{
			break;
		}
	}

	const Gaffer::GraphComponent *ancestor = srcPlug->commonAncestor<Gaffer::GraphComponent>( dstPlug );

	std::string srcName;
	std::string dstName;
	if( ancestor )
	{
		srcName = srcPlug->relativeName( ancestor );
		dstName = dstPlug->relativeName( ancestor );
	}
	else
	{
		srcName = srcPlug->fullName();
		dstName = dstPlug->fullName();
	}

	result = srcName + " -> " + dstName;
	if( numSkippedDots )
	{
		result += boost::str(
			boost::format( " (via %d dot%s)" ) % numSkippedDots % ( numSkippedDots > 1 ? "s" : "" )
		);
	}
	return result;
}

void StandardConnectionGadget::enter( const ButtonEvent &event )
{
	m_hovering = endAt( event.line ) != Plug::Invalid;
	requestRender();
}

bool StandardConnectionGadget::mouseMove( const ButtonEvent &event )
{
	m_hovering = endAt( event.line ) != Plug::Invalid;
 	requestRender();
	return false;
}

void StandardConnectionGadget::leave( const ButtonEvent &event )
{
	m_hovering = false;
	requestRender();
}

bool StandardConnectionGadget::nodeSelected( const Nodule *nodule ) const
{
	if( !nodule )
	{
		return false;
	}

	const Gaffer::Node *node = nodule->plug()->node();
	if( !node )
	{
		return false;
	}

	const Gaffer::ScriptNode *script = node->scriptNode();
	return script && script->selection()->contains( node );
}

void StandardConnectionGadget::plugMetadataChanged( IECore::TypeId nodeTypeId, const Gaffer::MatchPattern &plugPath, IECore::InternedString key, const Gaffer::Plug *plug )
{
	const Plug *dstPlug = dstNodule()->plug();
	if( plug && plug != dstPlug )
	{
		return;
	}

	const Node *node = dstPlug->node();
	if(
		key != g_colorKey ||
		!node->isInstanceOf( nodeTypeId ) ||
		!match( dstPlug->relativeName( node ), plugPath )
	)
	{
		return;
	}

	if( updateUserColor() )
	{
 		requestRender();
	}
}

bool StandardConnectionGadget::updateUserColor()
{
	boost::optional<Color3f> c;
	if( IECore::ConstColor3fDataPtr d = Metadata::plugValue<IECore::Color3fData>( dstNodule()->plug(), g_colorKey ) )
	{
		c = d->readable();
	}

	if( c == m_userColor )
	{
		return false;
	}

	m_userColor = c;
	return true;
}
<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 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 the engine header file.
#include <Dreemchest.h>

// Open a root engine namespace
DC_USE_DREEMCHEST

// Open a platform namespace to use shorter types.
using namespace Platform;

// Open a sound namespace.
using namespace Sound;

// Application delegate is used to handle an events raised by application instance.
class SoundPlayback : public ApplicationDelegate {

    // This method will be called once an application is launched.
    virtual void handleLaunched( Application* application ) {
		Sound::log::setStandardHandler();

        // Create the SoundFx instance
		SoundFxPtr sfx = SoundFx::create();

		SoundDataPtr s1 = sfx->createSound( "air_raid", "sounds/air_raid.wav" );
		s1->setLoading( SoundData::LoadToRam );
		s1->setFormat( SoundFormatWav );
		s1->setLooped( false );

		SoundDataPtr s2 = sfx->createSound( "air_raid_m", "sounds/air_raid.ogg" );
		s2->setLoading( SoundData::Stream );
		s2->setFormat( SoundFormatOgg );
		s2->setLooped( true );

		SoundChannelPtr ch = sfx->play( "air_raid" );

		while( true ) {
			sfx->update( 0.1f );

			if( ch.valid() && !ch->isPlaying() ) {
				ch = SoundChannelPtr();
				sfx->play( "air_raid_m" );
			}

			thread::Thread::sleep( 10 );
		}
    }

};

// Now declare an application entry point with Sounds application delegate.
dcDeclareApplication( new SoundPlayback )<commit_msg>Fixed: sound fx example compilation error<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 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 the engine header file.
#include <Dreemchest.h>

// Open a root engine namespace
DC_USE_DREEMCHEST

// Open a platform namespace to use shorter types.
using namespace Platform;

// Open a sound namespace.
using namespace Sound;

// Application delegate is used to handle an events raised by application instance.
class SoundPlayback : public ApplicationDelegate {

    // This method will be called once an application is launched.
    virtual void handleLaunched( Application* application ) {
		Sound::log::setStandardHandler();

        // Create the SoundFx instance
		SoundFxPtr sfx = SoundFx::create();

		SoundDataPtr s1 = sfx->createSound( "air_raid", "sounds/air_raid.wav" );
		s1->setLoading( SoundData::LoadToRam );
		s1->setFormat( SoundFormatWav );
		s1->setLooped( false );

		SoundDataPtr s2 = sfx->createSound( "air_raid_m", "sounds/air_raid.ogg" );
		s2->setLoading( SoundData::Stream );
		s2->setFormat( SoundFormatOgg );
		s2->setLooped( true );

		SoundChannelPtr ch = sfx->play( "air_raid" );

		while( true ) {
			sfx->update( 0.1f );

			if( ch.valid() && !ch->isPlaying() ) {
				ch = SoundChannelPtr();
				sfx->play( "air_raid_m" );
			}

			Threads::Thread::sleep( 10 );
		}
    }

};

// Now declare an application entry point with Sounds application delegate.
dcDeclareApplication( new SoundPlayback )<|endoftext|>


<commit_before>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/find_fn.h"
#include "kernel/inductive/inductive.h"

namespace lean {
bool has_unit_decls(environment const & env) {
    auto d = env.find(name({"unit", "star"}));
    if (!d)
        return false;
    if (length(d->get_univ_params()) != 1)
        return false;
    expr const & type = d->get_type();
    if (!is_constant(type))
        return false;
    return const_name(type) == "unit";
}

bool has_eq_decls(environment const & env) {
    auto d = env.find(name({"eq", "refl"}));
    if (!d)
        return false;
    if (length(d->get_univ_params()) != 1)
        return false;
    expr type = d->get_type();
    if (!is_pi(type) || !is_pi(binding_body(type)))
        return false;
    type = get_app_fn(binding_body(binding_body(type)));
    if (!is_constant(type))
        return false;
    return const_name(type) == "eq";
}

bool has_heq_decls(environment const & env) {
    auto d = env.find(name({"heq", "refl"}));
    if (!d)
        return false;
    if (length(d->get_univ_params()) != 1)
        return false;
    expr type = d->get_type();
    for (unsigned i = 0; i < 2; i++) {
        if (!is_pi(type))
            return type;
        type = binding_body(type);
    }
    type = get_app_fn(type);
    if (!is_constant(type))
        return false;
    return const_name(type) == "heq";
}

bool is_recursive_datatype(environment const & env, name const & n) {
    optional<inductive::inductive_decls> decls = inductive::is_inductive_decl(env, n);
    if (!decls)
        return false;
    for (inductive::inductive_decl const & decl : std::get<2>(*decls)) {
        for (inductive::intro_rule const & intro : inductive::inductive_decl_intros(decl)) {
            expr type = inductive::intro_rule_type(intro);
            while (is_pi(type)) {
                if (find(binding_domain(type), [&](expr const & e, unsigned) {
                            return is_constant(e) && const_name(e) == n; }))
                    return true;
                type = binding_body(type);
            }
        }
    }
    return false;
}

bool is_inductive_predicate(environment const & env, name const & n) {
    if (!env.impredicative())
        return false; // environment does not have Prop
    if (!inductive::is_inductive_decl(env, n))
        return false; // n is not inductive datatype
    expr type = env.get(n).get_type();
    while (is_pi(type)) {
        type = binding_body(type);
    }
    return is_sort(type) && is_zero(sort_level(type));
}
}
<commit_msg>refactor(library/definitional/util): remove code duplication<commit_after>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/find_fn.h"
#include "kernel/inductive/inductive.h"

namespace lean {
/** \brief Return true if environment has a constructor named \c c that returns
    an element of the inductive datatype named \c I, and \c c must have \c nparams parameters.
*/
bool has_constructor(environment const & env, name const & c, name const & I, unsigned nparams) {
    auto d = env.find(c);
    if (!d || d->is_definition())
        return false;
    expr type = d->get_type();
    unsigned i = 0;
    while (is_pi(type)) {
        i++;
        type = binding_body(type);
    }
    if (i != nparams)
        return false;
    type = get_app_fn(type);
    return is_constant(type) && const_name(type) == I;
}

bool has_unit_decls(environment const & env) {
    return has_constructor(env, name{"unit", "star"}, "unit", 0);
}

bool has_eq_decls(environment const & env) {
    return has_constructor(env, name{"eq", "refl"}, "eq", 2);
}

bool has_heq_decls(environment const & env) {
    return has_constructor(env, name{"heq", "refl"}, "heq", 2);
}

bool is_recursive_datatype(environment const & env, name const & n) {
    optional<inductive::inductive_decls> decls = inductive::is_inductive_decl(env, n);
    if (!decls)
        return false;
    for (inductive::inductive_decl const & decl : std::get<2>(*decls)) {
        for (inductive::intro_rule const & intro : inductive::inductive_decl_intros(decl)) {
            expr type = inductive::intro_rule_type(intro);
            while (is_pi(type)) {
                if (find(binding_domain(type), [&](expr const & e, unsigned) {
                            return is_constant(e) && const_name(e) == n; }))
                    return true;
                type = binding_body(type);
            }
        }
    }
    return false;
}

bool is_inductive_predicate(environment const & env, name const & n) {
    if (!env.impredicative())
        return false; // environment does not have Prop
    if (!inductive::is_inductive_decl(env, n))
        return false; // n is not inductive datatype
    expr type = env.get(n).get_type();
    while (is_pi(type)) {
        type = binding_body(type);
    }
    return is_sort(type) && is_zero(sort_level(type));
}
}
<|endoftext|>


<commit_before><commit_msg>Add 3<commit_after><|endoftext|>


<commit_before>#ifndef SOFTCIRCLE_HPP
#define SOFTCIRCLE_HPP

#include "body.hpp"
#include "NotDrawableCircle.hpp"

class SoftCircle : public Body // , Sprite
{

    public :
        SoftCircle(float posx,float posy,float rayon,float duretee=0.5f,const unsigned int quality=24);
        void Draw(sf::RenderTarget& window);
        inline void SetTexture(GLuint t){texture =t;}
        ~SoftCircle();

    private:
        const unsigned int nb_circles;
        NotDrawableCircleBody** bodys;

        struct fpoint{
            float x,y;
        };
        fpoint* textcoord;
        GLuint texture;

};

#endif

<commit_msg>ajout d'une description à la class pour avertir de son coup d'utilisation<commit_after>#ifndef SOFTCIRCLE_HPP
#define SOFTCIRCLE_HPP

#include "body.hpp"
#include "NotDrawableCircle.hpp"

/***************************************
*   Attention avec l'utilisation de
    cette classe.
    Le moteur physique n'est pas fait
    pour gérer les corps mous.
    Par concéquent, cela coute beaucoup en
    ressources.
    Elle est totalement inutile si la
    duretée est mise à 1
    Utiliser CircleBody à la place quand
    cela est possible.
******************************************/

class SoftCircle : public Body // , Sprite
{

    public :
        SoftCircle(float posx,float posy,float rayon,float duretee=0.5f,const unsigned int quality=24);
        void Draw(sf::RenderTarget& window);
        inline void SetTexture(GLuint t){texture =t;}
        ~SoftCircle();

    private:
        const unsigned int nb_circles;
        NotDrawableCircleBody** bodys;

        struct fpoint{
            float x,y;
        };
        fpoint* textcoord;
        GLuint texture;

};

#endif

<|endoftext|>


<commit_before>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "test_utils.h"

#include "gtest/gtest.h"

#include <libcellml>

static const std::string EMPTY_STRING = "";

TEST(Generator, emptyModel) {
    libcellml::ModelPtr model = std::make_shared<libcellml::Model>();

    model->setName("emptyModel");

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());

    EXPECT_EQ(size_t(0), generator.stateCount());
    EXPECT_EQ(size_t(0), generator.rateCount());
    EXPECT_EQ(size_t(0), generator.variableCount());

    EXPECT_EQ(EMPTY_STRING, generator.neededMathMethods());
    EXPECT_EQ(EMPTY_STRING, generator.initializeVariables());
    EXPECT_EQ(EMPTY_STRING, generator.computeConstantEquations());
    EXPECT_EQ(EMPTY_STRING, generator.computeRateEquations());
    EXPECT_EQ(EMPTY_STRING, generator.computeAlgebraicEquations());
}

/*TODO: reenable this test once we can correctly type a model's variables.
TEST(Generator, coverage) {
//TODO: code should be generated for the coverage CellML file with and without
//      the Generator's private mHasXXX booleans set, so that we really cover
//      everything indeed.
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/coverage.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());
}
*/

TEST(Generator, initialized_variable_of_integration) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/initialized_variable_of_integration.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'time' in component 'main' of model 'initialized_variable_of_integration' cannot be both a variable of integration and initialised."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
        EXPECT_EQ(libcellml::Error::Kind::GENERATOR, generator.getError(i)->getKind());
    }
}

TEST(Generator, two_variables_of_integration) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/two_variables_of_integration.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'time' in component 'main' of model 'two_variables_of_integration' and variable 'other_time' in component 'sub_sub_sub' of model 'two_variables_of_integration' cannot both be a variable of integration."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
        EXPECT_EQ(libcellml::Error::Kind::GENERATOR, generator.getError(i)->getKind());
    }
}

TEST(Generator, non_first_order_odes) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/non_first_order_odes.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "The differential equation for variable 'x' in component 'main' of model 'non_first_order_odes' must be of the first order.",
        "The differential equation for variable 'y' in component 'sub' of model 'non_first_order_odes' must be of the first order.",
        "The differential equation for variable 'z' in component 'sub_sub' of model 'non_first_order_odes' must be of the first order."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
        EXPECT_EQ(libcellml::Error::Kind::GENERATOR, generator.getError(i)->getKind());
    }
}

TEST(Generator, variable_initialized_twice) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/variable_initialized_twice.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'x' in component 'sub' of model 'variable_initialized_twice' and variable 'x' in component 'main' of model 'variable_initialized_twice' are equivalent and cannot therefore both be initialised."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
    }
}

TEST(Generator, non_initialized_state) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/non_initialized_state.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'x' in component 'main' of model 'non_initialized_state' is used in an ODE, but it is not initialised."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
    }
}

/*TODO: reenable this test once we are done with the previous tests.
TEST(Generator, algebraic_eqn_derivative_on_rhs_one_component) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/model.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());

    EXPECT_EQ(size_t(1), generator.stateCount());
    EXPECT_EQ(size_t(1), generator.rateCount());
    EXPECT_EQ(size_t(2), generator.variableCount());

    EXPECT_EQ(EMPTY_STRING, generator.neededMathMethods());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/initializeVariables.out"),
              generator.initializeVariables());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeConstantEquations.out"),
              generator.computeConstantEquations());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeRateEquations.out"),
              generator.computeRateEquations());
    EXPECT_EQ(EMPTY_STRING,
              generator.computeAlgebraicEquations());

    generator.setWithNames(true);

    EXPECT_EQ(EMPTY_STRING, generator.neededMathMethods());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/initializeVariables_with_names.out"),
              generator.initializeVariables());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeConstantEquations_with_names.out"),
              generator.computeConstantEquations());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeRateEquations_with_names.out"),
              generator.computeRateEquations());
    EXPECT_EQ(EMPTY_STRING,
              generator.computeAlgebraicEquations());
}
*/

//TODO: remove the below test once we are done testing things...
TEST(Generator, test) {
    libcellml::Parser parser;
//libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/hodgkin_huxley_squid_axon_model_1952.cellml"));
//libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/noble_model_1962.cellml"));
libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/van_der_pol_model_1928.cellml"));
//libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/zhang_SAN_model_2000_all.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());
}
<commit_msg>Generator test: slight improvements to our algebraic_eqn_derivative_on_rhs_one_component test.<commit_after>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "test_utils.h"

#include "gtest/gtest.h"

#include <libcellml>

static const std::string EMPTY_STRING = "";

TEST(Generator, emptyModel) {
    libcellml::ModelPtr model = std::make_shared<libcellml::Model>();

    model->setName("emptyModel");

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());

    EXPECT_EQ(size_t(0), generator.stateCount());
    EXPECT_EQ(size_t(0), generator.rateCount());
    EXPECT_EQ(size_t(0), generator.variableCount());

    EXPECT_EQ(EMPTY_STRING, generator.neededMathMethods());
    EXPECT_EQ(EMPTY_STRING, generator.initializeVariables());
    EXPECT_EQ(EMPTY_STRING, generator.computeConstantEquations());
    EXPECT_EQ(EMPTY_STRING, generator.computeRateEquations());
    EXPECT_EQ(EMPTY_STRING, generator.computeAlgebraicEquations());
}

/*TODO: reenable this test once we can correctly type a model's variables.
TEST(Generator, coverage) {
//TODO: code should be generated for the coverage CellML file with and without
//      the Generator's private mHasXXX booleans set, so that we really cover
//      everything indeed.
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/coverage.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());
}
*/

TEST(Generator, initialized_variable_of_integration) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/initialized_variable_of_integration.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'time' in component 'main' of model 'initialized_variable_of_integration' cannot be both a variable of integration and initialised."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
        EXPECT_EQ(libcellml::Error::Kind::GENERATOR, generator.getError(i)->getKind());
    }
}

TEST(Generator, two_variables_of_integration) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/two_variables_of_integration.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'time' in component 'main' of model 'two_variables_of_integration' and variable 'other_time' in component 'sub_sub_sub' of model 'two_variables_of_integration' cannot both be a variable of integration."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
        EXPECT_EQ(libcellml::Error::Kind::GENERATOR, generator.getError(i)->getKind());
    }
}

TEST(Generator, non_first_order_odes) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/non_first_order_odes.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "The differential equation for variable 'x' in component 'main' of model 'non_first_order_odes' must be of the first order.",
        "The differential equation for variable 'y' in component 'sub' of model 'non_first_order_odes' must be of the first order.",
        "The differential equation for variable 'z' in component 'sub_sub' of model 'non_first_order_odes' must be of the first order."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
        EXPECT_EQ(libcellml::Error::Kind::GENERATOR, generator.getError(i)->getKind());
    }
}

TEST(Generator, variable_initialized_twice) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/variable_initialized_twice.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'x' in component 'sub' of model 'variable_initialized_twice' and variable 'x' in component 'main' of model 'variable_initialized_twice' are equivalent and cannot therefore both be initialised."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
    }
}

TEST(Generator, non_initialized_state) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/non_initialized_state.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    std::vector<std::string> expectedErrors = {
        "Variable 'x' in component 'main' of model 'non_initialized_state' is used in an ODE, but it is not initialised."
    };

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(expectedErrors.size(), generator.errorCount());

    for (size_t i = 0; i < generator.errorCount(); ++i) {
        EXPECT_EQ(expectedErrors.at(i), generator.getError(i)->getDescription());
    }
}

/*TODO: reenable this test once we are done with the previous tests.
TEST(Generator, algebraic_eqn_derivative_on_rhs_one_component) {
    libcellml::Parser parser;
    libcellml::ModelPtr model = parser.parseModel(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/model.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());

    EXPECT_EQ(libcellml::Generator::Type::ALGEBRAIC, generator.type());

    EXPECT_EQ(size_t(1), generator.stateCount());
    EXPECT_EQ(size_t(2), generator.variableCount());

    EXPECT_EQ(EMPTY_STRING, generator.neededMathMethods());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/initializeVariables.out"),
              generator.initializeVariables());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeConstantEquations.out"),
              generator.computeConstantEquations());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeRateEquations.out"),
              generator.computeRateEquations());
    EXPECT_EQ(EMPTY_STRING,
              generator.computeAlgebraicEquations());

    generator.setWithNames(true);

    EXPECT_EQ(EMPTY_STRING, generator.neededMathMethods());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/initializeVariables_with_names.out"),
              generator.initializeVariables());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeConstantEquations_with_names.out"),
              generator.computeConstantEquations());
    EXPECT_EQ(fileContents("generator/resources/algebraic_eqn_derivative_on_rhs_one_component/computeRateEquations_with_names.out"),
              generator.computeRateEquations());
    EXPECT_EQ(EMPTY_STRING,
              generator.computeAlgebraicEquations());
}
*/

//TODO: remove the below test once we are done testing things...
TEST(Generator, test) {
    libcellml::Parser parser;
//libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/hodgkin_huxley_squid_axon_model_1952.cellml"));
//libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/noble_model_1962.cellml"));
libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/van_der_pol_model_1928.cellml"));
//libcellml::ModelPtr model = parser.parseModel(fileContents("../../../../Desktop/zhang_SAN_model_2000_all.cellml"));

    EXPECT_EQ(size_t(0), parser.errorCount());

    libcellml::Generator generator;

    generator.processModel(model);

    EXPECT_EQ(size_t(0), generator.errorCount());
}
<|endoftext|>


<commit_before><commit_msg>Delete rtest_ac_sincos_lut.cpp<commit_after><|endoftext|>