<commit_before>/*
 * Copyright 2017, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#include <chrono>
#include <conwrap/ProcessorAsio.hpp>
#include <csignal>
#include <cxxopts.hpp>
#include <exception>
#include <fstream>
#include <g3log/logworker.hpp>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "slim/alsa/Parameters.hpp"
#include "slim/alsa/Source.hpp"
#include "slim/conn/Callbacks.hpp"
#include "slim/conn/Server.hpp"
#include "slim/Consumer.hpp"
#include "slim/Container.hpp"
#include "slim/Exception.hpp"
#include "slim/FileConsumer.hpp"
#include "slim/flac/Encoder.hpp"
#include "slim/log/ConsoleSink.hpp"
#include "slim/log/log.hpp"
#include "slim/Pipeline.hpp"
#include "slim/Producer.hpp"
#include "slim/proto/Streamer.hpp"
#include "slim/Scheduler.hpp"
#include "slim/util/StreamWriter.hpp"

#include "slim/util/BufferedWriter.hpp"

using ContainerBase = slim::ContainerBase;
using Connection    = slim::conn::Connection<ContainerBase>;
using Server        = slim::conn::Server<ContainerBase>;
using Callbacks     = slim::conn::Callbacks<ContainerBase>;
using Encoder       = slim::flac::Encoder;
using Streamer      = slim::proto::Streamer<Connection, Encoder>;

using Source        = slim::alsa::Source;
using File          = slim::FileConsumer<Encoder>;
using Pipeline      = slim::Pipeline;
using Scheduler     = slim::Scheduler;

using Container     = slim::Container<Scheduler, Server, Server, Streamer>;

static volatile bool running = true;

void signalHandler(int sig)
{
	running = false;
}

void printVersionInfo()
{
	std::cout << "SlimStreamer version " << VERSION << std::endl;
}

void printLicenseInfo()
{
	printVersionInfo();

	std::cout << std::endl;
	std::cout << "Copyright 2017, Andrej Kislovskij" << std::endl;
	std::cout << std::endl;
	std::cout << "This is PUBLIC DOMAIN software so use at your own risk as it comes" << std::endl;
	std::cout << "with no warranties. This code is yours to share, use and modify without" << std::endl;
	std::cout << "any restrictions or obligations." << std::endl;
	std::cout << std::endl;
	std::cout << "For more information see conwrap/LICENSE or refer refer to http://unlicense.org" << std::endl;
	std::cout << std::endl;
	std::cout << "Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)" << std::endl;
	std::cout << std::endl;
	std::cout << "SlimStreamer relies a lot on numerous libraries, which where tailored as required:" << std::endl;
	std::cout << "-> Concurrent Wrapper for asynchronous tasks (Public Domain)" << std::endl;
	std::cout << "-> Logging library 'g3log' (Public Domain)" << std::endl;
	std::cout << "-> Standalone version of 'asio' for networking (Boost Software License)" << std::endl;
	std::cout << "-> Command line options parser 'cxxopts' (MIT)" << std::endl;
	std::cout << "-> Zero overhead data types 'type_safe' (MIT)" << std::endl;
	std::cout << "-> Scope guard library 'Boost.ScopeGuard' (Boost Software License 1.0)" << std::endl;
	std::cout << "-> Unit testing library 'googletest' (BSD-3-Clause)" << std::endl;
	std::cout << std::endl;
	std::cout << "Important note: used dependencies may rely on other dependencies shipped with correspondent license." << std::endl;
	std::cout << std::endl;
}

auto createCommandCallbacks(Streamer& streamer)
{
	return std::move(Callbacks{}
		.setOpenCallback([&](auto& connection)
		{
			streamer.onSlimProtoOpen(connection);
		})
		.setDataCallback([&](auto& connection, unsigned char* buffer, const std::size_t size)
		{
			streamer.onSlimProtoData(connection, buffer, size);
		})
		.setCloseCallback([&](auto& connection)
		{
			streamer.onSlimProtoClose(connection);
		}));
}

auto createStreamingCallbacks(Streamer& streamer)
{
	return std::move(Callbacks{}
		.setOpenCallback([&](auto& connection)
		{
			streamer.onHTTPOpen(connection);
		})
		.setDataCallback([&](auto& connection, unsigned char* buffer, const std::size_t size)
		{
			streamer.onHTTPData(connection, buffer, size);
		})
		.setCloseCallback([&](auto& connection)
		{
			streamer.onHTTPClose(connection);
		}));
}

auto createPipelines(std::vector<std::unique_ptr<Source>>& sources, Streamer& streamer, std::vector<std::unique_ptr<File>>& files)
{
	std::vector<Pipeline> pipelines;

	for (auto& sourcePtr : sources)
	{
		auto parameters{sourcePtr->getParameters()};

		//auto streamPtr{std::make_unique<std::ofstream>(std::to_string(parameters.getSamplingRate()) + ".flac", std::ios::binary)};
		//auto writerPtr{std::make_unique<slim::util::SyncStreamWriter>(std::move(streamPtr))};
		//auto filePtr{std::make_unique<File>(std::move(writerPtr), 2, parameters.getSamplingRate(), 32)};

		//pipelines.emplace_back(sourcePtr.get(), filePtr.get());
		//files.push_back(std::move(filePtr));

		pipelines.emplace_back(sourcePtr.get(), &streamer);
	}

	return std::move(pipelines);
}

auto createSources()
{
	std::vector<std::tuple<unsigned int, std::string>> rates
	{
		{8000,   "hw:1,1,1"},
		{11025,  "hw:1,1,2"},
		{12000,  "hw:1,1,3"},
		{16000,  "hw:1,1,4"},
		{22500,  "hw:1,1,5"},
		{24000,  "hw:1,1,6"},
		{32000,  "hw:1,1,7"},
		{44100,  "hw:2,1,1"},
		{48000,  "hw:2,1,2"},
		{88200,  "hw:2,1,3"},
		{96000,  "hw:2,1,4"},
		{176400, "hw:2,1,5"},
		{192000, "hw:2,1,6"},
	};

	slim::alsa::Parameters               parameters{"", 3, SND_PCM_FORMAT_S32_LE, 0, 128, 0, 8};
	unsigned int                         chunkDurationMilliSecond{100};
	std::vector<std::unique_ptr<Source>> sources;

	for (auto& rate : rates)
	{
		auto[rateValue, deviceValue] = rate;

		parameters.setSamplingRate(rateValue);
		parameters.setDeviceName(deviceValue);
		parameters.setFramesPerChunk((rateValue * chunkDurationMilliSecond) / 1000);

		sources.push_back(std::make_unique<Source>(parameters));
	}

	return std::move(sources);
}

int main(int argc, const char *argv[])
{
	// initializing log and adding custom sink
	auto logWorkerPtr = g3::LogWorker::createLogWorker();
	g3::initializeLogging(logWorkerPtr.get());
	g3::only_change_at_initialization::addLogLevel(ERROR);
    logWorkerPtr->addSink(std::make_unique<ConsoleSink>(), &ConsoleSink::print);

    try
	{
		// defining supported options
		cxxopts::Options options("SlimStreamer", "SlimStreamer - A multi-room bit-perfect streamer for systemwise audio\n");
		options
			.custom_help("[options]")
			.add_options()
				("c,maxclients", "Maximum amount of clients able to connect", cxxopts::value<int>()->default_value("10"), "<number>")
				("g,gain", "Client audio gain", cxxopts::value<unsigned int>(), "<0-100>")
				("h,help", "Print this help message", cxxopts::value<bool>())
				("l,license", "Print license details", cxxopts::value<bool>())
				("s,slimprotoport", "SlimProto (command connection) server port", cxxopts::value<int>()->default_value("3483"), "<port>")
				("t,httpport", "HTTP (streaming connection) server port", cxxopts::value<int>()->default_value("9000"), "<port>")
				("v,version", "Print version details", cxxopts::value<bool>());

		// parsing provided options
		auto result = options.parse(argc, argv);

		if (result.count("help"))
		{
			std::cout << options.help() << std::endl;
		}
		else if (result.count("license"))
		{
			printLicenseInfo();
		}
		else if (result.count("version"))
		{
			printVersionInfo();
		}
		else
		{
			// setting mandatory parameters
			auto maxClients    = result["maxclients"].as<int>();
			auto slimprotoPort = result["slimprotoport"].as<int>();
			auto httpPort      = result["httpport"].as<int>();

			// setting optional parameters
			std::optional<unsigned int> gain{std::nullopt};
			if (result.count("gain"))
			{
				gain = result["gain"].as<unsigned int>();
			}

			// creating source objects stored in a vector
			auto sources{createSources()};

			// Callbacks objects 'glue' SlimProto Streamer with TCP Command Servers
			auto streamerPtr{std::make_unique<Streamer>(httpPort, gain)};
			auto commandServerPtr{std::make_unique<Server>(slimprotoPort, maxClients, createCommandCallbacks(*streamerPtr))};
			auto streamingServerPtr{std::make_unique<Server>(httpPort, maxClients, createStreamingCallbacks(*streamerPtr))};

			// creating a container for files objects
			std::vector<std::unique_ptr<File>> files;

			// creating Scheduler object with destination directed to slimproto Streamer
			auto schedulerPtr{std::make_unique<Scheduler>(createPipelines(sources, *streamerPtr, files))};

			// creating Container object within Asio Processor with Scheduler and Servers
			conwrap::ProcessorAsio<ContainerBase> processorAsio
			{
				std::unique_ptr<ContainerBase>
				{
					new Container(std::move(schedulerPtr), std::move(commandServerPtr), std::move(streamingServerPtr), std::move(streamerPtr))
				}
			};

			// start streaming
			LOG(INFO) << "Starting SlimStreamer...";
			auto startStatus = processorAsio.process([](auto context) -> bool
			{
				auto started{false};

				try
				{
					context.getResource()->start();
					started = true;
				}
				catch (const std::exception& error)
				{
					LOG(ERROR) << error.what();
				}
				catch (...)
				{
					std::cout << "Unexpected exception" << std::endl;
				}

				return started;
			});
			if (startStatus.get())
			{
				LOG(INFO) << "SlimStreamer was started";

				// registering signal handler
				signal(SIGHUP, signalHandler);
				signal(SIGTERM, signalHandler);
				signal(SIGINT, signalHandler);

				// waiting for Control^C
				while(running)
				{
					std::this_thread::sleep_for(std::chrono::milliseconds{200});
				}

				// stop streaming
				LOG(INFO) << "Stopping SlimStreamer...";
				processorAsio.process([](auto context)
				{
					context.getResource()->stop();
				}).wait();
				LOG(INFO) << "SlimStreamer was stopped";
			}
		}
	}
	catch (const cxxopts::OptionException& e)
	{
		std::cout << "Wrong option(s) provided: " << e.what() << std::endl;
	}
	catch (const slim::Exception& error)
	{
		LOG(ERROR) << error;
	}
	catch (const std::exception& error)
	{
		LOG(ERROR) << error.what();
	}
	catch (...)
	{
		std::cout << "Unexpected exception" << std::endl;
	}

	return 0;
}
<commit_msg>Minor change<commit_after>/*
 * Copyright 2017, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#include <chrono>
#include <conwrap/ProcessorAsio.hpp>
#include <csignal>
#include <cxxopts.hpp>
#include <exception>
#include <fstream>
#include <g3log/logworker.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "slim/alsa/Parameters.hpp"
#include "slim/alsa/Source.hpp"
#include "slim/conn/Callbacks.hpp"
#include "slim/conn/Server.hpp"
#include "slim/Consumer.hpp"
#include "slim/Container.hpp"
#include "slim/Exception.hpp"
#include "slim/FileConsumer.hpp"
#include "slim/flac/Encoder.hpp"
#include "slim/log/ConsoleSink.hpp"
#include "slim/log/log.hpp"
#include "slim/Pipeline.hpp"
#include "slim/Producer.hpp"
#include "slim/proto/Streamer.hpp"
#include "slim/Scheduler.hpp"
#include "slim/util/StreamWriter.hpp"

#include "slim/util/BufferedWriter.hpp"

using ContainerBase = slim::ContainerBase;
using Connection    = slim::conn::Connection<ContainerBase>;
using Server        = slim::conn::Server<ContainerBase>;
using Callbacks     = slim::conn::Callbacks<ContainerBase>;
using Encoder       = slim::flac::Encoder;
using Streamer      = slim::proto::Streamer<Connection, Encoder>;

using Source        = slim::alsa::Source;
using File          = slim::FileConsumer<Encoder>;
using Pipeline      = slim::Pipeline;
using Scheduler     = slim::Scheduler;

using Container     = slim::Container<Scheduler, Server, Server, Streamer>;

static volatile bool running = true;

void signalHandler(int sig)
{
	running = false;
}

void printVersionInfo()
{
	std::cout << "SlimStreamer version " << VERSION << std::endl;
}

void printLicenseInfo()
{
	printVersionInfo();

	std::cout << std::endl;
	std::cout << "Copyright 2017, Andrej Kislovskij" << std::endl;
	std::cout << std::endl;
	std::cout << "This is PUBLIC DOMAIN software so use at your own risk as it comes" << std::endl;
	std::cout << "with no warranties. This code is yours to share, use and modify without" << std::endl;
	std::cout << "any restrictions or obligations." << std::endl;
	std::cout << std::endl;
	std::cout << "For more information see conwrap/LICENSE or refer refer to http://unlicense.org" << std::endl;
	std::cout << std::endl;
	std::cout << "Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)" << std::endl;
	std::cout << std::endl;
	std::cout << "SlimStreamer relies a lot on numerous libraries, which where tailored as required:" << std::endl;
	std::cout << "-> Concurrent Wrapper for asynchronous tasks (Public Domain)" << std::endl;
	std::cout << "-> Logging library 'g3log' (Public Domain)" << std::endl;
	std::cout << "-> Standalone version of 'asio' for networking (Boost Software License)" << std::endl;
	std::cout << "-> Command line options parser 'cxxopts' (MIT)" << std::endl;
	std::cout << "-> Zero overhead data types 'type_safe' (MIT)" << std::endl;
	std::cout << "-> Scope guard library 'Boost.ScopeGuard' (Boost Software License 1.0)" << std::endl;
	std::cout << "-> Unit testing library 'googletest' (BSD-3-Clause)" << std::endl;
	std::cout << std::endl;
	std::cout << "Important note: used dependencies may rely on other dependencies shipped with correspondent license." << std::endl;
	std::cout << std::endl;
}

auto createCommandCallbacks(Streamer& streamer)
{
	return std::move(Callbacks{}
		.setOpenCallback([&](auto& connection)
		{
			streamer.onSlimProtoOpen(connection);
		})
		.setDataCallback([&](auto& connection, unsigned char* buffer, const std::size_t size)
		{
			streamer.onSlimProtoData(connection, buffer, size);
		})
		.setCloseCallback([&](auto& connection)
		{
			streamer.onSlimProtoClose(connection);
		}));
}

auto createStreamingCallbacks(Streamer& streamer)
{
	return std::move(Callbacks{}
		.setOpenCallback([&](auto& connection)
		{
			streamer.onHTTPOpen(connection);
		})
		.setDataCallback([&](auto& connection, unsigned char* buffer, const std::size_t size)
		{
			streamer.onHTTPData(connection, buffer, size);
		})
		.setCloseCallback([&](auto& connection)
		{
			streamer.onHTTPClose(connection);
		}));
}

auto createPipelines(std::vector<std::unique_ptr<Source>>& sources, Streamer& streamer, std::vector<std::unique_ptr<File>>& files)
{
	std::vector<Pipeline> pipelines;

	for (auto& sourcePtr : sources)
	{
		auto parameters{sourcePtr->getParameters()};

		//auto streamPtr{std::make_unique<std::ofstream>(std::to_string(parameters.getSamplingRate()) + ".flac", std::ios::binary)};
		//auto writerPtr{std::make_unique<slim::util::SyncStreamWriter>(std::move(streamPtr))};
		//auto filePtr{std::make_unique<File>(std::move(writerPtr), 2, parameters.getSamplingRate(), 32)};

		//pipelines.emplace_back(sourcePtr.get(), filePtr.get());
		//files.push_back(std::move(filePtr));

		pipelines.emplace_back(sourcePtr.get(), &streamer);
	}

	return std::move(pipelines);
}

auto createSources()
{
	std::vector<std::tuple<unsigned int, std::string>> rates
	{
		{8000,   "hw:1,1,1"},
		{11025,  "hw:1,1,2"},
		{12000,  "hw:1,1,3"},
		{16000,  "hw:1,1,4"},
		{22500,  "hw:1,1,5"},
		{24000,  "hw:1,1,6"},
		{32000,  "hw:1,1,7"},
		{44100,  "hw:2,1,1"},
		{48000,  "hw:2,1,2"},
		{88200,  "hw:2,1,3"},
		{96000,  "hw:2,1,4"},
		{176400, "hw:2,1,5"},
		{192000, "hw:2,1,6"},
	};

	slim::alsa::Parameters               parameters{"", 3, SND_PCM_FORMAT_S32_LE, 0, 128, 0, 8};
	unsigned int                         chunkDurationMilliSecond{100};
	std::vector<std::unique_ptr<Source>> sources;

	for (auto& rate : rates)
	{
		auto[rateValue, deviceValue] = rate;

		parameters.setSamplingRate(rateValue);
		parameters.setDeviceName(deviceValue);
		parameters.setFramesPerChunk((rateValue * chunkDurationMilliSecond) / 1000);

		sources.push_back(std::make_unique<Source>(parameters));
	}

	return std::move(sources);
}

int main(int argc, const char *argv[])
{
	// initializing log and adding custom sink
	auto logWorkerPtr = g3::LogWorker::createLogWorker();
	g3::initializeLogging(logWorkerPtr.get());
	g3::only_change_at_initialization::addLogLevel(ERROR);
    logWorkerPtr->addSink(std::make_unique<ConsoleSink>(), &ConsoleSink::print);

    try
	{
		// defining supported options
		cxxopts::Options options("SlimStreamer", "SlimStreamer - A multi-room bit-perfect streamer for systemwise audio\n");
		options
			.custom_help("[options]")
			.add_options()
				("c,maxclients", "Maximum amount of clients able to connect", cxxopts::value<int>()->default_value("10"), "<number>")
				("g,gain", "Client audio gain", cxxopts::value<unsigned int>(), "<0-100>")
				("h,help", "Print this help message", cxxopts::value<bool>())
				("l,license", "Print license details", cxxopts::value<bool>())
				("s,slimprotoport", "SlimProto (command connection) server port", cxxopts::value<int>()->default_value("3483"), "<port>")
				("t,httpport", "HTTP (streaming connection) server port", cxxopts::value<int>()->default_value("9000"), "<port>")
				("v,version", "Print version details", cxxopts::value<bool>());

		// parsing provided options
		auto result = options.parse(argc, argv);

		if (result.count("help"))
		{
			std::cout << options.help() << std::endl;
		}
		else if (result.count("license"))
		{
			printLicenseInfo();
		}
		else if (result.count("version"))
		{
			printVersionInfo();
		}
		else
		{
			// setting mandatory parameters
			auto maxClients    = result["maxclients"].as<int>();
			auto slimprotoPort = result["slimprotoport"].as<int>();
			auto httpPort      = result["httpport"].as<int>();

			// setting optional parameters
			std::optional<unsigned int> gain{std::nullopt};
			if (result.count("gain"))
			{
				gain = result["gain"].as<unsigned int>();
			}

			// creating source objects stored in a vector
			auto sources{createSources()};

			// Callbacks objects 'glue' SlimProto Streamer with TCP Command Servers
			auto streamerPtr{std::make_unique<Streamer>(httpPort, gain)};
			auto commandServerPtr{std::make_unique<Server>(slimprotoPort, maxClients, createCommandCallbacks(*streamerPtr))};
			auto streamingServerPtr{std::make_unique<Server>(httpPort, maxClients, createStreamingCallbacks(*streamerPtr))};

			// creating a container for files objects
			std::vector<std::unique_ptr<File>> files;

			// creating Scheduler object with destination directed to slimproto Streamer
			auto schedulerPtr{std::make_unique<Scheduler>(createPipelines(sources, *streamerPtr, files))};

			// creating Container object within Asio Processor with Scheduler and Servers
			conwrap::ProcessorAsio<ContainerBase> processorAsio
			{
				std::unique_ptr<ContainerBase>
				{
					new Container(std::move(schedulerPtr), std::move(commandServerPtr), std::move(streamingServerPtr), std::move(streamerPtr))
				}
			};

			// start streaming
			LOG(INFO) << "Starting SlimStreamer...";
			auto startStatus = processorAsio.process([](auto context) -> bool
			{
				auto started{false};

				try
				{
					context.getResource()->start();
					started = true;
				}
				catch (const std::exception& error)
				{
					LOG(ERROR) << error.what();
				}
				catch (...)
				{
					std::cout << "Unexpected exception" << std::endl;
				}

				return started;
			});
			if (startStatus.get())
			{
				LOG(INFO) << "SlimStreamer was started";

				// registering signal handler
				signal(SIGHUP, signalHandler);
				signal(SIGTERM, signalHandler);
				signal(SIGINT, signalHandler);

				// waiting for Control^C
				while(running)
				{
					std::this_thread::sleep_for(std::chrono::milliseconds{200});
				}

				// stop streaming
				LOG(INFO) << "Stopping SlimStreamer...";
				processorAsio.process([](auto context)
				{
					context.getResource()->stop();
				}).wait();
				LOG(INFO) << "SlimStreamer was stopped";
			}
		}
	}
	catch (const cxxopts::OptionException& e)
	{
		std::cout << "Wrong option(s) provided: " << e.what() << std::endl;
	}
	catch (const slim::Exception& error)
	{
		LOG(ERROR) << error;
	}
	catch (const std::exception& error)
	{
		LOG(ERROR) << error.what();
	}
	catch (...)
	{
		std::cout << "Unexpected exception" << std::endl;
	}

	return 0;
}
<|endoftext|>


<commit_before>// Copyright 2016 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <vector>
#include <iostream>
#include <exception>
#include <iomanip>
#include <random>
#include <algorithm>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Stencil.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * output_d, const unsigned int outputSize);

int main(int argc, char * argv[]) {
  bool reInit = true;
  unsigned int nrIterations = 0;
  unsigned int samplingFactor = 100;
  unsigned int clPlatformID = 0;
  unsigned int clDeviceID = 0;
  unsigned int vectorSize = 0;
  unsigned int maxThreads = 0;
  unsigned int maxItems = 0;
  unsigned int matrixWidth = 0;
  unsigned int padding = 0;
  // Random number generation
  std::random_device randomDevice;
  std::default_random_engine randomEngine(randomDevice());
  std::uniform_int_distribution<unsigned int> uniformDistribution(0, magicValue);

  try {
    isa::utils::ArgumentList args(argc, argv);

    clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
    clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    if ( args.getSwitch("-sampling") ) {
      samplingFactor = args.getSwitchArgument< unsigned int >("-factor");
    }
    nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
    vectorSize = args.getSwitchArgument< unsigned int >("-vector");
    padding = args.getSwitchArgument< unsigned int >("-padding");
    maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
    maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    matrixWidth = args.getSwitchArgument< unsigned int >("-matrix_width");
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << argv[0] << " -opencl_platform ... -opencl_device ... [-sampling -factor ...] -iterations ... -vector ... -padding ... -max_threads ... -max_items ... -matrix_width ..." << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  cl::Context clContext;
  std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
  std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
  std::vector< std::vector< cl::CommandQueue > > * clQueues = 0;

  // Allocate host memory
  std::vector< inputDataType > input((matrixWidth + 2) * isa::utils::pad(matrixWidth + 2, padding)), output(matrixWidth * isa::utils::pad(matrixWidth, padding)), output_c;
  cl::Buffer input_d, output_d;

  for ( unsigned int y = 0; y < matrixWidth + 2; y++ ) {
    for ( unsigned int x = 0; x < matrixWidth + 2; x++ ) {
      if ( y == 0 || y == (matrixWidth - 1) ) {
        input[(y * isa::utils::pad(matrixWidth + 2, padding)) + x] = 0;
      } else if ( x == 0 || x == (matrixWidth - 1) ) {
        input[(y * isa::utils::pad(matrixWidth + 2, padding)) + x] = 0;
      } else {
        input[(y * isa::utils::pad(matrixWidth + 2, padding)) + x] = uniformDistribution(randomEngine);
      }
    }
  }
  output_c.resize(output.size());

  // Run the control
  TuneBench::stencil2D(input, output_c, matrixWidth, padding);

  // Generate tuning configurations
  std::vector<TuneBench::Stencil2DConf> configurations;
  for ( unsigned int threadsD0 = vectorSize; threadsD0 <= maxThreads; threadsD0 += vectorSize) {
    for ( unsigned int threadsD1 = 1; threadsD0 * threadsD1 <= maxThreads; threadsD1++ ) {
      for ( unsigned int itemsD0 = 1; itemsD0 <= maxItems; itemsD0++ ) {
        if ( matrixWidth % (threadsD0 * itemsD0) != 0 ) {
          continue;
        }
        for ( unsigned int itemsD1 = 1; itemsD0 * itemsD1 <= maxItems; itemsD1++ ) {
          if ( matrixWidth % (threadsD1 * itemsD1) != 0 ) {
            continue;
          }
          for ( unsigned int local = 0; local < 2; local++ ) {
            TuneBench::Stencil2DConf configuration;
            configuration.setLocalMemory(static_cast<bool>(local));
            configuration.setNrThreadsD0(threadsD0);
            configuration.setNrThreadsD1(threadsD1);
            configuration.setNrItemsD0(itemsD0);
            configuration.setNrItemsD1(itemsD1);
            configurations.push_back(configuration);
          }
        }
      }
    }
  }
  if ( samplingFactor < 100 ) {
    unsigned int newSize = static_cast<unsigned int>((configurations.size() * samplingFactor) / 100.0);
    std::shuffle(configurations.begin(), configurations.end(), randomEngine);
    configurations.resize(newSize);
  }

  std::cout << std::fixed << std::endl;
  std::cout << "# matrixWidth *configuration* GFLOP/s time stdDeviation COV" << std::endl << std::endl;

  for ( auto configuration = configurations.begin(); configuration != configurations.end(); ++configuration ) {
    // Generate kernel
    double gflops = isa::utils::giga(static_cast< uint64_t >(matrixWidth) * matrixWidth * 18.0);
    cl::Event clEvent;
    cl::Kernel * kernel;
    isa::utils::Timer timer;
    std::string * code = TuneBench::getStencil2DOpenCL(*configuration, inputDataName, matrixWidth, padding);

    if ( reInit ) {
      delete clQueues;
      clQueues = new std::vector< std::vector< cl::CommandQueue > >();
      isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
      try {
        initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), &input, &input_d, &output_d, output.size());
      } catch ( cl::Error & err ) {
        return -1;
      }
      reInit = false;
    }
    try {
      kernel = isa::OpenCL::compile("stencil2D", *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
    } catch ( isa::OpenCL::OpenCLError & err ) {
      std::cerr << err.what() << std::endl;
      delete code;
      continue;
    }
    delete code;

    cl::NDRange global(matrixWidth / (*configuration).getNrItemsD0(), matrixWidth / (*configuration).getNrItemsD1());
    cl::NDRange local((*configuration).getNrThreadsD0(), (*configuration).getNrThreadsD1());

    kernel->setArg(0, input_d);
    kernel->setArg(1, output_d);

    try {
      // Warm-up run
      clQueues->at(clDeviceID)[0].finish();
      clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
      clEvent.wait();
      // Tuning runs
      for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
        timer.start();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
        clEvent.wait();
        timer.stop();
      }
      clQueues->at(clDeviceID)[0].enqueueReadBuffer(output_d, CL_TRUE, 0, output.size() * sizeof(inputDataType), reinterpret_cast< void * >(output.data()), 0, &clEvent);
      clEvent.wait();
    } catch ( cl::Error & err ) {
      reInit = true;
      std::cerr << "OpenCL kernel execution error (";
      std::cerr << (*configuration).print();
      std::cerr << "): ";
      std::cerr << isa::utils::toString(err.err()) << std::endl;
      delete kernel;
      if ( err.err() == -4 || err.err() == -61 ) {
        return -1;
      }
      continue;
    }
    delete kernel;

    bool error = false;
    for ( unsigned int y = 0; y < matrixWidth; y++ ) {
      for ( unsigned int x = 0; x < matrixWidth; x++ ) {
        if ( !isa::utils::same(output[(y * isa::utils::pad(matrixWidth, padding)) + x], output_c[(y * isa::utils::pad(matrixWidth, padding)) + x]) ) {
          std::cerr << "Output error (" << (*configuration).print() << ")." << std::endl;
          error = true;
          break;
        }
      }
      if ( error ) {
        break;
      }
    }
    if ( error ) {
      continue;
    }

    std::cout << matrixWidth << " ";
    std::cout << (*configuration).print() << " ";
    std::cout << std::setprecision(3);
    std::cout << gflops / timer.getAverageTime() << " ";
    std::cout << std::setprecision(6);
    std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " " << timer.getCoefficientOfVariation() << std::endl;
  }
  std::cout << std::endl;

  return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * output_d, const unsigned int outputSize) {
  try {
    *input_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, input->size() * sizeof(inputDataType), 0, 0);
    *output_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, outputSize * sizeof(inputDataType), 0, 0);
    clQueue->enqueueWriteBuffer(*input_d, CL_FALSE, 0, input->size() * sizeof(inputDataType), reinterpret_cast< void * >(input->data()));
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error (memory initialization): " << isa::utils::toString(err.err()) << "." << std::endl;
    throw;
  }
}

<commit_msg>Wrong data type :)<commit_after>// Copyright 2016 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <vector>
#include <iostream>
#include <exception>
#include <iomanip>
#include <random>
#include <algorithm>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Stencil.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * output_d, const unsigned int outputSize);

int main(int argc, char * argv[]) {
  bool reInit = true;
  unsigned int nrIterations = 0;
  unsigned int samplingFactor = 100;
  unsigned int clPlatformID = 0;
  unsigned int clDeviceID = 0;
  unsigned int vectorSize = 0;
  unsigned int maxThreads = 0;
  unsigned int maxItems = 0;
  unsigned int matrixWidth = 0;
  unsigned int padding = 0;
  // Random number generation
  std::random_device randomDevice;
  std::default_random_engine randomEngine(randomDevice());
  std::uniform_int_distribution<inputDataType> uniformDistribution(0, magicValue);

  try {
    isa::utils::ArgumentList args(argc, argv);

    clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
    clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    if ( args.getSwitch("-sampling") ) {
      samplingFactor = args.getSwitchArgument< unsigned int >("-factor");
    }
    nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
    vectorSize = args.getSwitchArgument< unsigned int >("-vector");
    padding = args.getSwitchArgument< unsigned int >("-padding");
    maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
    maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    matrixWidth = args.getSwitchArgument< unsigned int >("-matrix_width");
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << argv[0] << " -opencl_platform ... -opencl_device ... [-sampling -factor ...] -iterations ... -vector ... -padding ... -max_threads ... -max_items ... -matrix_width ..." << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  cl::Context clContext;
  std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
  std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
  std::vector< std::vector< cl::CommandQueue > > * clQueues = 0;

  // Allocate host memory
  std::vector<inputDataType> input((matrixWidth + 2) * isa::utils::pad(matrixWidth + 2, padding)), output(matrixWidth * isa::utils::pad(matrixWidth, padding)), output_c;
  cl::Buffer input_d, output_d;

  for ( unsigned int y = 0; y < matrixWidth + 2; y++ ) {
    for ( unsigned int x = 0; x < matrixWidth + 2; x++ ) {
      if ( y == 0 || y == (matrixWidth - 1) ) {
        input[(y * isa::utils::pad(matrixWidth + 2, padding)) + x] = 0;
      } else if ( x == 0 || x == (matrixWidth - 1) ) {
        input[(y * isa::utils::pad(matrixWidth + 2, padding)) + x] = 0;
      } else {
        input[(y * isa::utils::pad(matrixWidth + 2, padding)) + x] = uniformDistribution(randomEngine);
      }
    }
  }
  output_c.resize(output.size());

  // Run the control
  TuneBench::stencil2D(input, output_c, matrixWidth, padding);

  // Generate tuning configurations
  std::vector<TuneBench::Stencil2DConf> configurations;
  for ( unsigned int threadsD0 = vectorSize; threadsD0 <= maxThreads; threadsD0 += vectorSize) {
    for ( unsigned int threadsD1 = 1; threadsD0 * threadsD1 <= maxThreads; threadsD1++ ) {
      for ( unsigned int itemsD0 = 1; itemsD0 <= maxItems; itemsD0++ ) {
        if ( matrixWidth % (threadsD0 * itemsD0) != 0 ) {
          continue;
        }
        for ( unsigned int itemsD1 = 1; itemsD0 * itemsD1 <= maxItems; itemsD1++ ) {
          if ( matrixWidth % (threadsD1 * itemsD1) != 0 ) {
            continue;
          }
          for ( unsigned int local = 0; local < 2; local++ ) {
            TuneBench::Stencil2DConf configuration;
            configuration.setLocalMemory(static_cast<bool>(local));
            configuration.setNrThreadsD0(threadsD0);
            configuration.setNrThreadsD1(threadsD1);
            configuration.setNrItemsD0(itemsD0);
            configuration.setNrItemsD1(itemsD1);
            configurations.push_back(configuration);
          }
        }
      }
    }
  }
  if ( samplingFactor < 100 ) {
    unsigned int newSize = static_cast<unsigned int>((configurations.size() * samplingFactor) / 100.0);
    std::shuffle(configurations.begin(), configurations.end(), randomEngine);
    configurations.resize(newSize);
  }

  std::cout << std::fixed << std::endl;
  std::cout << "# matrixWidth *configuration* GFLOP/s time stdDeviation COV" << std::endl << std::endl;

  for ( auto configuration = configurations.begin(); configuration != configurations.end(); ++configuration ) {
    // Generate kernel
    double gflops = isa::utils::giga(static_cast< uint64_t >(matrixWidth) * matrixWidth * 18.0);
    cl::Event clEvent;
    cl::Kernel * kernel;
    isa::utils::Timer timer;
    std::string * code = TuneBench::getStencil2DOpenCL(*configuration, inputDataName, matrixWidth, padding);

    if ( reInit ) {
      delete clQueues;
      clQueues = new std::vector< std::vector< cl::CommandQueue > >();
      isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
      try {
        initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), &input, &input_d, &output_d, output.size());
      } catch ( cl::Error & err ) {
        return -1;
      }
      reInit = false;
    }
    try {
      kernel = isa::OpenCL::compile("stencil2D", *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
    } catch ( isa::OpenCL::OpenCLError & err ) {
      std::cerr << err.what() << std::endl;
      delete code;
      continue;
    }
    delete code;

    cl::NDRange global(matrixWidth / (*configuration).getNrItemsD0(), matrixWidth / (*configuration).getNrItemsD1());
    cl::NDRange local((*configuration).getNrThreadsD0(), (*configuration).getNrThreadsD1());

    kernel->setArg(0, input_d);
    kernel->setArg(1, output_d);

    try {
      // Warm-up run
      clQueues->at(clDeviceID)[0].finish();
      clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
      clEvent.wait();
      // Tuning runs
      for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
        timer.start();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
        clEvent.wait();
        timer.stop();
      }
      clQueues->at(clDeviceID)[0].enqueueReadBuffer(output_d, CL_TRUE, 0, output.size() * sizeof(inputDataType), reinterpret_cast< void * >(output.data()), 0, &clEvent);
      clEvent.wait();
    } catch ( cl::Error & err ) {
      reInit = true;
      std::cerr << "OpenCL kernel execution error (";
      std::cerr << (*configuration).print();
      std::cerr << "): ";
      std::cerr << isa::utils::toString(err.err()) << std::endl;
      delete kernel;
      if ( err.err() == -4 || err.err() == -61 ) {
        return -1;
      }
      continue;
    }
    delete kernel;

    bool error = false;
    for ( unsigned int y = 0; y < matrixWidth; y++ ) {
      for ( unsigned int x = 0; x < matrixWidth; x++ ) {
        if ( !isa::utils::same(output[(y * isa::utils::pad(matrixWidth, padding)) + x], output_c[(y * isa::utils::pad(matrixWidth, padding)) + x]) ) {
          std::cerr << "Output error (" << (*configuration).print() << ")." << std::endl;
          error = true;
          break;
        }
      }
      if ( error ) {
        break;
      }
    }
    if ( error ) {
      continue;
    }

    std::cout << matrixWidth << " ";
    std::cout << (*configuration).print() << " ";
    std::cout << std::setprecision(3);
    std::cout << gflops / timer.getAverageTime() << " ";
    std::cout << std::setprecision(6);
    std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " " << timer.getCoefficientOfVariation() << std::endl;
  }
  std::cout << std::endl;

  return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * input, cl::Buffer * input_d, cl::Buffer * output_d, const unsigned int outputSize) {
  try {
    *input_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, input->size() * sizeof(inputDataType), 0, 0);
    *output_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, outputSize * sizeof(inputDataType), 0, 0);
    clQueue->enqueueWriteBuffer(*input_d, CL_FALSE, 0, input->size() * sizeof(inputDataType), reinterpret_cast< void * >(input->data()));
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error (memory initialization): " << isa::utils::toString(err.err()) << "." << std::endl;
    throw;
  }
}

<|endoftext|>


<commit_before>#include "Test.h"
#include "System/Log.h"
#include "System/Threading/ThreadPool.h"
#include "System/Events/Callable.h"

static void LogFiller()
{
    const char  filler[] = "01234567890123456789012345678901234567890123456789";

    while (true)
    {
        Log_Message("%s", filler);
    }
}

TEST_DEFINE(TestLogRotate)
{
    Log_SetOutputFile("test.log", false);
    Log_SetTarget(LOG_TARGET_STDOUT | LOG_TARGET_FILE);
    Log_SetMaxSize(100);

    LogFiller();    // never returns

    return TEST_SUCCESS;
}

TEST_DEFINE(TestLogRotateMultiThreaded)
{
    ThreadPool*     threadPool;
    unsigned        num = 100;

    Log_SetOutputFile("test.log", false);
    Log_SetAutoFlush(false);
    Log_SetTarget(LOG_TARGET_FILE);
    Log_SetMaxSize(1000);

    threadPool = ThreadPool::Create(num);
    for (unsigned i = 0; i < num; i++)
    {
        threadPool->Execute(CFunc(LogFiller));
    }

    threadPool->Start();
    threadPool->WaitStop();

    return TEST_SUCCESS;
}

TEST_DEFINE(TestLogTraceBuffer)
{
    int     i;

    Log_SetTrace(false);
    Log_SetTraceBufferSize(65536);

    for (i = 0; i < 11231; i++)
    {
        Log_Trace("%d", i);
    }

    Log_SetTrace(true);

    return TEST_SUCCESS;
}
<commit_msg>Updated Log traceBuffer test.<commit_after>#include "Test.h"
#include "System/Log.h"
#include "System/Time.h"
#include "System/Threading/ThreadPool.h"
#include "System/Events/Callable.h"

static void LogFiller()
{
    const char  filler[] = "01234567890123456789012345678901234567890123456789";

    while (true)
    {
        Log_Message("%s", filler);
    }
}

TEST_DEFINE(TestLogRotate)
{
    Log_SetOutputFile("test.log", false);
    Log_SetTarget(LOG_TARGET_STDOUT | LOG_TARGET_FILE);
    Log_SetMaxSize(100);

    LogFiller();    // never returns

    return TEST_SUCCESS;
}

TEST_DEFINE(TestLogRotateMultiThreaded)
{
    ThreadPool*     threadPool;
    unsigned        num = 100;

    Log_SetOutputFile("test.log", false);
    Log_SetAutoFlush(false);
    Log_SetTarget(LOG_TARGET_FILE);
    Log_SetMaxSize(1000);

    threadPool = ThreadPool::Create(num);
    for (unsigned i = 0; i < num; i++)
    {
        threadPool->Execute(CFunc(LogFiller));
    }

    threadPool->Start();
    threadPool->WaitStop();

    return TEST_SUCCESS;
}

TEST_DEFINE(TestLogTraceBuffer)
{
    int     i;

    // the running clock may interfere with log messages
    StopClock();
    Log_SetTrace(false);
    Log_SetTraceBufferSize(1024*1024);

    for (i = 0; i < 1234567; i++)
    {
        Log_Trace("%d", i);
    }

    Log_SetTrace(true);

    return TEST_SUCCESS;
}
<|endoftext|>


<commit_before>#include "core/FileSystem.h"
#include "debugger/RstParser.h"
#include "subprocess/subprocess.h"
#include <fstream>

#undef FAIL
#include "gtest/gtest.h"

namespace {
    void StringToFile(const std::string& s, fs::path path) {
        std::ofstream fout(path);
        fout << s;
    }

    fs::path CompileSource(const char* source, bool showOutput) {
        const auto tempDir = fs::temp_directory_path() / "vectrexy-unit-tests";
        const auto buildDir = tempDir / "build-template";

        fs::create_directories(buildDir);

        auto cwd = fs::current_path();

        fs::copy("./tests/debugger_tests/build-template", buildDir,
                 fs::copy_options::update_existing | fs::copy_options::recursive);

        StringToFile(source, buildDir / "src/main.cpp");

        const char* command[] = {
            "docker",
            "run",
            "-v",
            FormattedString("%s:/root/build-template", buildDir.string().c_str()),
            "amaiorano/gcc6809",
            "make",
            "DEBUG=1",
            "-C",
            "build-template",
            0};

        struct subprocess_s subprocess;
        int result =
            subprocess_create(command, subprocess_option_combined_stdout_stderr, &subprocess);
        if (result != 0)
            return {};

        FILE* p_stdout = subprocess_stdout(&subprocess);
        if (showOutput) {
            char outputText[1024];
            while (fgets(outputText, sizeof(outputText), p_stdout)) {
                std::cout << "stdout/stderr> " << outputText;
            }
        }

        int process_return;
        result = subprocess_join(&subprocess, &process_return);
        if (result != 0)
            return {};
        if (process_return != 0) {
            std::cerr << "Process returned unexpected value: " << process_return << std::endl;
            return {};
        }

        result = subprocess_destroy(&subprocess);
        if (result != 0)
            return {};

        auto rstFile = buildDir / "main.rst";
        if (!fs::exists(rstFile)) {
            std::cerr << "Compiled listing file not found: " << rstFile << std::endl;
            return {};
        }

        return rstFile;
    }

    std::shared_ptr<Variable> FindVariableByName(const std::shared_ptr<const Function>& function,
                                                 const char* name) {

        return Traverse(
            function->scope, [&](const std::shared_ptr<Scope>& node) -> std::shared_ptr<Variable> {
                auto iter = std::find_if(node->variables.begin(), node->variables.end(),
                                         [&](auto variable) { return variable->name == name; });
                if (iter != node->variables.end()) {
                    return *iter;
                }
                return {};
            });
    }

} // namespace

TEST(StabsParser, PrimitiveTypes) {

    const char* source = R"(
int main() {
    // Primitive types
    float f = 1.0f;
    double d = 2.0;
    long double ld = 3.0;
    char c = 127;
    signed char sc = 127;
    unsigned char uc = 255;
    int i = 127;
    unsigned int ui = 255;
    long unsigned int lui = 65535u;
    long long unsigned int llui = 0xFFFF;
    long long int lli = 0xFFFF;
    short int si = 127;
    short unsigned int sui = 255;

    // Alias types
    signed s = 127;
    unsigned long ul = 255;
    long long unsigned llu = 0xFFFF;
    unsigned short us = 255;

    return 0;
}
)";
    auto rstFile = CompileSource(source, false);
    ASSERT_TRUE(!rstFile.empty());

    auto symbols = std::make_unique<DebugSymbols>();
    auto parser = std::make_unique<RstParser>(*symbols);
    EXPECT_TRUE(parser->Parse(rstFile));

    auto* mainSymbol = symbols->GetSymbolByName("main()");
    EXPECT_TRUE(mainSymbol);
    auto mainFunction = symbols->GetFunctionByAddress(mainSymbol->address);
    EXPECT_TRUE(mainFunction);

    // Should have a scope since there are local variables
    EXPECT_TRUE(mainFunction->scope);

    struct TestParams {
        const char* name;
        const char* typeName;
        bool isSigned;
        size_t byteSize;
        PrimitiveType::Format format;
    };

    TestParams testParams[] = {
        {"f", "float", true, 4, PrimitiveType::Format::Float},
        {"d", "double", true, 4, PrimitiveType::Format::Float},
        {"ld", "long double", true, 4, PrimitiveType::Format::Float},
        {"c", "char", true, 1, PrimitiveType::Format::Char},
        {"sc", "signed char", true, 1, PrimitiveType::Format::Char},
        {"uc", "unsigned char", false, 1, PrimitiveType::Format::Char},
        {"i", "int", true, 1, PrimitiveType::Format::Int},
        {"ui", "unsigned int", false, 1, PrimitiveType::Format::Int},
        {"lui", "long unsigned int", false, 2, PrimitiveType::Format::Int},
        {"llui", "long long unsigned int", false, 4, PrimitiveType::Format::Int},
        {"lli", "long long int", true, 4, PrimitiveType::Format::Int},
        {"si", "short int", true, 1, PrimitiveType::Format::Int},
        {"sui", "short unsigned int", false, 1, PrimitiveType::Format::Int},
        // Alias types
        {"s", "int", true, 1, PrimitiveType::Format::Int},
        {"ul", "long unsigned int", false, 2, PrimitiveType::Format::Int},
        {"llu", "long long unsigned int", false, 4, PrimitiveType::Format::Int},
        {"us", "short unsigned int", false, 1, PrimitiveType::Format::Int},
        // TODO: add "void" and test with a void*
    };

    for (auto& p : testParams) {
        SCOPED_TRACE(p.name);

        auto var = FindVariableByName(mainFunction, p.name);
        ASSERT_TRUE(var);
        EXPECT_EQ(var->name, p.name);
        EXPECT_EQ(var->type->name, p.typeName);

        auto primType = std::dynamic_pointer_cast<PrimitiveType>(var->type);
        ASSERT_TRUE(primType);
        EXPECT_EQ(primType->isSigned, p.isSigned);
        EXPECT_EQ(primType->byteSize, p.byteSize);
        EXPECT_EQ(primType->format, p.format);
    }
}

TEST(StabsParser, IndirectTypes) {

    const char* source = R"(
int main() {
    int a;
    int* p1 = &a;
    int* p2 = p1;
    int& r1 = a;
    int& r2 = r1;
    int** pp = &p1;
    int*** ppp = &pp;
    int***& rppp = ppp;

    const int* cp1 = &a;

    // TODO: pointer to class/struct
    // TODO: pointer to function

    return 0;
}
)";
    auto rstFile = CompileSource(source, false);
    ASSERT_TRUE(!rstFile.empty());

    auto symbols = std::make_unique<DebugSymbols>();
    auto parser = std::make_unique<RstParser>(*symbols);
    EXPECT_TRUE(parser->Parse(rstFile));

    auto* mainSymbol = symbols->GetSymbolByName("main()");
    EXPECT_TRUE(mainSymbol);
    auto mainFunction = symbols->GetFunctionByAddress(mainSymbol->address);
    EXPECT_TRUE(mainFunction);

    // Should have a scope since there are local variables
    EXPECT_TRUE(mainFunction->scope);

    struct TestParams {
        const char* name;
        const char* typeName;
        const std::type_info& pointeeTypeInfo;
        const char* pointeeName;
    };

    TestParams testParams[] = {
        "p1",   "int*",    typeid(PrimitiveType), "int",
        "p2",   "int*",    typeid(PrimitiveType), "int",
        "r1",   "int*",    typeid(PrimitiveType), "int",
        "r2",   "int*",    typeid(PrimitiveType), "int",
        "pp",   "int**",   typeid(IndirectType),  "int*",
        "ppp",  "int***",  typeid(IndirectType),  "int**",
        "rppp", "int****", typeid(IndirectType),  "int***",
    };

    for (auto& p : testParams) {
        SCOPED_TRACE(p.name);
        auto var = FindVariableByName(mainFunction, p.name);
        ASSERT_TRUE(var);
        EXPECT_EQ(var->name, p.name);
        EXPECT_EQ(var->type->name, p.typeName);

        auto indirectType = std::dynamic_pointer_cast<IndirectType>(var->type);
        ASSERT_TRUE(indirectType);

        EXPECT_EQ(typeid(*indirectType->type), p.pointeeTypeInfo);
        EXPECT_EQ(indirectType->type->name, p.pointeeName);
    }
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>debugger_tests: add support for finding build template dir from any subdir of the project<commit_after>#include "core/FileSystem.h"
#include "debugger/RstParser.h"
#include "subprocess/subprocess.h"
#include <fstream>

#undef FAIL
#include "gtest/gtest.h"

namespace {
    void StringToFile(const std::string& s, fs::path path) {
        std::ofstream fout(path);
        fout << s;
    }

    fs::path CompileSource(const char* source, bool showOutput) {
        // Find template dir in current path and up to root. This works as long as we're running out
        // of a subdirectory of the project folder.
        auto findBuildTemplateDir = []() -> fs::path {
            auto templatePath = fs::path{"tests/debugger_tests/build-template"};
            while (true) {
                if (fs::exists(templatePath)) {
                    return (fs::current_path() / templatePath).make_preferred();
                }
                fs::current_path("..");
            }
            return {};
        };

        const auto sourceBuildTemplateDir = findBuildTemplateDir();
        const auto tempDir = fs::temp_directory_path() / "vectrexy-unit-tests";
        const auto buildDir = tempDir / "build-template";

        fs::create_directories(buildDir);

        fs::copy(sourceBuildTemplateDir, buildDir,
                 fs::copy_options::update_existing | fs::copy_options::recursive);

        StringToFile(source, buildDir / "src/main.cpp");

        const char* command[] = {
            "docker",
            "run",
            "-v",
            FormattedString("%s:/root/build-template", buildDir.string().c_str()),
            "amaiorano/gcc6809",
            "make",
            "DEBUG=1",
            "-C",
            "build-template",
            0};

        std::string s;
        for (auto& s2 : command) {
            s += !s2 ? "" : std::string{s2} + " ";
        }

        struct subprocess_s subprocess;
        int result =
            subprocess_create(command, subprocess_option_combined_stdout_stderr, &subprocess);
        if (result != 0)
            return {};

        FILE* p_stdout = subprocess_stdout(&subprocess);
        if (showOutput) {
            char outputText[1024];
            while (fgets(outputText, sizeof(outputText), p_stdout)) {
                std::cout << "stdout/stderr> " << outputText;
            }
        }

        int process_return;
        result = subprocess_join(&subprocess, &process_return);
        if (result != 0)
            return {};
        if (process_return != 0) {
            std::cerr << "Process returned unexpected value: " << process_return << std::endl;
            return {};
        }

        result = subprocess_destroy(&subprocess);
        if (result != 0)
            return {};

        auto rstFile = buildDir / "main.rst";
        if (!fs::exists(rstFile)) {
            std::cerr << "Compiled listing file not found: " << rstFile << std::endl;
            return {};
        }

        return rstFile;
    }

    std::shared_ptr<Variable> FindVariableByName(const std::shared_ptr<const Function>& function,
                                                 const char* name) {

        return Traverse(
            function->scope, [&](const std::shared_ptr<Scope>& node) -> std::shared_ptr<Variable> {
                auto iter = std::find_if(node->variables.begin(), node->variables.end(),
                                         [&](auto variable) { return variable->name == name; });
                if (iter != node->variables.end()) {
                    return *iter;
                }
                return {};
            });
    }

} // namespace

TEST(StabsParser, PrimitiveTypes) {

    const char* source = R"(
int main() {
    // Primitive types
    float f = 1.0f;
    double d = 2.0;
    long double ld = 3.0;
    char c = 127;
    signed char sc = 127;
    unsigned char uc = 255;
    int i = 127;
    unsigned int ui = 255;
    long unsigned int lui = 65535u;
    long long unsigned int llui = 0xFFFF;
    long long int lli = 0xFFFF;
    short int si = 127;
    short unsigned int sui = 255;

    // Alias types
    signed s = 127;
    unsigned long ul = 255;
    long long unsigned llu = 0xFFFF;
    unsigned short us = 255;

    return 0;
}
)";
    auto rstFile = CompileSource(source, false);
    ASSERT_TRUE(!rstFile.empty());

    auto symbols = std::make_unique<DebugSymbols>();
    auto parser = std::make_unique<RstParser>(*symbols);
    EXPECT_TRUE(parser->Parse(rstFile));

    auto* mainSymbol = symbols->GetSymbolByName("main()");
    EXPECT_TRUE(mainSymbol);
    auto mainFunction = symbols->GetFunctionByAddress(mainSymbol->address);
    EXPECT_TRUE(mainFunction);

    // Should have a scope since there are local variables
    EXPECT_TRUE(mainFunction->scope);

    struct TestParams {
        const char* name;
        const char* typeName;
        bool isSigned;
        size_t byteSize;
        PrimitiveType::Format format;
    };

    TestParams testParams[] = {
        {"f", "float", true, 4, PrimitiveType::Format::Float},
        {"d", "double", true, 4, PrimitiveType::Format::Float},
        {"ld", "long double", true, 4, PrimitiveType::Format::Float},
        {"c", "char", true, 1, PrimitiveType::Format::Char},
        {"sc", "signed char", true, 1, PrimitiveType::Format::Char},
        {"uc", "unsigned char", false, 1, PrimitiveType::Format::Char},
        {"i", "int", true, 1, PrimitiveType::Format::Int},
        {"ui", "unsigned int", false, 1, PrimitiveType::Format::Int},
        {"lui", "long unsigned int", false, 2, PrimitiveType::Format::Int},
        {"llui", "long long unsigned int", false, 4, PrimitiveType::Format::Int},
        {"lli", "long long int", true, 4, PrimitiveType::Format::Int},
        {"si", "short int", true, 1, PrimitiveType::Format::Int},
        {"sui", "short unsigned int", false, 1, PrimitiveType::Format::Int},
        // Alias types
        {"s", "int", true, 1, PrimitiveType::Format::Int},
        {"ul", "long unsigned int", false, 2, PrimitiveType::Format::Int},
        {"llu", "long long unsigned int", false, 4, PrimitiveType::Format::Int},
        {"us", "short unsigned int", false, 1, PrimitiveType::Format::Int},
        // TODO: add "void" and test with a void*
    };

    for (auto& p : testParams) {
        SCOPED_TRACE(p.name);

        auto var = FindVariableByName(mainFunction, p.name);
        ASSERT_TRUE(var);
        EXPECT_EQ(var->name, p.name);
        EXPECT_EQ(var->type->name, p.typeName);

        auto primType = std::dynamic_pointer_cast<PrimitiveType>(var->type);
        ASSERT_TRUE(primType);
        EXPECT_EQ(primType->isSigned, p.isSigned);
        EXPECT_EQ(primType->byteSize, p.byteSize);
        EXPECT_EQ(primType->format, p.format);
    }
}

TEST(StabsParser, IndirectTypes) {

    const char* source = R"(
int main() {
    int a;
    int* p1 = &a;
    int* p2 = p1;
    int& r1 = a;
    int& r2 = r1;
    int** pp = &p1;
    int*** ppp = &pp;
    int***& rppp = ppp;

    const int* cp1 = &a;

    // TODO: pointer to class/struct
    // TODO: pointer to function

    return 0;
}
)";
    auto rstFile = CompileSource(source, false);
    ASSERT_TRUE(!rstFile.empty());

    auto symbols = std::make_unique<DebugSymbols>();
    auto parser = std::make_unique<RstParser>(*symbols);
    EXPECT_TRUE(parser->Parse(rstFile));

    auto* mainSymbol = symbols->GetSymbolByName("main()");
    EXPECT_TRUE(mainSymbol);
    auto mainFunction = symbols->GetFunctionByAddress(mainSymbol->address);
    EXPECT_TRUE(mainFunction);

    // Should have a scope since there are local variables
    EXPECT_TRUE(mainFunction->scope);

    struct TestParams {
        const char* name;
        const char* typeName;
        const std::type_info& pointeeTypeInfo;
        const char* pointeeName;
    };

    TestParams testParams[] = {
        "p1",   "int*",    typeid(PrimitiveType), "int",
        "p2",   "int*",    typeid(PrimitiveType), "int",
        "r1",   "int*",    typeid(PrimitiveType), "int",
        "r2",   "int*",    typeid(PrimitiveType), "int",
        "pp",   "int**",   typeid(IndirectType),  "int*",
        "ppp",  "int***",  typeid(IndirectType),  "int**",
        "rppp", "int****", typeid(IndirectType),  "int***",
    };

    for (auto& p : testParams) {
        SCOPED_TRACE(p.name);
        auto var = FindVariableByName(mainFunction, p.name);
        ASSERT_TRUE(var);
        EXPECT_EQ(var->name, p.name);
        EXPECT_EQ(var->type->name, p.typeName);

        auto indirectType = std::dynamic_pointer_cast<IndirectType>(var->type);
        ASSERT_TRUE(indirectType);

        EXPECT_EQ(typeid(*indirectType->type), p.pointeeTypeInfo);
        EXPECT_EQ(indirectType->type->name, p.pointeeName);
    }
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// Copyright 2016-2020 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

#include "file.h"

#include <stddef.h>

#include <memory>
#include <set>

#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include "proto2-descriptor-extensions.pb.h"
#include "enum.h"
#include "field.h"
#include "message.h"
#include "names.h"
#include "service.h"

namespace google {
namespace protobuf {
namespace cl_protobufs {

// ===================================================================

FileGenerator::FileGenerator(const FileDescriptor* file) :
    file_(file),
    lisp_package_name_(FileLispPackage(file)),
    schema_name_(file->name()),
    enums_(file->enum_type_count()),
    messages_(file->message_type_count()),
    services_(file->service_count()) {
  for (int i = 0; i < file->enum_type_count(); ++i) {
    enums_[i] = std::make_unique<EnumGenerator>(file->enum_type(i));
  }

  for (int i = 0; i < file->message_type_count(); ++i) {
    messages_[i] = std::make_unique<MessageGenerator>(file->message_type(i));
  }

  for (int i = 0; i < file->service_count(); ++i) {
    services_[i] = std::make_unique<ServiceGenerator>(file->service(i));
  }

  switch (file_->syntax()) {
    case FileDescriptor::Syntax::SYNTAX_PROTO2:
      syntax_ = ":proto2";
      break;
    case FileDescriptor::Syntax::SYNTAX_PROTO3:
      syntax_ = ":proto3";
      break;
    case FileDescriptor::Syntax::SYNTAX_UNKNOWN:
      GOOGLE_LOG(FATAL) << "Unknown syntax for file: " << file->DebugString();
      break;
  }

  // Derive schema name.
  const size_t slash = schema_name_.find_last_of("\\/");
  if (std::string::npos != slash) {
    schema_name_.erase(0, slash + 1);
  }
  const size_t period = schema_name_.rfind('.');
  if (std::string::npos != period) {
    schema_name_.erase(period);
  }
  StrToLower(&schema_name_);
}

FileGenerator::~FileGenerator() {}

void FileGenerator::GenerateSource(io::Printer* printer) {
  printer->Print(
      ";;; $file_name$.lisp\n"
      ";;;\n"
      ";;; Generated by the protocol buffer compiler. DO NOT EDIT!\n",
      "file_name", file_->name());

  // Just in case multiple schema are written to the same file.
  printer->Print("\n(cl:in-package #:common-lisp-user)\n");

  std::set<std::string> packages;
  if (!lisp_package_name_.empty()) {
    packages.insert(lisp_package_name_);
    if (file_->service_count() > 0) {
      packages.insert(lisp_package_name_ + "-RPC");
    }
  }

  for (int i = 0; i < file_->message_type_count(); ++i) {
    messages_[i]->AddPackages(&packages);
  }

  printer->Print("\n#+sbcl (cl:declaim (cl:optimize (cl:debug 0)"
                 " (sb-c:store-coverage-data 0)))\n");
  for (const std::string& package : packages) {
    printer->Print(
        "\n(cl:eval-when (:compile-toplevel :load-toplevel :execute)\n"
        "  (cl:unless (cl:find-package \"$package_name$\")\n"
        "    (cl:defpackage \"$package_name$\" (:use))))\n",
        "package_name", package);
  }

  if (!lisp_package_name_.empty()) {
    printer->Print("\n(cl:in-package \"$package_name$\")\n",
                   "package_name", lisp_package_name_);
  }

  printer->Print(
      "\n(cl:eval-when (:compile-toplevel :load-toplevel :execute)"
      "\n(proto:define-schema '$schema_name$\n",
      "schema_name", schema_name_);
  printer->Indent();
  // Schema options.
  printer->Indent();
  const char* sep = "";
  printer->Print(":syntax $syntax$\n", "syntax", syntax_);
  if (!file_->package().empty()) {
    printer->Print(sep); sep = "\n ";
    printer->Print(":package \"$pck$\"", "pck", file_->package());
  }
  if (file_->dependency_count() > 0) {
    printer->Print(sep);
    printer->Print(":import '("); sep = "";
    for (int i = 0; i < file_->dependency_count(); ++i) {
      printer->Print(sep); sep = "\n          ";
      printer->Print("\"$import$\"", "import", file_->dependency(i)->name());
    }
    printer->Print(")"); sep = "\n ";
  }
  // END schema options
  printer->Print(")\n");
  printer->Outdent();
  printer->Outdent();
  printer->Print(")\n");

  std::vector<std::string> exports;
  exports.push_back(schema_name_);

  if (file_->enum_type_count() > 0) {
    printer->Print("\n\n;;; Top-Level enums");
    for (int i = 0; i < file_->enum_type_count(); ++i) {
      enums_[i]->Generate(printer);
      enums_[i]->AddExports(&exports);
    }
  }

  if (file_->message_type_count() > 0) {
    printer->Print("\n\n;;; Top-Level messages");
    for (int i = 0; i < file_->message_type_count(); ++i) {
      messages_[i]->Generate(printer);
      messages_[i]->AddExports(&exports);
    }
  }

  if (file_->extension_count() > 0) {
    printer->Print("\n\n;;; Top-Level extensions");
    for (int i = 0; i < file_->extension_count(); ++i) {
      GenerateExtension(printer, file_->extension(i), file_);
    }
  }

  std::vector<std::string> rpc_exports;
  if (file_->service_count() > 0) {
    printer->Print("\n\n;;; Services");
    for (int i = 0; i < file_->service_count(); ++i) {
      services_[i]->Generate(printer);
      services_[i]->AddExports(&exports);
      services_[i]->AddRpcExports(&rpc_exports);
    }
  }
  // END of schema defintion.

  // Register the schema by pathname.
  printer->Print(
      "\n\n"
      "(cl:eval-when (:compile-toplevel :load-toplevel :execute)\n"
      "(cl:setf (cl:gethash #P\"$file_name$\" proto-impl::*all-schemas*)\n"
      "         (proto:find-schema '$schema_name$)))\n",
      "file_name", file_->name(),
      "schema_name", schema_name_);

  if (!lisp_package_name_.empty()) {
    // Export symbols.
    if (!exports.empty()) {
      std::sort(exports.begin(), exports.end());
      auto last = std::unique(exports.begin(), exports.end());
      exports.erase(last, exports.end());
      sep = "(";
      printer->Print("\n(cl:export '");
      for (const std::string& e : exports) {
        printer->Print(sep); sep = "\n             ";
        printer->PrintRaw(e);
      }
      printer->Print("))\n");
    }

    if (!rpc_exports.empty()) {
      printer->Print(
          "\n(cl:in-package \"$package_name$\")\n",
          "package_name", lisp_package_name_ + "-RPC");
      sep = "(";
      printer->Print("\n(cl:export '");
      for (const std::string& e : rpc_exports) {
        printer->Print(sep); sep = "\n             ";
        printer->PrintRaw(e);
      }
      printer->Print("))\n");
    }
  }
}

}  // namespace cl_protobufs
}  // namespace protobuf
}  // namespace google
<commit_msg>Internal change<commit_after>// Copyright 2016-2020 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

#include "file.h"

#include <stddef.h>

#include <memory>
#include <set>

#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include "proto2-descriptor-extensions.pb.h"
#include "enum.h"
#include "field.h"
#include "message.h"
#include "names.h"
#include "service.h"

namespace google {
namespace protobuf {
namespace cl_protobufs {

// ===================================================================

FileGenerator::FileGenerator(const FileDescriptor* file) :
    file_(file),
    lisp_package_name_(FileLispPackage(file)),
    schema_name_(file->name()),
    enums_(file->enum_type_count()),
    messages_(file->message_type_count()),
    services_(file->service_count()) {
  for (int i = 0; i < file->enum_type_count(); ++i) {
    enums_[i] = std::make_unique<EnumGenerator>(file->enum_type(i));
  }

  for (int i = 0; i < file->message_type_count(); ++i) {
    messages_[i] = std::make_unique<MessageGenerator>(file->message_type(i));
  }

  for (int i = 0; i < file->service_count(); ++i) {
    services_[i] = std::make_unique<ServiceGenerator>(file->service(i));
  }

  switch (file_->syntax()) {
    case FileDescriptor::Syntax::SYNTAX_PROTO2:
      syntax_ = ":proto2";
      break;
    case FileDescriptor::Syntax::SYNTAX_PROTO3:
      syntax_ = ":proto3";
      break;
    case FileDescriptor::Syntax::SYNTAX_UNKNOWN:
      GOOGLE_LOG(FATAL) << "Unknown syntax for file: " << file->DebugString();
      break;
  }

  // Derive schema name.
  const size_t slash = schema_name_.find_last_of("\\/");
  if (std::string::npos != slash) {
    schema_name_.erase(0, slash + 1);
  }
  const size_t period = schema_name_.rfind('.');
  if (std::string::npos != period) {
    schema_name_.erase(period);
  }
  StrToLower(&schema_name_);
}

FileGenerator::~FileGenerator() {}

void FileGenerator::GenerateSource(io::Printer* printer) {
  printer->Print(
      ";;; $file_name$.lisp\n"
      ";;;\n"
      ";;; Generated by the protocol buffer compiler. DO NOT EDIT!\n",
      "file_name", file_->name());

  // Just in case multiple schema are written to the same file.
  printer->Print("\n(cl:in-package #:common-lisp-user)\n");

  std::set<std::string> packages;
  if (!lisp_package_name_.empty()) {
    packages.insert(lisp_package_name_);
    if (file_->service_count() > 0) {
      packages.insert(lisp_package_name_ + "-RPC");
    }
  }

  for (int i = 0; i < file_->message_type_count(); ++i) {
    messages_[i]->AddPackages(&packages);
  }

  printer->Print("\n#+sbcl\n"
                 "(cl:progn\n (cl:eval-when (:compile-toplevel)"
                 " (sb-ext:restrict-compiler-policy 'cl:debug 0 1))\n"
                 " (cl:declaim (cl:optimize (sb-c:store-coverage-data 0))))\n");

  for (const std::string& package : packages) {
    printer->Print(
        "\n(cl:eval-when (:compile-toplevel :load-toplevel :execute)\n"
        "  (cl:unless (cl:find-package \"$package_name$\")\n"
        "    (cl:defpackage \"$package_name$\" (:use))))\n",
        "package_name", package);
  }

  if (!lisp_package_name_.empty()) {
    printer->Print("\n(cl:in-package \"$package_name$\")\n",
                   "package_name", lisp_package_name_);
  }

  printer->Print(
      "\n(cl:eval-when (:compile-toplevel :load-toplevel :execute)"
      "\n(proto:define-schema '$schema_name$\n",
      "schema_name", schema_name_);
  printer->Indent();
  // Schema options.
  printer->Indent();
  const char* sep = "";
  printer->Print(":syntax $syntax$\n", "syntax", syntax_);
  if (!file_->package().empty()) {
    printer->Print(sep); sep = "\n ";
    printer->Print(":package \"$pck$\"", "pck", file_->package());
  }
  if (file_->dependency_count() > 0) {
    printer->Print(sep);
    printer->Print(":import '("); sep = "";
    for (int i = 0; i < file_->dependency_count(); ++i) {
      printer->Print(sep); sep = "\n          ";
      printer->Print("\"$import$\"", "import", file_->dependency(i)->name());
    }
    printer->Print(")"); sep = "\n ";
  }
  // END schema options
  printer->Print(")\n");
  printer->Outdent();
  printer->Outdent();
  printer->Print(")\n");

  std::vector<std::string> exports;
  exports.push_back(schema_name_);

  if (file_->enum_type_count() > 0) {
    printer->Print("\n\n;;; Top-Level enums");
    for (int i = 0; i < file_->enum_type_count(); ++i) {
      enums_[i]->Generate(printer);
      enums_[i]->AddExports(&exports);
    }
  }

  if (file_->message_type_count() > 0) {
    printer->Print("\n\n;;; Top-Level messages");
    for (int i = 0; i < file_->message_type_count(); ++i) {
      messages_[i]->Generate(printer);
      messages_[i]->AddExports(&exports);
    }
  }

  if (file_->extension_count() > 0) {
    printer->Print("\n\n;;; Top-Level extensions");
    for (int i = 0; i < file_->extension_count(); ++i) {
      GenerateExtension(printer, file_->extension(i), file_);
    }
  }

  std::vector<std::string> rpc_exports;
  if (file_->service_count() > 0) {
    printer->Print("\n\n;;; Services");
    for (int i = 0; i < file_->service_count(); ++i) {
      services_[i]->Generate(printer);
      services_[i]->AddExports(&exports);
      services_[i]->AddRpcExports(&rpc_exports);
    }
  }
  // END of schema defintion.

  // Register the schema by pathname.
  printer->Print(
      "\n\n"
      "(cl:eval-when (:compile-toplevel :load-toplevel :execute)\n"
      "(cl:setf (cl:gethash #P\"$file_name$\" proto-impl::*all-schemas*)\n"
      "         (proto:find-schema '$schema_name$)))\n",
      "file_name", file_->name(),
      "schema_name", schema_name_);

  if (!lisp_package_name_.empty()) {
    // Export symbols.
    if (!exports.empty()) {
      std::sort(exports.begin(), exports.end());
      auto last = std::unique(exports.begin(), exports.end());
      exports.erase(last, exports.end());
      sep = "(";
      printer->Print("\n(cl:export '");
      for (const std::string& e : exports) {
        printer->Print(sep); sep = "\n             ";
        printer->PrintRaw(e);
      }
      printer->Print("))\n");
    }

    if (!rpc_exports.empty()) {
      printer->Print(
          "\n(cl:in-package \"$package_name$\")\n",
          "package_name", lisp_package_name_ + "-RPC");
      sep = "(";
      printer->Print("\n(cl:export '");
      for (const std::string& e : rpc_exports) {
        printer->Print(sep); sep = "\n             ";
        printer->PrintRaw(e);
      }
      printer->Print("))\n");
    }
  }
}

}  // namespace cl_protobufs
}  // namespace protobuf
}  // namespace google
<|endoftext|>


<commit_before>#include "qnitexyartist.h"
#include "qniteaxes.h"
#include "qniteaxis.h"
#include "qnitemapper.h"
#include "qniteclipper.h"

QniteXYArtist::QniteXYArtist(QQuickItem* parent):
  QniteArtist(parent),
  m_clipper{nullptr},
  m_xMapper{nullptr},
  m_yMapper{nullptr}
{
}

QniteXYArtist::~QniteXYArtist()
{
}

QColor QniteXYArtist::color() const
{
  return m_color;
}

void QniteXYArtist::setColor(const QColor& color)
{
  if (color != m_color) {
    m_color = color;
    emit colorChanged();
  }
}

const QList<qreal>& QniteXYArtist::xValues()
{
  return m_xValues;
}

void QniteXYArtist::setXValues(const QList<qreal>& values)
{
  if (m_xValues != values) {
    m_xValues = values;
    // TODO: transform the values here and cache
    emit xValuesChanged();
  }
}

const QList<qreal>& QniteXYArtist::yValues()
{
  return m_yValues;
}

void QniteXYArtist::setYValues(const QList<qreal>& values)
{
  if (m_yValues != values) {
    m_yValues = values;
    // TODO: transform the values here and cache
    emit yValuesChanged();
  }
}

QniteMapper* QniteXYArtist::xMapper() const
{
  return m_xMapper;
}

void QniteXYArtist::setXMapper(QniteMapper* mapper)
{
  // TODO: when the mapper is set we should
  // connect to its factorChanged event and trigger an update
  // and disconnect the previous one
  if (mapper != m_xMapper) {
    m_xMapper = mapper;
    // TODO: emit a signal??
  }
}

QniteMapper* QniteXYArtist::yMapper() const
{
  return m_yMapper;
}

void QniteXYArtist::setYMapper(QniteMapper* mapper)
{
  // TODO: when the mapper is set we should
  // connect to its factorChanged event and trigger an update
  // and disconnect the previous one
  if (mapper != m_yMapper) {
    m_yMapper = mapper;
    // TODO: emit a signal??
  }
}

QniteClipper* QniteXYArtist::clipper() const
{
  return m_clipper;
}

void QniteXYArtist::setClipper(QniteClipper* clipper)
{
  if (m_clipper != clipper) {
    m_clipper = clipper;
    // TODO: signal????
  }
}

const QList<qreal>& QniteXYArtist::xMapped() const
{
  return m_xMapped;
}

const QList<qreal>& QniteXYArtist::yMapped() const
{
  return m_yMapped;
}

void QniteXYArtist::processData()
{
  qDebug() << "processing data";
  if (xValues().size() != yValues().size())
    qWarning() << "xValues and yValues size for the artists are different";

  // get bounds
  qreal xLower = axes()->bottomAxis()->lowerBound();
  qreal xUpper = axes()->bottomAxis()->upperBound();
  qreal yLower = axes()->leftAxis()->lowerBound();
  qreal yUpper = axes()->leftAxis()->upperBound();

  // TODO: this should be improved. clipping should be done only when bounds changes
  // and tranforsm should always be performed
  QList<qreal> xClipped;
  QList<qreal> yClipped;
  // clip non visible data
  if (clipper() != nullptr) {
    clipper()->clip(xValues(), yValues(), xLower, xUpper, yLower, yUpper, xClipped, yClipped);
  } else {
    xClipped = xValues();
    yClipped = yValues();
  }

  // map to display
  m_xMapped = xMapper()->mapTo(xLower, xUpper, 0, width(), xClipped);
  m_yMapped = yMapper()->mapTo(yLower, yUpper, 0, height(), yClipped, true);
}

void QniteXYArtist::updateAxes()
{
  QniteAxes* axes = this->axes();
  if (axes != nullptr) {
    disconnect(axes, SIGNAL(bottomAxisChanged()), this, 0);
    disconnect(axes, SIGNAL(leftAxisChanged()), this, 0);

    connect(axes, &QniteAxes::bottomAxisChanged, this, [=](){ this->setXMapper(axes->bottomAxis()->mapper()); });
    connect(axes, &QniteAxes::leftAxisChanged, this, [=](){ this->setYMapper(axes->leftAxis()->mapper()); });
  }
}
<commit_msg>mapper is updated in xyartists when the axes changes<commit_after>#include "qnitexyartist.h"
#include "qniteaxes.h"
#include "qniteaxis.h"
#include "qnitemapper.h"
#include "qniteclipper.h"

QniteXYArtist::QniteXYArtist(QQuickItem* parent):
  QniteArtist(parent),
  m_clipper{nullptr},
  m_xMapper{nullptr},
  m_yMapper{nullptr}
{
}

QniteXYArtist::~QniteXYArtist()
{
}

QColor QniteXYArtist::color() const
{
  return m_color;
}

void QniteXYArtist::setColor(const QColor& color)
{
  if (color != m_color) {
    m_color = color;
    emit colorChanged();
  }
}

const QList<qreal>& QniteXYArtist::xValues()
{
  return m_xValues;
}

void QniteXYArtist::setXValues(const QList<qreal>& values)
{
  if (m_xValues != values) {
    m_xValues = values;
    // TODO: transform the values here and cache
    emit xValuesChanged();
  }
}

const QList<qreal>& QniteXYArtist::yValues()
{
  return m_yValues;
}

void QniteXYArtist::setYValues(const QList<qreal>& values)
{
  if (m_yValues != values) {
    m_yValues = values;
    // TODO: transform the values here and cache
    emit yValuesChanged();
  }
}

QniteMapper* QniteXYArtist::xMapper() const
{
  return m_xMapper;
}

void QniteXYArtist::setXMapper(QniteMapper* mapper)
{
  // TODO: when the mapper is set we should
  // connect to its factorChanged event and trigger an update
  // and disconnect the previous one
  if (mapper != m_xMapper) {
    m_xMapper = mapper;
    // TODO: emit a signal??
  }
}

QniteMapper* QniteXYArtist::yMapper() const
{
  return m_yMapper;
}

void QniteXYArtist::setYMapper(QniteMapper* mapper)
{
  // TODO: when the mapper is set we should
  // connect to its factorChanged event and trigger an update
  // and disconnect the previous one
  if (mapper != m_yMapper) {
    m_yMapper = mapper;
    // TODO: emit a signal??
  }
}

QniteClipper* QniteXYArtist::clipper() const
{
  return m_clipper;
}

void QniteXYArtist::setClipper(QniteClipper* clipper)
{
  if (m_clipper != clipper) {
    m_clipper = clipper;
    // TODO: signal????
  }
}

const QList<qreal>& QniteXYArtist::xMapped() const
{
  return m_xMapped;
}

const QList<qreal>& QniteXYArtist::yMapped() const
{
  return m_yMapped;
}

void QniteXYArtist::processData()
{
  qDebug() << "processing data";
  if (xValues().size() != yValues().size())
    qWarning() << "xValues and yValues size for the artists are different";

  if (qMin(xValues().size(), yValues().size()) < 1) {
    qWarning() << "at least one of x/y series is empty";
    return;
  }

  // get bounds
  qreal xLower = axes()->bottomAxis()->lowerBound();
  qreal xUpper = axes()->bottomAxis()->upperBound();
  qreal yLower = axes()->leftAxis()->lowerBound();
  qreal yUpper = axes()->leftAxis()->upperBound();

  // TODO: this should be improved. clipping should be done only when bounds changes
  // and tranforsm should always be performed
  QList<qreal> xClipped;
  QList<qreal> yClipped;
  // clip non visible data
  if (clipper() != nullptr) {
    clipper()->clip(xValues(), yValues(), xLower, xUpper, yLower, yUpper, xClipped, yClipped);
  } else {
    xClipped = xValues();
    yClipped = yValues();
  }

  // map to display
  m_xMapped = xMapper()->mapTo(xLower, xUpper, 0, width(), xClipped);
  m_yMapped = yMapper()->mapTo(yLower, yUpper, 0, height(), yClipped, true);
}

void QniteXYArtist::updateAxes()
{
  QniteArtist::updateAxes();

  QniteAxes* axes = this->axes();
  if (axes != nullptr) {
    // TODO: find a better way to handle axis bindings
    if (axes->bottomAxis() != nullptr)
      this->setXMapper(axes->bottomAxis()->mapper());

    if (axes->leftAxis() != nullptr)
      this->setYMapper(axes->leftAxis()->mapper());

    disconnect(axes, SIGNAL(bottomAxisChanged()), this, 0);
    disconnect(axes, SIGNAL(leftAxisChanged()), this, 0);

    connect(axes, &QniteAxes::bottomAxisChanged, this, [=](){ this->setXMapper(axes->bottomAxis()->mapper()); });
    connect(axes, &QniteAxes::leftAxisChanged, this, [=](){ this->setYMapper(axes->leftAxis()->mapper()); });
  }
}
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/****************************************************************************

  Error.cc

  This file contains code to manipulate Error

 ****************************************************************************/
