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

/**
 * @ file md25.cpp
 *
 * Driver for MD25 I2C Motor Driver
 *
 * references:
 * http://www.robot-electronics.co.uk/htm/md25tech.htm
 * http://www.robot-electronics.co.uk/files/rpi_md25.c
 *
 */

#include <nuttx/config.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <systemlib/systemlib.h>
#include <systemlib/param/param.h>

#include <arch/board/board.h>
#include "MD25.hpp"

static bool thread_should_exit = false;     /**< Deamon exit flag */
static bool thread_running = false;     /**< Deamon status flag */
static int deamon_task;             /**< Handle of deamon task / thread */

/**
 * Deamon management function.
 */
extern "C" __EXPORT int md25_main(int argc, char *argv[]);

/**
 * Mainloop of deamon.
 */
int md25_thread_main(int argc, char *argv[]);

/**
 * Print the correct usage.
 */
static void usage(const char *reason);

static void
usage(const char *reason)
{
	if (reason)
		fprintf(stderr, "%s\n", reason);

	fprintf(stderr, "usage: md25 {start|stop|status|search|test|change_address}\n\n");
	exit(1);
}

/**
 * The deamon app only briefly exists to start
 * the background job. The stack size assigned in the
 * Makefile does only apply to this management task.
 *
 * The actual stack size should be set in the call
 * to task_create().
 */
int md25_main(int argc, char *argv[])
{

	if (argc < 1)
		usage("missing command");

	if (!strcmp(argv[1], "start")) {

		if (thread_running) {
			printf("md25 already running\n");
			/* this is not an error */
			exit(0);
		}

		thread_should_exit = false;
		deamon_task = task_spawn("md25",
					 SCHED_DEFAULT,
					 SCHED_PRIORITY_MAX - 10,
					 2048,
					 md25_thread_main,
					 (const char **)argv);
		exit(0);
	}

	if (!strcmp(argv[1], "test")) {

		if (argc < 4) {
			printf("usage: md25 test bus address\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t address = strtoul(argv[3], nullptr, 0);

		md25Test(deviceName, bus, address);

		exit(0);
	}

	if (!strcmp(argv[1], "probe")) {
		if (argc < 4) {
			printf("usage: md25 probe bus address\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t address = strtoul(argv[3], nullptr, 0);

		MD25 md25(deviceName, bus, address);

		int ret = md25.probe();

		if (ret == OK) {
			printf("MD25 found on bus %d at address 0x%X\n", bus, md25.get_address());

		} else {
			printf("MD25 not found on bus %d\n", bus);
		}

		exit(0);
	}

	if (!strcmp(argv[1], "search")) {
		if (argc < 3) {
			printf("usage: md25 search bus\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t address = strtoul(argv[3], nullptr, 0);

		MD25 md25(deviceName, bus, address);

		md25.search();

		exit(0);
	}

	if (!strcmp(argv[1], "change_address")) {
		if (argc < 5) {
			printf("usage: md25 change_address bus old_address new_address\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t old_address = strtoul(argv[3], nullptr, 0);

		uint8_t new_address = strtoul(argv[4], nullptr, 0);

		MD25 md25(deviceName, bus, old_address);

		int ret = md25.setDeviceAddress(new_address);

		if (ret == OK)  {
			printf("MD25 new address set to 0x%X\n", new_address);

		} else {
			printf("MD25 failed to set address to 0x%X\n", new_address);
		}

		exit(0);
	}

	if (!strcmp(argv[1], "stop")) {
		thread_should_exit = true;
		exit(0);
	}

	if (!strcmp(argv[1], "status")) {
		if (thread_running) {
			printf("\tmd25 app is running\n");

		} else {
			printf("\tmd25 app not started\n");
		}

		exit(0);
	}

	usage("unrecognized command");
	exit(1);
}

int md25_thread_main(int argc, char *argv[])
{
	printf("[MD25] starting\n");

	if (argc < 5) {
		// extra md25 in arg list since this is a thread
		printf("usage: md25 start bus address\n");
		exit(0);
	}

	const char *deviceName = "/dev/md25";

	uint8_t bus = strtoul(argv[3], nullptr, 0);

	uint8_t address = strtoul(argv[4], nullptr, 0);

	// start
	MD25 md25("/dev/md25", bus, address);

	thread_running = true;

	// loop
	while (!thread_should_exit) {
		md25.update();
	}

	// exit
	printf("[MD25] exiting.\n");
	thread_running = false;
	return 0;
}

// vi:noet:smarttab:autoindent:ts=4:sw=4:tw=78
<commit_msg>fix capitalisation of include file name<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2013 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @ file md25.cpp
 *
 * Driver for MD25 I2C Motor Driver
 *
 * references:
 * http://www.robot-electronics.co.uk/htm/md25tech.htm
 * http://www.robot-electronics.co.uk/files/rpi_md25.c
 *
 */

#include <nuttx/config.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <systemlib/systemlib.h>
#include <systemlib/param/param.h>

#include <arch/board/board.h>
#include "md25.hpp"

static bool thread_should_exit = false;     /**< Deamon exit flag */
static bool thread_running = false;     /**< Deamon status flag */
static int deamon_task;             /**< Handle of deamon task / thread */

/**
 * Deamon management function.
 */
extern "C" __EXPORT int md25_main(int argc, char *argv[]);

/**
 * Mainloop of deamon.
 */
int md25_thread_main(int argc, char *argv[]);

/**
 * Print the correct usage.
 */
static void usage(const char *reason);

static void
usage(const char *reason)
{
	if (reason)
		fprintf(stderr, "%s\n", reason);

	fprintf(stderr, "usage: md25 {start|stop|status|search|test|change_address}\n\n");
	exit(1);
}

/**
 * The deamon app only briefly exists to start
 * the background job. The stack size assigned in the
 * Makefile does only apply to this management task.
 *
 * The actual stack size should be set in the call
 * to task_create().
 */
int md25_main(int argc, char *argv[])
{

	if (argc < 1)
		usage("missing command");

	if (!strcmp(argv[1], "start")) {

		if (thread_running) {
			printf("md25 already running\n");
			/* this is not an error */
			exit(0);
		}

		thread_should_exit = false;
		deamon_task = task_spawn("md25",
					 SCHED_DEFAULT,
					 SCHED_PRIORITY_MAX - 10,
					 2048,
					 md25_thread_main,
					 (const char **)argv);
		exit(0);
	}

	if (!strcmp(argv[1], "test")) {

		if (argc < 4) {
			printf("usage: md25 test bus address\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t address = strtoul(argv[3], nullptr, 0);

		md25Test(deviceName, bus, address);

		exit(0);
	}

	if (!strcmp(argv[1], "probe")) {
		if (argc < 4) {
			printf("usage: md25 probe bus address\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t address = strtoul(argv[3], nullptr, 0);

		MD25 md25(deviceName, bus, address);

		int ret = md25.probe();

		if (ret == OK) {
			printf("MD25 found on bus %d at address 0x%X\n", bus, md25.get_address());

		} else {
			printf("MD25 not found on bus %d\n", bus);
		}

		exit(0);
	}

	if (!strcmp(argv[1], "search")) {
		if (argc < 3) {
			printf("usage: md25 search bus\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t address = strtoul(argv[3], nullptr, 0);

		MD25 md25(deviceName, bus, address);

		md25.search();

		exit(0);
	}

	if (!strcmp(argv[1], "change_address")) {
		if (argc < 5) {
			printf("usage: md25 change_address bus old_address new_address\n");
			exit(0);
		}

		const char *deviceName = "/dev/md25";

		uint8_t bus = strtoul(argv[2], nullptr, 0);

		uint8_t old_address = strtoul(argv[3], nullptr, 0);

		uint8_t new_address = strtoul(argv[4], nullptr, 0);

		MD25 md25(deviceName, bus, old_address);

		int ret = md25.setDeviceAddress(new_address);

		if (ret == OK)  {
			printf("MD25 new address set to 0x%X\n", new_address);

		} else {
			printf("MD25 failed to set address to 0x%X\n", new_address);
		}

		exit(0);
	}

	if (!strcmp(argv[1], "stop")) {
		thread_should_exit = true;
		exit(0);
	}

	if (!strcmp(argv[1], "status")) {
		if (thread_running) {
			printf("\tmd25 app is running\n");

		} else {
			printf("\tmd25 app not started\n");
		}

		exit(0);
	}

	usage("unrecognized command");
	exit(1);
}

int md25_thread_main(int argc, char *argv[])
{
	printf("[MD25] starting\n");

	if (argc < 5) {
		// extra md25 in arg list since this is a thread
		printf("usage: md25 start bus address\n");
		exit(0);
	}

	const char *deviceName = "/dev/md25";

	uint8_t bus = strtoul(argv[3], nullptr, 0);

	uint8_t address = strtoul(argv[4], nullptr, 0);

	// start
	MD25 md25("/dev/md25", bus, address);

	thread_running = true;

	// loop
	while (!thread_should_exit) {
		md25.update();
	}

	// exit
	printf("[MD25] exiting.\n");
	thread_running = false;
	return 0;
}

// vi:noet:smarttab:autoindent:ts=4:sw=4:tw=78
<|endoftext|>


<commit_before><commit_msg>clang<commit_after><|endoftext|>


<commit_before>#include "SilentCompiler.h"
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
//File reader
class fileReader{
	public:
	fileReader()
	{

	}
	string readAllText(string path)
	{
		string output;
		ifstream file(path);
		output.assign((istreambuf_iterator<char>(file)),
			(istreambuf_iterator<char>()));
		return output;
	}
	vector<string> readAllLines(string path)
	{
		vector<string> output;
		ifstream file(path);
		//if(source.is_open())
		return output;
	}
	string readLine(string path)
	{
		string output;
		ifstream file(path);

		return output;
	}
};

//Compiler structures
enum silentTokenType
{
	//Symbols
	silentPlusToken,
	silentMinusToken,
	silentMultiplyToken,
	silentDivideToken,
	silentParenthesToken,
	silentQuotationToken,
	silentSemicolonToken,

	//Structure
	silentClassToken,
	silentFunctionToken,
	silentStructToken,
	silentArrayToken,

	//Access
	silentPublicToken,
	silentPrivateToken,
	silentProtectedToken,

	//Data
	silentByteToken,
	silentIntegerToken,
	silentFloatToken,
	silentLongToken,
	silentDoubleToken,
	silentStringToken,
};

typedef struct silentToken
{
	silentTokenType type;
	std::string value;

}silentToken;

enum silentNodeType
{
	//Value
	silentCharacterNode,
	silentStringNode,
	silentIntegerNode,
	silentLongNode,
	silentFloatNode,
	silentDoubleNode,

	//Functionality
	silentAdditionNode,
	silentSubtractionNode,
	silentMultiplicationNode,
	silentDivisionNode,
	silentAssignNode,
	silentReturnNode,

	//Structure
	silentIfNode,
	silentWhileNode,
	silentForNode,

};

typedef struct silentValueNode
{
	silentNodeType type;
	string value;
}silentValueNode;

typedef struct silentExpressionNode
{
	silentNodeType type;
	silentValueNode parameters[2];

}silentExpressionNode;

typedef struct silentFunctionNode
{

}silentFunctionNode;

//Helper functions
char silentTestLetter(char character)
{
	string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

	for(int i = 0; i < letters.length(); i++)
	{
		if(character == letters[i])
		{
			return 1;
			break;
		}
	}
	return 0;
}

char silentTestNumber(char character)
{
	string numbers = "1234567890";
	for(int i = 0; i < numbers.length(); i++)
	{
		if(character == numbers[i])
		{
			return 1;
			break;
		}
	}
	return 0;
}

char silentTestWhitespace(char character)
{
	if(isspace(character))
	{
		return 1;
	}

	else
	{
		return 0;
	}
}

//Tokenizer

vector<silentToken> silentTokenize(string source)
{
	long currentChar = 0;
	long currentLine = 0;
	vector<silentToken> tokens;

	for(int i = 0; i < source.length(); i++)
	{

	}

	return tokens;
}

//Parser

//Transform

//Code Generation

string* silentCompile(string path)
{

	fileReader fr;
	string rawSource = fr.readAllText(path);//no AST
	vector<silentToken> tokens = silentTokenize(rawSource);

}
<commit_msg>add to tokenizer<commit_after>#include "SilentCompiler.h"
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
//File reader
class fileReader{
	public:
	fileReader()
	{

	}

	//Read all characters from a file
	string readAllText(string path)
	{
		string output;
		ifstream file(path);
		output.assign((istreambuf_iterator<char>(file)),
			(istreambuf_iterator<char>()));
		return output;
	}

	//Read all lines from a file
	vector<string> readAllLines(string path)
	{
		vector<string> output;
		ifstream file(path);
		//if(source.is_open())
		return output;
	}

	//Read a single line from a file
	string readLine(string path)
	{
		string output;
		ifstream file(path);

		return output;
	}
};

//Compiler structures
enum silentTokenType
{
	//Symbols
	silentPlusToken,
	silentMinusToken,
	silentMultiplyToken,
	silentDivideToken,
	silentParenthesToken,
	silentQuotationToken,
	silentSemicolonToken,

	//Structure
	silentClassToken,
	silentFunctionToken,
	silentStructToken,
	silentArrayToken,

	//Access
	silentPublicToken,
	silentPrivateToken,
	silentProtectedToken,

	//Data
	silentByteToken,
	silentIntegerToken,
	silentFloatToken,
	silentLongToken,
	silentDoubleToken,
	silentStringToken,
};

typedef struct silentToken
{
	silentTokenType type;
	std::string value;

}silentToken;

enum silentNodeType
{
	//Value
	silentCharacterNode,
	silentStringNode,
	silentIntegerNode,
	silentLongNode,
	silentFloatNode,
	silentDoubleNode,

	//Functionality
	silentAdditionNode,
	silentSubtractionNode,
	silentMultiplicationNode,
	silentDivisionNode,
	silentAssignNode,
	silentReturnNode,

	//Structure
	silentIfNode,
	silentWhileNode,
	silentForNode,

};

typedef struct silentValueNode
{
	silentNodeType type;
	string value;
}silentValueNode;

typedef struct silentExpressionNode
{
	silentNodeType type;
	silentValueNode parameters[2];

}silentExpressionNode;

typedef struct silentFunctionNode
{
	vector<silentExpressionNode> expressions;
}silentFunctionNode;

//Helper functions
//Test whether the passed token is a character
char silentTestLetter(char character)
{
	string letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

	for(int i = 0; i < letters.length(); i++)
	{
		if(character == letters[i])
		{
			return 1;
			break;
		}
	}
	return 0;
}

//Test whether the passed token is a number
char silentTestNumber(char character)
{
	string numbers = "1234567890";
	for(int i = 0; i < numbers.length(); i++)
	{
		if(character == numbers[i])
		{
			return 1;
			break;
		}
	}
	return 0;
}

//Test whether the passed token is whitespace
char silentTestWhitespace(char character)
{
	if(isspace(character))
	{
		return 1;
	}

	else
	{
		return 0;
	}
}

//Tokenizer

vector<silentToken> silentTokenize(string source)
{
	long currentChar = 0;
	long currentLine = 0;
	vector<silentToken> tokens;

	for(int i = 0; i < source.length(); i++)
	{
		silentToken token;

		if((source[i] == *"(") || (source[i] == *")"))
		{
			token.type = silentParenthesToken;
			token.value = source[i];
		}

		if(source[i] == *"\"")
		{
			token.type = silentQuotationToken;
			token.value = "";
			for(int j = 1; source[i+j] != *"\"";j++)
			{
				token.value += source[i+j];
			}
		}

		if(silentTestWhitespace(source[i]))
		{
			continue;
		}

		tokens.push_back(token);
	}

	return tokens;
}

//Parser

//Transform

//Code Generation

string* silentCompile(string path)
{

	fileReader fr;
	string rawSource = fr.readAllText(path);//no AST
	vector<silentToken> tokens = silentTokenize(rawSource);

}
<|endoftext|>


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

#include <atomic>
#include <cstdint>
#include <thread>

#include "MTL/Metal.h"
#include "GUI/Frame.h"
#include "PLT/Event.h"

std::atomic<uint8_t> gpio{0};

class VirtualDevice
{
public:
   VirtualDevice()
   {
      frame.clear(STB::BLACK);
      frame.refresh();

      PLT::Event::setTimer(50);
   }

   int eventLoop()
   {
      return PLT::Event::eventLoop(callback, this);
   }

private:
   static void callback(const PLT::Event::Message& event, void* ptr)
   {
      VirtualDevice* that = (VirtualDevice*)ptr;

      switch(event.type)
      {
      case PLT::Event::TIMER:
         that->redraw();
         break;

      default:
         break;
      }
   }

   void redraw()
   {
      for(size_t i=0; i<8; i++)
      {
         bool state = ((gpio >> i) & 1) != 0;
         if (state)
         {
            frame.fillRect(STB::RED,   10 + i * 40, 10, 30 + i * 40, 25);
         }
         else
         {
            frame.fillRect(STB::GREEN, 10 + i * 40, 10, 30 + i * 40, 25);
         }
      }

      frame.refresh();
   }

   GUI::Frame frame{"Metal", 400, 100};
};

int main()
{
   VirtualDevice device;

   std::thread thread{mtlMain};
   thread.detach();

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

#include <atomic>
#include <cstdint>
#include <thread>

#include "MTL/Metal.h"
#include "GUI/Frame.h"
#include "PLT/Event.h"

std::atomic<uint8_t> gpio{0};

//! Virtual Metal platform
class VirtualMetalPlatform
{
public:
   VirtualMetalPlatform()
   {
      frame.clear(STB::BLACK);
      frame.refresh();

      PLT::Event::setTimer(1000 / REFRESH_RATE_HZ);
   }

   int eventLoop()
   {
      return PLT::Event::eventLoop(callback, this);
   }

private:
   static void callback(const PLT::Event::Message& event, void* ptr)
   {
      VirtualMetalPlatform* that = (VirtualMetalPlatform*)ptr;
      that->handleEvent(event);
   }

   void handleEvent(const PLT::Event::Message& event)
   {
      switch(event.type)
      {
      case PLT::Event::TIMER:
         if (launch_application)
         {
             launch_application = false;

             // Start the metal application
             std::thread thread{mtlMain};
             thread.detach();
         }
         redraw();
         break;

      default:
         break;
      }
   }

   void drawLED(unsigned x, unsigned y, bool state)
   {
      STB::Colour colour = state ? STB::RED
                                 : STB::RGB(0x40, 0, 0);

      frame.fillRect(colour, x, y, x + 20, y + 15);
   }

   void redraw()
   {
      for(size_t i=0; i<8; i++)
      {
         unsigned x     = 10 + (8 - i) * 40;
         unsigned y     = 10;
         bool     state = ((gpio >> i) & 1) != 0;

         drawLED(x, y, state);
      }

      frame.refresh();
   }

   static const unsigned REFRESH_RATE_HZ = 20;

   GUI::Frame frame{"Metal", 400, 100};
   bool       launch_application{true};
};

int main()
{
   return VirtualMetalPlatform().eventLoop();
}
<|endoftext|>


<commit_before>/*
** Copyright 2011 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QCoreApplication>
#include <QMutexLocker>
#include <QReadLocker>
#include <QTimer>
#include <QWriteLocker>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/exceptions/with_pointer.hh"
#include "com/centreon/broker/io/exceptions/shutdown.hh"
#include "com/centreon/broker/io/raw.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/multiplexing/publisher.hh"
#include "com/centreon/broker/multiplexing/subscriber.hh"
#include "com/centreon/broker/processing/failover.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::processing;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Constructor.
 *
 *  @param[in] is_out true if the failover thread is an output thread.
 */
failover::failover(bool is_out)
  : _initial(true),
    _is_out(is_out),
    _retry_interval(30),
    _immediate(true),
    _should_exit(false),
    _should_exitm(QMutex::Recursive) {
  if (_is_out)
    _from = QSharedPointer<io::stream>(new multiplexing::subscriber);
  else
    _to = QSharedPointer<io::stream>(new multiplexing::publisher);
}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
failover::failover(failover const& f)
  :  QThread(),
     io::stream(),
     _endpoint(f._endpoint),
     _failover(f._failover),
     _initial(true),
     _is_out(f._is_out),
     _retry_interval(f._retry_interval),
     _immediate(true),
     _should_exit(false),
     _should_exitm(QMutex::Recursive) {
  {
    QMutexLocker lock(&f._datam);
    _data = f._data;
  }
  {
    QWriteLocker lock(&f._fromm);
    _from = f._from;
  }
  {
    QWriteLocker lock(&f._tom);
    _to = f._to;
  }
}

/**
 *  Destructor.
 */
failover::~failover() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
failover& failover::operator=(failover const& f) {
  if (this != &f) {
    _endpoint = f._endpoint;
    _failover = f._failover;
    _is_out = f._is_out;
    _retry_interval = f._retry_interval;
    {
      QMutexLocker lock(&f._datam);
      _data = f._data;
    }
    {
      QWriteLocker lock(&f._fromm);
      _from = f._from;
    }
    {
      QWriteLocker lock(&f._tom);
      _to = f._to;
    }
  }
  return (*this);
}

/**
 *  Get retry interval.
 *
 *  @return Failover thread retry interval.
 */
time_t failover::get_retry_interval() const throw () {
  return (_retry_interval);
}

/**
 *  Stop or start processing.
 *
 *  @param[in] in  true to process inputs.
 *  @param[in] out true to process outputs.
 */
void failover::process(bool in, bool out) {
  // Set exit flag.
  QMutexLocker lock(&_should_exitm);
  bool should_exit = _should_exit;
  _immediate = (!in && out);
  _should_exit = (!in || !out);

  // Quit event loop.
  if ((!in || !out) && isRunning()) {
    QTimer::singleShot(0, this, SLOT(quit()));
    QCoreApplication::processEvents();
  }

  // Full delayed shutdown.
  if (!in && !out) {
    _endpoint->close();
    bool tweaked_in(_failover.isNull());
    QReadLocker lock(&_fromm);
    if (!_from.isNull())
      _from->process(tweaked_in, false);
  }
  // Single delayed shutdown.
  else if (in && !out) {
    _endpoint->close();
    QReadLocker lock(&_fromm);
    if (!_from.isNull())
      _from->process(true, false);
  }
  // Immediate shutdown.
  else if (!in && out) {
    _endpoint->close();
    QList<QSharedPointer<QMutexLocker> > locks;
    bool all_failover_not_running(true);
    failover* last(this);
    for (QSharedPointer<failover> fo = _failover;
         !fo.isNull();
         fo = fo->_failover) {
      QSharedPointer<QMutexLocker>
        lock(new QMutexLocker(&fo->_should_exitm));
      all_failover_not_running
        = all_failover_not_running && !fo->isRunning();
      locks.push_back(lock);
      last = fo.data();
    }

    // Shutdown subscriber.
    if (all_failover_not_running) {
      QReadLocker rl(&last->_fromm);
      if (!last->_from.isNull())
        last->_from->process(false, true);
    }

    // Wait for thread to terminate.
    locks.clear();
    lock.unlock();
    QThread::wait();
    logging::debug(logging::medium) << "failover: thread "
      << this << " terminated";
    lock.relock();
    process(true, !should_exit);
    lock.unlock();
  }
  // Reinitialization.
  else {
    QReadLocker rl(&_fromm);
    if (!_from.isNull())
      _from->process(true, true);
  }

  return ;
}

/**
 *  Read data.
 *
 *  @param[out] data Data buffer.
 *  @param[out] type Data type.
 */
QSharedPointer<io::data> failover::read() {
  // Read retained data.
  QSharedPointer<io::data> data;
  QMutexLocker exit_lock(&_should_exitm);
  if (isRunning() && QThread::currentThread() != this) {
    // Release thread lock.
    exit_lock.unlock();

    // Read data from destination.
    logging::debug(logging::low)
      << "failover: reading retained data from failover thread";
    bool caught(false);
    QReadLocker tom(&_tom);
    try {
      if (!_to.isNull())
        data = _to->read();
      logging::debug(logging::low)
        << "failover: got retained event from failover thread";
    }
    catch (...) {
      caught = true;
    }

    // End of destination is reached, shutdown this thread.
    if (caught || data.isNull()) {
      logging::debug(logging::low)
        << "failover: could not get event from failover thread "
        << this;
      logging::info(logging::medium)
        << "failover: requesting failover thread " << this
        << " termination";

      // Reset lock.
      _to.clear();
      _tom.unlock();

      // Reread should exit.
      exit_lock.relock();
      bool should_exit(_should_exit);
      exit_lock.unlock();

      // Exit this thread immediately.
      process(false, true);

      // Recursive data reading.
      if (!should_exit)
	data = this->read();
    }
  }
  // Fetch next available event.
  else {
    // Release thread lock.
    exit_lock.unlock();

    // Try the one retained event.
    QMutexLocker lock(&_datam);
    if (!_data.isNull()) {
      data = _data;
      _data.clear();
      lock.unlock();
    }
    // Read from source.
    else {
      lock.unlock();
      QReadLocker fromm(&_fromm);
      data = _from->read();
    }
    logging::debug(logging::low)
      << "failover: got event from normal source";
  }
  return (data);
}

/**
 *  Thread core function.
 */
void failover::run() {
  // Check endpoint.
  if (_endpoint.isNull()) {
    logging::error(logging::high) << "failover: attempt to run a " \
      "thread with a non-existent endpoint";
    return ;
  }

  // Launch subfailover to fetch retained data.
  if (_initial && !_failover.isNull()) {
    connect(&*_failover, SIGNAL(exception_caught()), SLOT(quit()));
    connect(&*_failover, SIGNAL(initial_lock()), SLOT(quit()));
    connect(&*_failover, SIGNAL(finished()), SLOT(quit()));
    connect(&*_failover, SIGNAL(terminated()), SLOT(quit()));
    _failover->start();
    exec();
    disconnect(
      &*_failover,
      SIGNAL(exception_caught()),
      this,
      SLOT(quit()));
    disconnect(
      &*_failover,
      SIGNAL(initial_lock()),
      this,
      SLOT(quit()));
    disconnect(
      &*_failover,
      SIGNAL(finished()),
      this,
      SLOT(quit()));
    disconnect(
      &*_failover,
      SIGNAL(terminated()),
      this,
      SLOT(quit()));
    _initial = false;
  }

  // Failover should continue as long as not exit request was received.
  logging::debug(logging::medium) << "failover: launching loop";
  QMutexLocker exit_lock(&_should_exitm);
  _should_exit = false;

  while (!_should_exit) {
    QSharedPointer<io::stream> copy_handler;
    exit_lock.unlock();
    try {
      // Close previous endpoint if any and then open it.
      logging::debug(logging::medium) << "failover: opening endpoint";
      QReadWriteLock* rwl;
      QSharedPointer<io::stream>* s;
      if (_is_out) {
        rwl = &_tom;
        s = &_to;
      }
      else {
        rwl = &_fromm;
        s = &_from;
      }
      {
        QWriteLocker wl(rwl);
        s->clear();
        wl.unlock();
        QSharedPointer<io::stream> tmp(_endpoint->open());
        wl.relock();
        emit initial_lock();
        *s = tmp;
        if (s->isNull()) { // Retry connection.
          logging::debug(logging::medium)
            << "failover: resulting stream is nul, retrying";
          exit_lock.relock();
          continue ;
        }
        copy_handler = *s;
      }

      // Process input and output.
      logging::debug(logging::medium) << "failover: launching feeding";
      QSharedPointer<io::data> data;
      exit_lock.relock();
      while (!_should_exit || !_immediate) {
        exit_lock.unlock();
        try {
          {
            QReadLocker lock(&_fromm);
            if (!_from.isNull())
              data = _from->read();
          }
          if (data.isNull()) {
            exit_lock.relock();
            _immediate = true;
            _should_exit = true;
            exit_lock.unlock();
          }
          else {
            QWriteLocker lock(&_tom);
            if (!_to.isNull())
              _to->write(data);
          }
        }
        catch (exceptions::msg const& e) {
          try {
            throw (exceptions::with_pointer(e, data));
          }
          catch (exceptions::with_pointer const& e) {
            throw ;
          }
          catch (...) {}
          throw ;
        }
        data.clear();
        exit_lock.relock();
      }
    }
    catch (exceptions::with_pointer const& e) {
      logging::error(logging::high) << e.what();
      if (!e.ptr().isNull() && !_failover.isNull() && !_failover->isRunning())
        _failover->write(e.ptr());
    }
    catch (io::exceptions::shutdown const& e) {
      logging::info(logging::medium)
        << "failover: a stream has shutdown: " << e.what();
    }
    catch (exceptions::msg const& e) {
      logging::error(logging::high) << e.what();
    }
    catch (std::exception const& e) {
      logging::error(logging::high)
        << "failover: standard library error: " << e.what();
    }
    catch (...) {
      logging::error(logging::high)
        << "failover: unknown error caught in processing thread";
    }
    emit exception_caught();
    if (_is_out) {
      QWriteLocker lock(&_tom);
      _to.clear();
    }
    else {
      QWriteLocker lock(&_fromm);
      _from.clear();
    }

    // Relock thread lock.
    exit_lock.relock();

    if (!_failover.isNull() && !_failover->isRunning() && !_should_exit) {
      connect(&*_failover, SIGNAL(exception_caught()), SLOT(quit()));
      connect(&*_failover, SIGNAL(initial_lock()), SLOT(quit()));
      connect(&*_failover, SIGNAL(finished()), SLOT(quit()));
      connect(&*_failover, SIGNAL(terminated()), SLOT(quit()));
      _failover->start();
      exec();
      disconnect(
        &*_failover,
        SIGNAL(exception_caught()),
        this,
        SLOT(quit()));
      disconnect(
        &*_failover,
        SIGNAL(initial_lock()),
        this,
        SLOT(quit()));
      disconnect(
        &*_failover,
        SIGNAL(finished()),
        this,
        SLOT(quit()));
      disconnect(
        &*_failover,
        SIGNAL(terminated()),
        this,
        SLOT(quit()));
    }
    if (!_should_exit) {
      // Unlock thread lock.
      exit_lock.unlock();
      logging::info(logging::medium) << "failover: sleeping "
        << _retry_interval << " seconds before reconnection";
      QTimer::singleShot(_retry_interval * 1000, this, SLOT(quit()));
      exec();
      // Relock thread lock.
      exit_lock.relock();
    }
  }
  return ;
}

/**
 *  Set thread endpoint.
 *
 *  @param[in] endp Thread endpoint.
 */
void failover::set_endpoint(QSharedPointer<io::endpoint> endp) {
  _endpoint = endp;
  return ;
}

/**
 *  Set the thread's failover.
 *
 *  @param[in] fo Thread's failover.
 */
void failover::set_failover(QSharedPointer<failover> fo) {
  _failover = fo;
  if (!fo.isNull() && _is_out) { // failover object will act as input for output threads.
    QWriteLocker lock(&_fromm);
    _from = _failover;
  }
  return ;
}

/**
 *  Set the connection retry interval.
 *
 *  @param[in] retry_interval Time to wait between two connection
 *                            attempts.
 */
void failover::set_retry_interval(time_t retry_interval) {
  _retry_interval = retry_interval;
  return ;
}

/**
 *  Wait for this thread to terminate along with other failovers.
 *
 *  @param[in] time Maximum time to wait for thread termination.
 */
bool failover::wait(unsigned long time) {
  if (!_failover.isNull())
    _failover->wait(time);
  return (this->QThread::wait(time));
}

/**
 *  Write data.
 *
 *  @param[in] d Unused.
 *
 *  @return Does not return, throw an exception.
 */
void failover::write(QSharedPointer<io::data> d) {
  QMutexLocker lock(&_datam);
  _data = d;
  return ;
}
<commit_msg>Add QThread::wait into the failover destructor.<commit_after>/*
** Copyright 2011 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QCoreApplication>
#include <QMutexLocker>
#include <QReadLocker>
#include <QTimer>
#include <QWriteLocker>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/exceptions/with_pointer.hh"
#include "com/centreon/broker/io/exceptions/shutdown.hh"
#include "com/centreon/broker/io/raw.hh"
#include "com/centreon/broker/logging/logging.hh"
#include "com/centreon/broker/multiplexing/publisher.hh"
#include "com/centreon/broker/multiplexing/subscriber.hh"
#include "com/centreon/broker/processing/failover.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::processing;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Constructor.
 *
 *  @param[in] is_out true if the failover thread is an output thread.
 */
failover::failover(bool is_out)
  : _initial(true),
    _is_out(is_out),
    _retry_interval(30),
    _immediate(true),
    _should_exit(false),
    _should_exitm(QMutex::Recursive) {
  if (_is_out)
    _from = QSharedPointer<io::stream>(new multiplexing::subscriber);
  else
    _to = QSharedPointer<io::stream>(new multiplexing::publisher);
}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
failover::failover(failover const& f)
  :  QThread(),
     io::stream(),
     _endpoint(f._endpoint),
     _failover(f._failover),
     _initial(true),
     _is_out(f._is_out),
     _retry_interval(f._retry_interval),
     _immediate(true),
     _should_exit(false),
     _should_exitm(QMutex::Recursive) {
  {
    QMutexLocker lock(&f._datam);
    _data = f._data;
  }
  {
    QWriteLocker lock(&f._fromm);
    _from = f._from;
  }
  {
    QWriteLocker lock(&f._tom);
    _to = f._to;
  }
}

/**
 *  Destructor.
 */
failover::~failover() { QThread::wait(); }

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
failover& failover::operator=(failover const& f) {
  if (this != &f) {
    _endpoint = f._endpoint;
    _failover = f._failover;
    _is_out = f._is_out;
    _retry_interval = f._retry_interval;
    {
      QMutexLocker lock(&f._datam);
      _data = f._data;
    }
    {
      QWriteLocker lock(&f._fromm);
      _from = f._from;
    }
    {
      QWriteLocker lock(&f._tom);
      _to = f._to;
    }
  }
  return (*this);
}

/**
 *  Get retry interval.
 *
 *  @return Failover thread retry interval.
 */
time_t failover::get_retry_interval() const throw () {
  return (_retry_interval);
}

/**
 *  Stop or start processing.
 *
 *  @param[in] in  true to process inputs.
 *  @param[in] out true to process outputs.
 */
void failover::process(bool in, bool out) {
  // Set exit flag.
  QMutexLocker lock(&_should_exitm);
  bool should_exit = _should_exit;
  _immediate = (!in && out);
  _should_exit = (!in || !out);

  // Quit event loop.
  if ((!in || !out) && isRunning()) {
    QTimer::singleShot(0, this, SLOT(quit()));
    QCoreApplication::processEvents();
  }

  // Full delayed shutdown.
  if (!in && !out) {
    _endpoint->close();
    bool tweaked_in(_failover.isNull());
    QReadLocker lock(&_fromm);
    if (!_from.isNull())
      _from->process(tweaked_in, false);
  }
  // Single delayed shutdown.
  else if (in && !out) {
    _endpoint->close();
    QReadLocker lock(&_fromm);
    if (!_from.isNull())
      _from->process(true, false);
  }
  // Immediate shutdown.
  else if (!in && out) {
    _endpoint->close();
    QList<QSharedPointer<QMutexLocker> > locks;
    bool all_failover_not_running(true);
    failover* last(this);
    for (QSharedPointer<failover> fo = _failover;
         !fo.isNull();
         fo = fo->_failover) {
      QSharedPointer<QMutexLocker>
        lock(new QMutexLocker(&fo->_should_exitm));
      all_failover_not_running
        = all_failover_not_running && !fo->isRunning();
      locks.push_back(lock);
      last = fo.data();
    }

    // Shutdown subscriber.
    if (all_failover_not_running) {
      QReadLocker rl(&last->_fromm);
      if (!last->_from.isNull())
        last->_from->process(false, true);
    }

    // Wait for thread to terminate.
    locks.clear();
    lock.unlock();
    QThread::wait();
    logging::debug(logging::medium) << "failover: thread "
      << this << " terminated";
    lock.relock();
    process(true, !should_exit);
    lock.unlock();
  }
  // Reinitialization.
  else {
    QReadLocker rl(&_fromm);
    if (!_from.isNull())
      _from->process(true, true);
  }

  return ;
}

/**
 *  Read data.
 *
 *  @param[out] data Data buffer.
 *  @param[out] type Data type.
 */
QSharedPointer<io::data> failover::read() {
  // Read retained data.
  QSharedPointer<io::data> data;
  QMutexLocker exit_lock(&_should_exitm);
  if (isRunning() && QThread::currentThread() != this) {
    // Release thread lock.
    exit_lock.unlock();

    // Read data from destination.
    logging::debug(logging::low)
      << "failover: reading retained data from failover thread";
    bool caught(false);
    QReadLocker tom(&_tom);
    try {
      if (!_to.isNull())
        data = _to->read();
      logging::debug(logging::low)
        << "failover: got retained event from failover thread";
    }
    catch (...) {
      caught = true;
    }

    // End of destination is reached, shutdown this thread.
    if (caught || data.isNull()) {
      logging::debug(logging::low)
        << "failover: could not get event from failover thread "
        << this;
      logging::info(logging::medium)
        << "failover: requesting failover thread " << this
        << " termination";

      // Reset lock.
      _to.clear();
      _tom.unlock();

      // Reread should exit.
      exit_lock.relock();
      bool should_exit(_should_exit);
      exit_lock.unlock();

      // Exit this thread immediately.
      process(false, true);

      // Recursive data reading.
      if (!should_exit)
	data = this->read();
    }
  }
  // Fetch next available event.
  else {
    // Release thread lock.
    exit_lock.unlock();

    // Try the one retained event.
    QMutexLocker lock(&_datam);
    if (!_data.isNull()) {
      data = _data;
      _data.clear();
      lock.unlock();
    }
    // Read from source.
    else {
      lock.unlock();
      QReadLocker fromm(&_fromm);
      data = _from->read();
    }
    logging::debug(logging::low)
      << "failover: got event from normal source";
  }
  return (data);
}

/**
 *  Thread core function.
 */
void failover::run() {
  // Check endpoint.
  if (_endpoint.isNull()) {
    logging::error(logging::high) << "failover: attempt to run a " \
      "thread with a non-existent endpoint";
    return ;
  }

  // Launch subfailover to fetch retained data.
  if (_initial && !_failover.isNull()) {
    connect(&*_failover, SIGNAL(exception_caught()), SLOT(quit()));
    connect(&*_failover, SIGNAL(initial_lock()), SLOT(quit()));
    connect(&*_failover, SIGNAL(finished()), SLOT(quit()));
    connect(&*_failover, SIGNAL(terminated()), SLOT(quit()));
    _failover->start();
    exec();
    disconnect(
      &*_failover,
      SIGNAL(exception_caught()),
      this,
      SLOT(quit()));
    disconnect(
      &*_failover,
      SIGNAL(initial_lock()),
      this,
      SLOT(quit()));
    disconnect(
      &*_failover,
      SIGNAL(finished()),
      this,
      SLOT(quit()));
    disconnect(
      &*_failover,
      SIGNAL(terminated()),
      this,
      SLOT(quit()));
    _initial = false;
  }

  // Failover should continue as long as not exit request was received.
  logging::debug(logging::medium) << "failover: launching loop";
  QMutexLocker exit_lock(&_should_exitm);
  _should_exit = false;

  while (!_should_exit) {
    QSharedPointer<io::stream> copy_handler;
    exit_lock.unlock();
    try {
      // Close previous endpoint if any and then open it.
      logging::debug(logging::medium) << "failover: opening endpoint";
      QReadWriteLock* rwl;
      QSharedPointer<io::stream>* s;
      if (_is_out) {
        rwl = &_tom;
        s = &_to;
      }
      else {
        rwl = &_fromm;
        s = &_from;
      }
      {
        QWriteLocker wl(rwl);
        s->clear();
        wl.unlock();
        QSharedPointer<io::stream> tmp(_endpoint->open());
        wl.relock();
        emit initial_lock();
        *s = tmp;
        if (s->isNull()) { // Retry connection.
          logging::debug(logging::medium)
            << "failover: resulting stream is nul, retrying";
          exit_lock.relock();
          continue ;
        }
        copy_handler = *s;
      }

      // Process input and output.
      logging::debug(logging::medium) << "failover: launching feeding";
      QSharedPointer<io::data> data;
      exit_lock.relock();
      while (!_should_exit || !_immediate) {
        exit_lock.unlock();
        try {
          {
            QReadLocker lock(&_fromm);
            if (!_from.isNull())
              data = _from->read();
          }
          if (data.isNull()) {
            exit_lock.relock();
            _immediate = true;
            _should_exit = true;
            exit_lock.unlock();
          }
          else {
            QWriteLocker lock(&_tom);
            if (!_to.isNull())
              _to->write(data);
          }
        }
        catch (exceptions::msg const& e) {
          try {
            throw (exceptions::with_pointer(e, data));
          }
          catch (exceptions::with_pointer const& e) {
            throw ;
          }
          catch (...) {}
          throw ;
        }
        data.clear();
        exit_lock.relock();
      }
    }
    catch (exceptions::with_pointer const& e) {
      logging::error(logging::high) << e.what();
      if (!e.ptr().isNull() && !_failover.isNull() && !_failover->isRunning())
        _failover->write(e.ptr());
    }
    catch (io::exceptions::shutdown const& e) {
      logging::info(logging::medium)
        << "failover: a stream has shutdown: " << e.what();
    }
    catch (exceptions::msg const& e) {
      logging::error(logging::high) << e.what();
    }
    catch (std::exception const& e) {
      logging::error(logging::high)
        << "failover: standard library error: " << e.what();
    }
    catch (...) {
      logging::error(logging::high)
        << "failover: unknown error caught in processing thread";
    }
    emit exception_caught();
    if (_is_out) {
      QWriteLocker lock(&_tom);
      _to.clear();
    }
    else {
      QWriteLocker lock(&_fromm);
      _from.clear();
    }

    // Relock thread lock.
    exit_lock.relock();

    if (!_failover.isNull() && !_failover->isRunning() && !_should_exit) {
      connect(&*_failover, SIGNAL(exception_caught()), SLOT(quit()));
      connect(&*_failover, SIGNAL(initial_lock()), SLOT(quit()));
      connect(&*_failover, SIGNAL(finished()), SLOT(quit()));
      connect(&*_failover, SIGNAL(terminated()), SLOT(quit()));
      _failover->start();
      exec();
      disconnect(
        &*_failover,
        SIGNAL(exception_caught()),
        this,
        SLOT(quit()));
      disconnect(
        &*_failover,
        SIGNAL(initial_lock()),
        this,
        SLOT(quit()));
      disconnect(
        &*_failover,
        SIGNAL(finished()),
        this,
        SLOT(quit()));
      disconnect(
        &*_failover,
        SIGNAL(terminated()),
        this,
        SLOT(quit()));
    }
    if (!_should_exit) {
      // Unlock thread lock.
      exit_lock.unlock();
      logging::info(logging::medium) << "failover: sleeping "
        << _retry_interval << " seconds before reconnection";
      QTimer::singleShot(_retry_interval * 1000, this, SLOT(quit()));
      exec();
      // Relock thread lock.
      exit_lock.relock();
    }
  }
  return ;
}

/**
 *  Set thread endpoint.
 *
 *  @param[in] endp Thread endpoint.
 */
void failover::set_endpoint(QSharedPointer<io::endpoint> endp) {
  _endpoint = endp;
  return ;
}

/**
 *  Set the thread's failover.
 *
 *  @param[in] fo Thread's failover.
 */
void failover::set_failover(QSharedPointer<failover> fo) {
  _failover = fo;
  if (!fo.isNull() && _is_out) { // failover object will act as input for output threads.
    QWriteLocker lock(&_fromm);
    _from = _failover;
  }
  return ;
}

/**
 *  Set the connection retry interval.
 *
 *  @param[in] retry_interval Time to wait between two connection
 *                            attempts.
 */
void failover::set_retry_interval(time_t retry_interval) {
  _retry_interval = retry_interval;
  return ;
}

/**
 *  Wait for this thread to terminate along with other failovers.
 *
 *  @param[in] time Maximum time to wait for thread termination.
 */
bool failover::wait(unsigned long time) {
  if (!_failover.isNull())
    _failover->wait(time);
  return (this->QThread::wait(time));
}

/**
 *  Write data.
 *
 *  @param[in] d Unused.
 *
 *  @return Does not return, throw an exception.
 */
void failover::write(QSharedPointer<io::data> d) {
  QMutexLocker lock(&_datam);
  _data = d;
  return ;
}
<|endoftext|>


<commit_before>// #define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file

#include <iostream>
#include <chrono>
#include <thread>
#include <cassert>
#include <cstring>
#include <list>
#include <atomic>
#include <mutex>

// #include "catch.hpp"

#include "i_stat.hpp"
#include "i_probe.hpp"
#include "task_0.hpp"
#include "scheduler_0.hpp"
#include "thread_0.hpp"

using namespace std;
using namespace e2::mt;
using namespace e2::interface;

// std::mutex mtx;

int increment( int * v ){
    // std::lock_guard<std::mutex> lck( mtx );
    if( v ) ++(*v);
    return *v;
}

int main(){
    bool ret;
    scheduler_0 * sch = new scheduler_0;
    vector< thread_0 * > thread_allocated;
    int num_threads = 3;
    for( int i = 0; i < num_threads; ++i ){
    	thread_0 * new_t =  new thread_0;
    	thread_allocated.push_back( new_t );
	ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::ADD_THREAD, new_t );
        assert( ret );
    }
    std::vector< int > vals( 100, 0);
    auto t0 = std::chrono::high_resolution_clock::now();

    std::list< ::e2::mt::task_0 > tks;

    int ans = 0;
    // while(true){
	// for( int i = 0; i < 6; ++i ){
        for( int i = 0; i < 10000000; ++i ){
	    ::e2::mt::task_0 tk;
	    tk.set( &ans, increment, &vals[i%2] );
	    tks.push_back( tk );
	    // bool ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::ADD_TASK, &tk );
	    bool ret = sch->scheduler_add_task( &tks.back() );
	    std::this_thread::yield();
	    // std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
	// auto t1 = std::chrono::high_resolution_clock::now();
	// std::chrono::duration<double> dur = t1 - t0;
	// auto dur_ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur);
	// if( dur_ms.count() > 20000 )
	//     break;
    // }

    std::this_thread::sleep_for( std::chrono::milliseconds(20000) );

    ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::END );
    assert( ret );
    std::cout << "end add." << std::endl;

    std::this_thread::sleep_for( std::chrono::milliseconds(1000) );

    size_t expected_count_tasks = 0;
    std::cout << "vals: " << std::endl;
    for( int i = 0; i < 6; ++i ){
	// assert( 0 != vals[i] );
	std::cout << vals[i] << std::endl;
	expected_count_tasks += vals[i];
    }
    std::cout << "ans: " << ans << std::endl;

    ::e2::interface::i_stat_threads stat;
    ret = sch->probe_process( ::e2::interface::e_probe_action::PROBE_FILTER_SINGLE, &stat );
    assert( ret );

    std::cout << "count total thread calls: " << stat._stat_count_thread_calls << std::endl;
    std::cout << "num thread busy: " << stat._stat_num_thread_busy << std::endl;
    std::cout << "num thread idle: " << stat._stat_num_thread_idle << std::endl;
    // assert( 0 == stat._stat_count_thread_calls );
    // assert( 0 == stat._stat_num_thread_busy );
    // assert( 0 == stat._stat_num_thread_idle );

    // ret = sch->probe_process( ::e2::interface::e_probe_action::PROBE_FILTER_SINGLE, &stat );
    // assert( ret );
    // std::cout << "count total thread calls: " << stat._stat_count_thread_calls << std::endl;
    // std::cout << "num thread busy: " << stat._stat_num_thread_busy << std::endl;
    // std::cout << "num thread idle: " << stat._stat_num_thread_idle << std::endl;
    // assert( 0 == stat._stat_count_thread_calls );
    // assert( 0 == stat._stat_num_thread_busy );
    // assert( num_threads == stat._stat_num_thread_idle );

    for( auto & i : thread_allocated ){
        ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::REMOVE_THREAD, i );
    }

    std::cout << "terminating scheduler activity." << std::endl;

    for( auto & i : thread_allocated ){
	if( i )
	    delete i;
    }

    delete sch;

    std::cout << "terminated scheduler." << std::endl;
    std::this_thread::sleep_for( std::chrono::milliseconds(20000) );

    return 0;
}
<commit_msg>revised scheduler testcase.<commit_after>// #define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file

#include <iostream>
#include <chrono>
#include <thread>
#include <cassert>
#include <cstring>
#include <list>
#include <atomic>
#include <mutex>

// #include "catch.hpp"

#include "i_stat.hpp"
#include "i_probe.hpp"
#include "task_0.hpp"
#include "scheduler_0.hpp"
#include "thread_0.hpp"

using namespace std;
using namespace e2::mt;
using namespace e2::interface;

// std::mutex mtx;

int increment( int * v ){
    // std::lock_guard<std::mutex> lck( mtx );
    if( v ) ++(*v);
    return *v;
}

int main(){
    bool ret;
    scheduler_0 * sch = new scheduler_0;
    vector< thread_0 * > thread_allocated;
    constexpr int num_threads = 3;
    for( int i = 0; i < num_threads; ++i ){
    	thread_0 * new_t =  new thread_0;
    	thread_allocated.push_back( new_t );
	ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::ADD_THREAD, new_t );
        assert( ret );
    }
    constexpr int num_vals = 6;
    std::vector< int > vals( num_vals, 0);
    auto t0 = std::chrono::high_resolution_clock::now();

    int ans = 0;
    for( int i = 0; i < 10000000; ++i ){
	::e2::mt::task_0 tk;
	tk.set( &ans, increment, &vals[ i % num_vals ] );
	bool ret = sch->scheduler_add_task( &tk );

	auto t1 = std::chrono::high_resolution_clock::now();
	std::chrono::duration<double> dur = t1 - t0;
	auto dur_ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur);
	if( dur_ms.count() > 5000 ){
	    ::e2::interface::i_stat_threads stat;
	    ret = sch->probe_process( ::e2::interface::e_probe_action::PROBE_FILTER_SINGLE, &stat );
	    assert( ret );

	    std::cout << "count total thread calls: " << stat._stat_count_thread_calls << std::endl;
	    std::cout << "num thread busy: " << stat._stat_num_thread_busy << std::endl;
	    std::cout << "num thread idle: " << stat._stat_num_thread_idle << std::endl;
	    t0 = t1;
	}
    }

    std::this_thread::sleep_for( std::chrono::milliseconds(1000) );

    ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::END );
    assert( ret );
    std::cout << "end add." << std::endl;

    std::this_thread::sleep_for( std::chrono::milliseconds(1000) );

    bool ret_val_check = false;
    size_t expected_count_tasks = 0;
    std::cout << "vals: " << std::endl;
    for( int i = 0; i < num_vals; ++i ){
	assert( 0 != vals[i] );
	std::cout << vals[i] << std::endl;
	expected_count_tasks += vals[i];
	if( ans == vals[i] )
	    ret_val_check = true;
    }
    std::cout << "ans: " << ans << std::endl;
    assert( 0 < ans );
    assert( ret_val_check );

    {
	::e2::interface::i_stat_threads stat;
	ret = sch->probe_process( ::e2::interface::e_probe_action::PROBE_FILTER_SINGLE, &stat );
	assert( ret );

	std::cout << "count total thread calls: " << stat._stat_count_thread_calls << std::endl;
	std::cout << "num thread busy: " << stat._stat_num_thread_busy << std::endl;
	std::cout << "num thread idle: " << stat._stat_num_thread_idle << std::endl;
	assert( 0 < stat._stat_count_thread_calls );
	assert( 0 == stat._stat_num_thread_busy );
	assert( num_threads == stat._stat_num_thread_idle );

	//stat again
	ret = sch->probe_process( ::e2::interface::e_probe_action::PROBE_FILTER_SINGLE, &stat );
	assert( ret );
	assert( 0 == stat._stat_count_thread_calls );
	assert( 0 == stat._stat_num_thread_busy );
	assert( num_threads == stat._stat_num_thread_idle );

    }

    for( auto & i : thread_allocated ){
        ret = sch->scheduler_process( ::e2::interface::e_scheduler_action::REMOVE_THREAD, i );
    }

    std::cout << "terminating scheduler activity." << std::endl;

    for( auto & i : thread_allocated ){
	if( i ) delete i;
    }

    delete sch;

    std::cout << "terminated scheduler." << std::endl;
    std::this_thread::sleep_for( std::chrono::milliseconds(5000) );

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * 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 "config.h"
#include "core/html/HTMLImageElement.h"

#include "CSSPropertyNames.h"
#include "HTMLNames.h"
#include "bindings/v8/ScriptEventListener.h"
#include "core/dom/Attribute.h"
#include "core/dom/EventNames.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/loader/cache/CachedImage.h"
#include "core/rendering/RenderImage.h"

using namespace std;

namespace WebCore {

using namespace HTMLNames;

HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
    : HTMLElement(tagName, document)
    , m_imageLoader(this)
    , m_form(form)
    , m_compositeOperator(CompositeSourceOver)
{
    ASSERT(hasTagName(imgTag));
    ScriptWrappable::init(this);
    if (form)
        form->registerImgElement(this);
}

PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document* document)
{
    return adoptRef(new HTMLImageElement(imgTag, document));
}

PassRefPtr<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
{
    return adoptRef(new HTMLImageElement(tagName, document, form));
}

HTMLImageElement::~HTMLImageElement()
{
    if (m_form)
        m_form->removeImgElement(this);
}

PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document* document, const int* optionalWidth, const int* optionalHeight)
{
    RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(imgTag, document));
    if (optionalWidth)
        image->setWidth(*optionalWidth);
    if (optionalHeight)
        image->setHeight(*optionalHeight);
    return image.release();
}

bool HTMLImageElement::isPresentationAttribute(const QualifiedName& name) const
{
    if (name == widthAttr || name == heightAttr || name == borderAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == valignAttr)
        return true;
    return HTMLElement::isPresentationAttribute(name);
}

void HTMLImageElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
{
    if (name == widthAttr)
        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    else if (name == heightAttr)
        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    else if (name == borderAttr)
        applyBorderAttributeToStyle(value, style);
    else if (name == vspaceAttr) {
        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
    } else if (name == hspaceAttr) {
        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
    } else if (name == alignAttr)
        applyAlignmentAttributeToStyle(value, style);
    else if (name == valignAttr)
        addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
    else
        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
}

void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    if (name == altAttr) {
        if (renderer() && renderer()->isImage())
            toRenderImage(renderer())->updateAltText();
    } else if (name == srcAttr)
        m_imageLoader.updateFromElementIgnoringPreviousError();
    else if (name == usemapAttr)
        setIsLink(!value.isNull());
    else if (name == onbeforeloadAttr)
        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
    else if (name == compositeAttr) {
        // FIXME: images don't support blend modes in their compositing attribute.
        BlendMode blendOp = BlendModeNormal;
        if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp))
            m_compositeOperator = CompositeSourceOver;
    } else
        HTMLElement::parseAttribute(name, value);
}

String HTMLImageElement::altText() const
{
    // lets figure out the alt text.. magic stuff
    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
    // also heavily discussed by Hixie on bugzilla
    String alt = getAttribute(altAttr);
    // fall back to title attribute
    if (alt.isNull())
        alt = getAttribute(titleAttr);
    return alt;
}

RenderObject* HTMLImageElement::createRenderer(RenderStyle* style)
{
    if (style->hasContent())
        return RenderObject::createObject(this, style);

    RenderImage* image = new RenderImage(this);
    image->setImageResource(RenderImageResource::create());
    return image;
}

bool HTMLImageElement::canStartSelection() const
{
    if (shadow())
        return HTMLElement::canStartSelection();

    return false;
}

void HTMLImageElement::attach(const AttachContext& context)
{
    HTMLElement::attach(context);

    if (renderer() && renderer()->isImage() && !m_imageLoader.hasPendingBeforeLoadEvent()) {
        RenderImage* renderImage = toRenderImage(renderer());
        RenderImageResource* renderImageResource = renderImage->imageResource();
        if (renderImageResource->hasImage())
            return;
        renderImageResource->setCachedImage(m_imageLoader.image());

        // If we have no image at all because we have no src attribute, set
        // image height and width for the alt text instead.
        if (!m_imageLoader.image() && !renderImageResource->cachedImage())
            renderImage->setImageSizeForAltText();
    }
}

Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
{
    // m_form can be non-null if it was set in constructor.
    if (!m_form) {
        m_form = findFormAncestor();
        if (m_form)
            m_form->registerImgElement(this);
    }

    // If we have been inserted from a renderer-less document,
    // our loader may have not fetched the image, so do it now.
    if (insertionPoint->inDocument() && !m_imageLoader.image())
        m_imageLoader.updateFromElement();

    return HTMLElement::insertedInto(insertionPoint);
}

void HTMLImageElement::removedFrom(ContainerNode* insertionPoint)
{
    if (m_form)
        m_form->removeImgElement(this);
    m_form = 0;
    HTMLElement::removedFrom(insertionPoint);
}

int HTMLImageElement::width(bool ignorePendingStylesheets)
{
    if (!renderer()) {
        // check the attribute first for an explicit pixel value
        bool ok;
        int width = getAttribute(widthAttr).toInt(&ok);
        if (ok)
            return width;

        // if the image is available, use its width
        if (m_imageLoader.image())
            return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).width();
    }

    if (ignorePendingStylesheets)
        document()->updateLayoutIgnorePendingStylesheets();
    else
        document()->updateLayout();

    RenderBox* box = renderBox();
    return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedWidth(), box) : 0;
}

int HTMLImageElement::height(bool ignorePendingStylesheets)
{
    if (!renderer()) {
        // check the attribute first for an explicit pixel value
        bool ok;
        int height = getAttribute(heightAttr).toInt(&ok);
        if (ok)
            return height;

        // if the image is available, use its height
        if (m_imageLoader.image())
            return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).height();
    }

    if (ignorePendingStylesheets)
        document()->updateLayoutIgnorePendingStylesheets();
    else
        document()->updateLayout();

    RenderBox* box = renderBox();
    return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedHeight(), box) : 0;
}

int HTMLImageElement::naturalWidth() const
{
    if (!m_imageLoader.image())
        return 0;

    return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).width();
}

int HTMLImageElement::naturalHeight() const
{
    if (!m_imageLoader.image())
        return 0;

    return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).height();
}

bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const
{
    return attribute.name() == srcAttr
        || attribute.name() == lowsrcAttr
        || attribute.name() == longdescAttr
        || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#')
        || HTMLElement::isURLAttribute(attribute);
}

const AtomicString& HTMLImageElement::alt() const
{
    return getAttribute(altAttr);
}

bool HTMLImageElement::draggable() const
{
    // Image elements are draggable by default.
    return !equalIgnoringCase(getAttribute(draggableAttr), "false");
}

void HTMLImageElement::setHeight(int value)
{
    setAttribute(heightAttr, String::number(value));
}

KURL HTMLImageElement::src() const
{
    return document()->completeURL(getAttribute(srcAttr));
}

void HTMLImageElement::setSrc(const String& value)
{
    setAttribute(srcAttr, value);
}

void HTMLImageElement::setWidth(int value)
{
    setAttribute(widthAttr, String::number(value));
}

int HTMLImageElement::x() const
{
    RenderObject* r = renderer();
    if (!r)
        return 0;

    // FIXME: This doesn't work correctly with transforms.
    FloatPoint absPos = r->localToAbsolute();
    return absPos.x();
}

int HTMLImageElement::y() const
{
    RenderObject* r = renderer();
    if (!r)
        return 0;

    // FIXME: This doesn't work correctly with transforms.
    FloatPoint absPos = r->localToAbsolute();
    return absPos.y();
}