#include "Main.h"
#include "Error.h"
#include <time.h>
#include "ink_platform.h"

ErrorClass::~ErrorClass()
{
}

void
ErrorClass::operator() (const char *aformat_string, ...)
{
  va_list aap;
  va_start(aap, aformat_string);
  format_string = aformat_string;
  raise(aap);
  va_end(aap);
  delete this;
}

void
ErrorClass::raise(va_list ap, const char *prefix)
{
  NOWARN_UNUSED(prefix);
  SrcLoc loc;
  loc.set(filename, function_name, line_number);
  diags->print_va(NULL, DL_Fatal, &loc, format_string, ap);
}

// Request Fatal
// Abort the current request, cleanup all related resources.
//
void
RequestFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "REQUEST FATAL");
  ink_assert(!"RequestFatal");
}

// Thread Fatal
// Abort the current thread, restart within processor
//
void
ThreadFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "THREAD FATAL");
  ink_assert(!"ThreadFatal");
  ink_thread_exit(0);
}

// Processor Fatal
// Kill and restart the processor
//
void
ProcessorFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "PROCESSOR FATAL");
  ink_assert(!"ProcessorFatal");
}

// Process Fatal
// Kill and restart the process
//
void
ProcessFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "PROCESS FATAL");
  //exit(1);
  ink_assert(!"ProcessFatal");
}