bool HTMLImageElement::complete() const
{
    return m_imageLoader.imageComplete();
}

void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
{
    HTMLElement::addSubresourceAttributeURLs(urls);

    addSubresourceURL(urls, src());
    // FIXME: What about when the usemap attribute begins with "#"?
    addSubresourceURL(urls, document()->completeURL(getAttribute(usemapAttr)));
}

void HTMLImageElement::didMoveToNewDocument(Document* oldDocument)
{
    m_imageLoader.elementDidMoveToNewDocument();
    HTMLElement::didMoveToNewDocument(oldDocument);
}

bool HTMLImageElement::isServerMap() const
{
    if (!fastHasAttribute(ismapAttr))
        return false;

    const AtomicString& usemap = fastGetAttribute(usemapAttr);

    // If the usemap attribute starts with '#', it refers to a map element in the document.
    if (usemap.string()[0] == '#')
        return false;

    return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(usemap)).isEmpty();
}

Image* HTMLImageElement::imageContents()
{
    if (!m_imageLoader.imageComplete())
        return 0;

    return m_imageLoader.image()->image();
}

}
<commit_msg>Refactor code for <img> size calculation during attach<commit_after>/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * 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 "config.h"
#include "core/html/HTMLImageElement.h"

#include "CSSPropertyNames.h"
#include "HTMLNames.h"
#include "bindings/v8/ScriptEventListener.h"
#include "core/dom/Attribute.h"
#include "core/dom/EventNames.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/loader/cache/CachedImage.h"
#include "core/rendering/RenderImage.h"

using namespace std;

namespace WebCore {

using namespace HTMLNames;

HTMLImageElement::HTMLImageElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
    : HTMLElement(tagName, document)
    , m_imageLoader(this)
    , m_form(form)
    , m_compositeOperator(CompositeSourceOver)
{
    ASSERT(hasTagName(imgTag));
    ScriptWrappable::init(this);
    if (form)
        form->registerImgElement(this);
}

PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document* document)
{
    return adoptRef(new HTMLImageElement(imgTag, document));
}

PassRefPtr<HTMLImageElement> HTMLImageElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
{
    return adoptRef(new HTMLImageElement(tagName, document, form));
}

HTMLImageElement::~HTMLImageElement()
{
    if (m_form)
        m_form->removeImgElement(this);
}

PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document* document, const int* optionalWidth, const int* optionalHeight)
{
    RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(imgTag, document));
    if (optionalWidth)
        image->setWidth(*optionalWidth);
    if (optionalHeight)
        image->setHeight(*optionalHeight);
    return image.release();
}

bool HTMLImageElement::isPresentationAttribute(const QualifiedName& name) const
{
    if (name == widthAttr || name == heightAttr || name == borderAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == valignAttr)
        return true;
    return HTMLElement::isPresentationAttribute(name);
}

void HTMLImageElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
{
    if (name == widthAttr)
        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    else if (name == heightAttr)
        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    else if (name == borderAttr)
        applyBorderAttributeToStyle(value, style);
    else if (name == vspaceAttr) {
        addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
        addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
    } else if (name == hspaceAttr) {
        addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
        addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
    } else if (name == alignAttr)
        applyAlignmentAttributeToStyle(value, style);
    else if (name == valignAttr)
        addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
    else
        HTMLElement::collectStyleForPresentationAttribute(name, value, style);
}