// Machine Fatal
// Kill and restart the set of processors on this machine
//
void
MachineFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "MACHINE FATAL");
  exit(2);
}
<commit_msg>TS-1887: fix SrcLoc build error<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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.
 */

/****************************************************************************

  Error.cc

  This file contains code to manipulate Error

 ****************************************************************************/
#include "Main.h"
#include "Error.h"
#include <time.h>
#include "ink_platform.h"

ErrorClass::~ErrorClass()
{
}

void
ErrorClass::operator() (const char *aformat_string, ...)
{
  va_list aap;
  va_start(aap, aformat_string);
  format_string = aformat_string;
  raise(aap);
  va_end(aap);
  delete this;
}

void
ErrorClass::raise(va_list ap, const char *prefix)
{
  NOWARN_UNUSED(prefix);
  SrcLoc loc(filename, function_name, line_number);
  diags->print_va(NULL, DL_Fatal, &loc, format_string, ap);
}

// Request Fatal
// Abort the current request, cleanup all related resources.
//
void
RequestFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "REQUEST FATAL");
  ink_assert(!"RequestFatal");
}

// Thread Fatal
// Abort the current thread, restart within processor
//
void
ThreadFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "THREAD FATAL");
  ink_assert(!"ThreadFatal");
  ink_thread_exit(0);
}