void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
    if (name == altAttr) {
        if (renderer() && renderer()->isImage())
            toRenderImage(renderer())->updateAltText();
    } else if (name == srcAttr)
        m_imageLoader.updateFromElementIgnoringPreviousError();
    else if (name == usemapAttr)
        setIsLink(!value.isNull());
    else if (name == onbeforeloadAttr)
        setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, name, value));
    else if (name == compositeAttr) {
        // FIXME: images don't support blend modes in their compositing attribute.
        BlendMode blendOp = BlendModeNormal;
        if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp))
            m_compositeOperator = CompositeSourceOver;
    } else
        HTMLElement::parseAttribute(name, value);
}

String HTMLImageElement::altText() const
{
    // lets figure out the alt text.. magic stuff
    // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
    // also heavily discussed by Hixie on bugzilla
    String alt = getAttribute(altAttr);
    // fall back to title attribute
    if (alt.isNull())
        alt = getAttribute(titleAttr);
    return alt;
}

RenderObject* HTMLImageElement::createRenderer(RenderStyle* style)
{
    if (style->hasContent())
        return RenderObject::createObject(this, style);

    RenderImage* image = new RenderImage(this);
    image->setImageResource(RenderImageResource::create());
    return image;
}

bool HTMLImageElement::canStartSelection() const
{
    if (shadow())
        return HTMLElement::canStartSelection();

    return false;
}

void HTMLImageElement::attach(const AttachContext& context)
{
    HTMLElement::attach(context);

    if (renderer() && renderer()->isImage() && !m_imageLoader.hasPendingBeforeLoadEvent()) {
        RenderImage* renderImage = toRenderImage(renderer());
        RenderImageResource* renderImageResource = renderImage->imageResource();
        if (renderImageResource->hasImage())
            return;

        // If we have no image at all because we have no src attribute, set
        // image height and width for the alt text instead.
        if (!m_imageLoader.image() && !renderImageResource->cachedImage())
            renderImage->setImageSizeForAltText();
        else
            renderImageResource->setCachedImage(m_imageLoader.image());

    }
}

Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
{
    // m_form can be non-null if it was set in constructor.
    if (!m_form) {
        m_form = findFormAncestor();
        if (m_form)
            m_form->registerImgElement(this);
    }

    // If we have been inserted from a renderer-less document,
    // our loader may have not fetched the image, so do it now.
    if (insertionPoint->inDocument() && !m_imageLoader.image())
        m_imageLoader.updateFromElement();

    return HTMLElement::insertedInto(insertionPoint);
}

void HTMLImageElement::removedFrom(ContainerNode* insertionPoint)
{
    if (m_form)
        m_form->removeImgElement(this);
    m_form = 0;
    HTMLElement::removedFrom(insertionPoint);
}