// Processor Fatal
// Kill and restart the processor
//
void
ProcessorFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "PROCESSOR FATAL");
  ink_assert(!"ProcessorFatal");
}

// Process Fatal
// Kill and restart the process
//
void
ProcessFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "PROCESS FATAL");
  //exit(1);
  ink_assert(!"ProcessFatal");
}

// Machine Fatal
// Kill and restart the set of processors on this machine
//
void
MachineFatalClass::raise(va_list ap, const char *prefix)
{
  ErrorClass::raise(ap, prefix ? prefix : "MACHINE FATAL");
  exit(2);
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

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

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

*/

#include "mediaobject.h"
#include <QTimer>
#include <kdebug.h>

namespace Phonon
{
namespace Fake
{
MediaObject::MediaObject( QObject* parent )
	: AbstractMediaProducer( parent )
	, m_aboutToFinishNotEmitted( true )
{
	//kDebug( 604 ) << k_funcinfo << endl;
}

MediaObject::~MediaObject()
{
	//kDebug( 604 ) << k_funcinfo << endl;
}

KUrl MediaObject::url() const
{
	//kDebug( 604 ) << k_funcinfo << endl;
	return m_url;
}

qint64 MediaObject::totalTime() const
{
	//kDebug( 604 ) << k_funcinfo << endl;
	return 1000*60*3; // 3 minutes
}

qint32 MediaObject::aboutToFinishTime() const
{
	//kDebug( 604 ) << k_funcinfo << endl;
	return m_aboutToFinishTime;
}

void MediaObject::setUrl( const KUrl& url )
{
	//kDebug( 604 ) << k_funcinfo << endl;
    m_aboutToFinishNotEmitted = true;
	m_url = url;
    setState(Phonon::LoadingState);
    if (!m_url.isValid() || m_url.isEmpty()) {
        return;
    }
	emit length( totalTime() );
	QMultiMap<QString, QString> metaData;
	metaData.insert( "TITLE", "Fake video" );
	metaData.insert( "ARTIST", "Matthias Kretz" );
	emit metaDataChanged( metaData );
    QTimer::singleShot(50, this, SLOT(loadingComplete()));
}

void MediaObject::openMedia(Phonon::MediaObject::Media media)
{
    switch (media) {
    case Phonon::MediaObject::None:
        setUrl(KUrl());
        break;
    case Phonon::MediaObject::CD:
    case Phonon::MediaObject::DVD:
    case Phonon::MediaObject::VCD:
        break;
    default:
        kError(604) << "media " << media << " not implemented" << endl;
    }
}

void MediaObject::loadingComplete()
{
    if (state() == Phonon::LoadingState) {
        setState(Phonon::StoppedState);
    } else if (state() == Phonon::BufferingState) {
        setState(Phonon::PlayingState);
    }
}

void MediaObject::setAboutToFinishTime( qint32 newAboutToFinishTime )
{
	//kDebug( 604 ) << k_funcinfo << endl;
	m_aboutToFinishTime = newAboutToFinishTime;
	if( currentTime() < totalTime() - m_aboutToFinishTime ) // not about to finish
		m_aboutToFinishNotEmitted = true;
}

void MediaObject::play()
{
	//kDebug( 604 ) << k_funcinfo << endl;
	AbstractMediaProducer::play();
}

void MediaObject::pause()
{
	//kDebug( 604 ) << k_funcinfo << endl;
    if (state() == Phonon::PlayingState || state() == Phonon::BufferingState) {
        AbstractMediaProducer::pause();
    }
}

void MediaObject::stop()
{
    //kDebug(604) << k_funcinfo << endl;
    if (state() == Phonon::PlayingState || state() == Phonon::BufferingState || state() == Phonon::PausedState) {
        AbstractMediaProducer::stop();
        m_aboutToFinishNotEmitted = true;
    }
}

void MediaObject::seek( qint64 time )
{
	//kDebug( 604 ) << k_funcinfo << endl;
	AbstractMediaProducer::seek( time );

	if( currentTime() < totalTime() - m_aboutToFinishTime ) // not about to finish
		m_aboutToFinishNotEmitted = true;
}

void MediaObject::emitTick()
{
	AbstractMediaProducer::emitTick();
	if( currentTime() >= totalTime() - m_aboutToFinishTime ) // about to finish
	{
		if( m_aboutToFinishNotEmitted )
		{
			m_aboutToFinishNotEmitted = false;
			emit aboutToFinish( totalTime() - currentTime() );
		}
	}
	if( currentTime() >= totalTime() ) // finished
	{
		stop();
		emit finished();
	}
}

}}

#include "mediaobject.moc"
// vim: sw=4 ts=4
<commit_msg>ups, forgot to add the parameter in the implementation, too<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

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

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

*/

#include "mediaobject.h"
#include <QTimer>
#include <kdebug.h>

namespace Phonon
{
namespace Fake
{
MediaObject::MediaObject( QObject* parent )
	: AbstractMediaProducer( parent )
	, m_aboutToFinishNotEmitted( true )
{
	//kDebug( 604 ) << k_funcinfo << endl;
}

MediaObject::~MediaObject()
{
	//kDebug( 604 ) << k_funcinfo << endl;
}

KUrl MediaObject::url() const
{
	//kDebug( 604 ) << k_funcinfo << endl;
	return m_url;
}

qint64 MediaObject::totalTime() const
{
	//kDebug( 604 ) << k_funcinfo << endl;
	return 1000*60*3; // 3 minutes
}

qint32 MediaObject::aboutToFinishTime() const
{
	//kDebug( 604 ) << k_funcinfo << endl;
	return m_aboutToFinishTime;
}

void MediaObject::setUrl( const KUrl& url )
{
	//kDebug( 604 ) << k_funcinfo << endl;
    m_aboutToFinishNotEmitted = true;
	m_url = url;
    setState(Phonon::LoadingState);
    if (!m_url.isValid() || m_url.isEmpty()) {
        return;
    }
	emit length( totalTime() );
	QMultiMap<QString, QString> metaData;
	metaData.insert( "TITLE", "Fake video" );
	metaData.insert( "ARTIST", "Matthias Kretz" );
	emit metaDataChanged( metaData );
    QTimer::singleShot(50, this, SLOT(loadingComplete()));
}

void MediaObject::openMedia(Phonon::MediaObject::Media media, const QString &)
{
    switch (media) {
    case Phonon::MediaObject::None:
        setUrl(KUrl());
        break;
    case Phonon::MediaObject::CD:
    case Phonon::MediaObject::DVD:
    case Phonon::MediaObject::VCD:
        break;
    default:
        kError(604) << "media " << media << " not implemented" << endl;
    }
}

void MediaObject::loadingComplete()
{
    if (state() == Phonon::LoadingState) {
        setState(Phonon::StoppedState);
    } else if (state() == Phonon::BufferingState) {
        setState(Phonon::PlayingState);
    }
}

void MediaObject::setAboutToFinishTime( qint32 newAboutToFinishTime )
{
	//kDebug( 604 ) << k_funcinfo << endl;
	m_aboutToFinishTime = newAboutToFinishTime;
	if( currentTime() < totalTime() - m_aboutToFinishTime ) // not about to finish
		m_aboutToFinishNotEmitted = true;
}

void MediaObject::play()
{
	//kDebug( 604 ) << k_funcinfo << endl;
	AbstractMediaProducer::play();
}

void MediaObject::pause()
{
	//kDebug( 604 ) << k_funcinfo << endl;
    if (state() == Phonon::PlayingState || state() == Phonon::BufferingState) {
        AbstractMediaProducer::pause();
    }
}

void MediaObject::stop()
{
    //kDebug(604) << k_funcinfo << endl;
    if (state() == Phonon::PlayingState || state() == Phonon::BufferingState || state() == Phonon::PausedState) {
        AbstractMediaProducer::stop();
        m_aboutToFinishNotEmitted = true;
    }
}

void MediaObject::seek( qint64 time )
{
	//kDebug( 604 ) << k_funcinfo << endl;
	AbstractMediaProducer::seek( time );

	if( currentTime() < totalTime() - m_aboutToFinishTime ) // not about to finish
		m_aboutToFinishNotEmitted = true;
}

void MediaObject::emitTick()
{
	AbstractMediaProducer::emitTick();
	if( currentTime() >= totalTime() - m_aboutToFinishTime ) // about to finish
	{
		if( m_aboutToFinishNotEmitted )
		{
			m_aboutToFinishNotEmitted = false;
			emit aboutToFinish( totalTime() - currentTime() );
		}
	}
	if( currentTime() >= totalTime() ) // finished
	{
		stop();
		emit finished();
	}
}

}}

#include "mediaobject.moc"
// vim: sw=4 ts=4
<|endoftext|>