int HTMLImageElement::width(bool ignorePendingStylesheets)
{
    if (!renderer()) {
        // check the attribute first for an explicit pixel value
        bool ok;
        int width = getAttribute(widthAttr).toInt(&ok);
        if (ok)
            return width;

        // if the image is available, use its width
        if (m_imageLoader.image())
            return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).width();
    }

    if (ignorePendingStylesheets)
        document()->updateLayoutIgnorePendingStylesheets();
    else
        document()->updateLayout();

    RenderBox* box = renderBox();
    return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedWidth(), box) : 0;
}

int HTMLImageElement::height(bool ignorePendingStylesheets)
{
    if (!renderer()) {
        // check the attribute first for an explicit pixel value
        bool ok;
        int height = getAttribute(heightAttr).toInt(&ok);
        if (ok)
            return height;

        // if the image is available, use its height
        if (m_imageLoader.image())
            return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).height();
    }

    if (ignorePendingStylesheets)
        document()->updateLayoutIgnorePendingStylesheets();
    else
        document()->updateLayout();

    RenderBox* box = renderBox();
    return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedHeight(), box) : 0;
}

int HTMLImageElement::naturalWidth() const
{
    if (!m_imageLoader.image())
        return 0;

    return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).width();
}

int HTMLImageElement::naturalHeight() const
{
    if (!m_imageLoader.image())
        return 0;

    return m_imageLoader.image()->imageSizeForRenderer(renderer(), 1.0f).height();
}

bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const
{
    return attribute.name() == srcAttr
        || attribute.name() == lowsrcAttr
        || attribute.name() == longdescAttr
        || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#')
        || HTMLElement::isURLAttribute(attribute);
}

const AtomicString& HTMLImageElement::alt() const
{
    return getAttribute(altAttr);
}

bool HTMLImageElement::draggable() const
{
    // Image elements are draggable by default.
    return !equalIgnoringCase(getAttribute(draggableAttr), "false");
}

void HTMLImageElement::setHeight(int value)
{
    setAttribute(heightAttr, String::number(value));
}

KURL HTMLImageElement::src() const
{
    return document()->completeURL(getAttribute(srcAttr));
}

void HTMLImageElement::setSrc(const String& value)
{
    setAttribute(srcAttr, value);
}

void HTMLImageElement::setWidth(int value)
{
    setAttribute(widthAttr, String::number(value));
}

int HTMLImageElement::x() const
{
    RenderObject* r = renderer();
    if (!r)
        return 0;

    // FIXME: This doesn't work correctly with transforms.
    FloatPoint absPos = r->localToAbsolute();
    return absPos.x();
}

int HTMLImageElement::y() const
{
    RenderObject* r = renderer();
    if (!r)
        return 0;

    // FIXME: This doesn't work correctly with transforms.
    FloatPoint absPos = r->localToAbsolute();
    return absPos.y();
}

bool HTMLImageElement::complete() const
{
    return m_imageLoader.imageComplete();
}

void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
{
    HTMLElement::addSubresourceAttributeURLs(urls);

    addSubresourceURL(urls, src());
    // FIXME: What about when the usemap attribute begins with "#"?
    addSubresourceURL(urls, document()->completeURL(getAttribute(usemapAttr)));
}

void HTMLImageElement::didMoveToNewDocument(Document* oldDocument)
{
    m_imageLoader.elementDidMoveToNewDocument();
    HTMLElement::didMoveToNewDocument(oldDocument);
}

bool HTMLImageElement::isServerMap() const
{
    if (!fastHasAttribute(ismapAttr))
        return false;

    const AtomicString& usemap = fastGetAttribute(usemapAttr);

    // If the usemap attribute starts with '#', it refers to a map element in the document.
    if (usemap.string()[0] == '#')
        return false;

    return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(usemap)).isEmpty();
}

Image* HTMLImageElement::imageContents()
{
    if (!m_imageLoader.imageComplete())
        return 0;

    return m_imageLoader.image()->image();
}

}
<|endoftext|>


<commit_before>/*Santiago Zubieta*/
#include <iostream>
#include <numeric>
#include <fstream>
#include <climits>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <deque>
#include <vector>
#include <string>
#include <cstdlib>
#include <cassert>
#include <sstream>
#include <iterator>
#include <algorithm>

using namespace std;

vector< vector<int> > graph;

int main() {
	int N, M;
	int numCase = 1;
	while(cin >> N >> M) {
		if(!N && !M) {
		// Input terminates with 0 0
			break;
		}
		graph.clear();
		for(int k = 0; k <= N; k++) {
		// We'll have a graph, which will be a list of list of integers. Each
		// list will have the numbers each position goes to, including itself.
			vector<int> v;
			graph.push_back(v);
		}
		for(int k = 1; k <= M; k++) {
		// Read the graph, define bidirectional relations, as in, p1 and p2 are
		// a couple persons that belong to the same religion.
			int p1, p2;
			cin >> p1 >> p2;
			graph[p1].push_back(p2);
			graph[p2].push_back(p1);
		}
		for(int k = 0; k <= N; k++) {
		// Then, we'll mark each number as having its own religion
			graph[k].push_back(k);
		}
		int religions = 0;
		for(int i = 1; i <= N; i++) {
		// At each i (each person), the list of relations that person has is
		// also the list of persons belonging to its same religion. So, all the
		// persons found in this list will be 'cleared', since we don't have
		// to re-check for this same religion. A person that hasn't been cle-
		// ared this far belongs to a yet un-checked religion. If we didn't add
		// a person to its own list of religions, the size of that person's own
		// list would be 0, which would coincide with an already cleared person
		// and we want this person whom we don't know anything about to count
		// as its own possible religion, for finding the upper bounding limit.
			if(graph[i].size() > 0) {
				religions++;
			}
			else {
				continue;
			}
			queue<int> q;
			q.push(i);
			// We'll clear the lists of the persons related to the current per-
			// son, and also the lists of the persons related to those persons,
			// and so on, until all people from a same religion is cleared so
			// we don't check them anymore in the future.
			while(q.size() > 0) {
				int p1 = q.front();
				q.pop();
				for(int j = 0; j < graph[p1].size(); j++) {
					int p2 = graph[p1][j];
					q.push(p2);
				}
				graph[p1].clear();
			}
		}
		cout << "Case " << numCase << ": " << religions << endl;
		numCase++;
	}
}<commit_msg>Added first batch of problems from Summer Training, 2014<commit_after>/*Santiago Zubieta*/
#include <iostream>
#include <numeric>
#include <fstream>
#include <climits>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <deque>
#include <vector>
#include <string>
#include <cstdlib>
#include <cassert>
#include <sstream>
#include <iterator>
#include <algorithm>

using namespace std;

vector< vector<int> > graph;

int main() {
    int N, M;
    int numCase = 1;
    while(cin >> N >> M) {
        if(!N && !M) {
        // Input terminates with 0 0
            break;
        }
        graph.clear();
        for(int k = 0; k <= N; k++) {
        // We'll have a graph, which will be a list of list of integers. Each
        // list will have the numbers each position goes to, including itself.
            vector<int> v;
            graph.push_back(v);
        }
        for(int k = 1; k <= M; k++) {
        // Read the graph, define bidirectional relations, as in, p1 and p2 are
        // a couple persons that belong to the same religion.
            int p1, p2;
            cin >> p1 >> p2;
            graph[p1].push_back(p2);
            graph[p2].push_back(p1);
        }
        for(int k = 0; k <= N; k++) {
        // Then, we'll mark each number as having its own religion
            graph[k].push_back(k);
        }
        int religions = 0;
        for(int i = 1; i <= N; i++) {
        // At each i (each person), the list of relations that person has is
        // also the list of persons belonging to its same religion. So, all the
        // persons found in this list will be 'cleared', since we don't have
        // to re-check for this same religion. A person that hasn't been cle-
        // ared this far belongs to a yet un-checked religion. If we didn't add
        // a person to its own list of religions, the size of that person's own
        // list would be 0, which would coincide with an already cleared person
        // and we want this person whom we don't know anything about to count
        // as its own possible religion, for finding the upper bounding limit.
            if(graph[i].size() > 0) {
                religions++;
            }
            else {
                continue;
            }
            queue<int> q;
            q.push(i);
            // We'll clear the lists of the persons related to the current per-
            // son, and also the lists of the persons related to those persons,
            // and so on, until all people from a same religion is cleared so
            // we don't check them anymore in the future.
            while(q.size() > 0) {
                int p1 = q.front();
                q.pop();
                for(int j = 0; j < graph[p1].size(); j++) {
                    int p2 = graph[p1][j];
                    q.push(p2);
                }
                graph[p1].clear();
            }
        }
        cout << "Case " << numCase << ": " << religions << endl;
        numCase++;
    }
}<|endoftext|>