<commit_before>/************************************************************************
	filename: 	CEGUIScheme.cpp
	created:	21/2/2004
	author:		Paul D Turner

	purpose:	Implements GUI Scheme class
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://crayzedsgui.sourceforge.net)
    Copyright (C)2004 Paul D Turner (crayzed@users.sourceforge.net)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIScheme.h"
#include "CEGUIExceptions.h"
#include "CEGUISchemeManager.h"
#include "CEGUILogger.h"
#include "CEGUIImagesetManager.h"
#include "CEGUIImageset.h"
#include "CEGUIFontManager.h"
#include "CEGUIFont.h"
#include "CEGUIWindowFactoryManager.h"
#include "CEGUIFactoryModule.h"

#include "xercesc/sax2/SAX2XMLReader.hpp"
#include "xercesc/sax2/XMLReaderFactory.hpp"

// Start of CEGUI namespace section
namespace CEGUI
{

/*************************************************************************
	Static Data definitions
*************************************************************************/
// name of the xml schema for GUIScheme files
const char Scheme::GUISchemeSchemaName[]					= "GUIScheme.xsd";

// xml file elements and attributes
const char	Scheme::xmlHandler::GUISchemeElement[]			= "GUIScheme";
const char	Scheme::xmlHandler::ImagesetElement[]			= "Imageset";
const char	Scheme::xmlHandler::FontElement[]				= "Font";
const char	Scheme::xmlHandler::WindowSetElement[]			= "WindowSet";
const char	Scheme::xmlHandler::WindowFactoryElement[]		= "WindowFactory";
const char	Scheme::xmlHandler::NameAttribute[]				= "Name";
const char	Scheme::xmlHandler::FilenameAttribute[]			= "Filename";

/*************************************************************************
	Constructor for scheme objects
*************************************************************************/
Scheme::Scheme(const String& filename)
{
	XERCES_CPP_NAMESPACE_USE

	if (filename.empty() || (filename == (utf8*)""))
	{
		throw InvalidRequestException((utf8*)"Scheme::Scheme - Filename supplied for Scheme loading must be valid");
	}

	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();

	// set basic settings we want from parser
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
	parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
	parser->setFeature(XMLUni::fgXercesSchema, true);
	parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);

	// setup schema for Scheme data
	XMLCh* pval = XMLString::transcode(GUISchemeSchemaName);
	ArrayJanitor<XMLCh>	arrayJanitor(pval);
	parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);

	// setup handler object
	xmlHandler handler(this);
	parser->setContentHandler(&handler);
	parser->setErrorHandler(&handler);

	// do parse (which uses handler to create actual data)
	try
	{
		parser->parse(filename.c_str());
	}
	catch(const XMLException& exc)
	{
		if (exc.getCode() != XMLExcepts::NoError)
		{
			delete parser;

			ArrayJanitor<char> excmsg(XMLString::transcode(exc.getMessage()));
			String message((utf8*)"Scheme::Scheme - An error occurred while parsing Scheme file '" + filename + "'.  Additional information: ");
			message += excmsg.get();

			throw FileIOException(message);
		}

	}
	catch(const SAXParseException& exc)
	{
		delete parser;

		ArrayJanitor<char> excmsg(XMLString::transcode(exc.getMessage()));
		String message((utf8*)"Scheme::Scheme - An error occurred while parsing Scheme file '" + filename + "'.  Additional information: ");
		message += excmsg.get();

		throw FileIOException(message);
	}
	catch(...)
	{
		delete parser;

		throw FileIOException((utf8*)"Scheme::Scheme - An unexpected error occurred while parsing Scheme file '" + filename + "'.");
	}

	// cleanup
	delete parser;

	Logger::getSingleton().logEvent((utf8*)"Loaded GUI scheme '" + d_name + "' from data in file '" + filename + "'.", Informative);

	// attempt to load in resources
	loadResources();
}

/*************************************************************************
	Destructor for scheme objects
*************************************************************************/
Scheme::~Scheme(void)
{
	unloadResources();

	Logger::getSingleton().logEvent((utf8*)"GUI scheme '" + d_name + "' has been unloaded.", Informative);
}

/*************************************************************************
	Load all resources for this scheme
*************************************************************************/
void Scheme::loadResources(void)
{
	Logger::getSingleton().logEvent((utf8*)"---- Begining resource loading for GUI scheme '" + d_name + "' ----", Informative);

	ImagesetManager& ismgr		= ImagesetManager::getSingleton();
	FontManager& fntmgr			= FontManager::getSingleton();
	WindowFactoryManager& wfmgr = WindowFactoryManager::getSingleton();

	std::vector<LoadableUIElement>::const_iterator	pos;

	// check imagesets
	for (pos = d_imagesets.begin(); pos != d_imagesets.end(); ++pos)
	{
		if (!ismgr.isImagesetPresent((*pos).name))
		{
			Imageset* iset = ismgr.createImageset((*pos).filename);

			// check for wrong imageset for specified name
			String realname = iset->getName();

			if (realname != (*pos).name)
			{
				ismgr.destroyImageset(iset);
				throw InvalidRequestException((utf8*)"Scheme::loadResources - The Imageset created by file '" +
					(*pos).filename + "' is named '" + realname + "', not '" + (*pos).name + "' as required by Scheme '" + d_name + "'.");
			}

		}

	}

	// check fonts
	for (pos = d_fonts.begin(); pos != d_fonts.end(); ++pos)
	{
		if (!fntmgr.isFontPresent((*pos).name))
		{
			Font* font = fntmgr.createFont((*pos).filename);

			// check for wrong font for specified name
			String realname = font->getName();

			if (realname != (*pos).name)
			{
				fntmgr.destroyFont(font);
				throw InvalidRequestException((utf8*)"Scheme::loadResources - The Font created by file '" +
					(*pos).filename + "' is named '" + realname + "', not '" + (*pos).name + "' as required by Scheme '" + d_name + "'.");
			}

		}

	}

	// check factories
	std::vector<UIModule>::iterator	cmod = d_widgetModules.begin();
	for (;cmod != d_widgetModules.end(); ++cmod)
	{
		// create and load dynamic module as required
		if ((*cmod).module == NULL)
		{
			(*cmod).module = new FactoryModule((*cmod).name);
		}

		std::vector<UIElementFactory>::const_iterator	elem = (*cmod).factories.begin();
		for (; elem != (*cmod).factories.end(); ++elem)
		{
			if (!wfmgr.isFactoryPresent((*elem).name))
			{
				(*cmod).module->registerFactory((*elem).name);
			}

		}

	}

	Logger::getSingleton().logEvent((utf8*)"---- Resource loading for GUI scheme '" + d_name + "' completed ----", Informative);
}

/*************************************************************************
	Unload all resources for this scheme
*************************************************************************/
void Scheme::unloadResources(void)
{
	Logger::getSingleton().logEvent((utf8*)"---- Begining resource cleanup for GUI scheme '" + d_name + "' ----", Informative);

	ImagesetManager& ismgr		= ImagesetManager::getSingleton();
	FontManager& fntmgr			= FontManager::getSingleton();
	WindowFactoryManager& wfmgr = WindowFactoryManager::getSingleton();

	std::vector<LoadableUIElement>::const_iterator	pos;

	// check Imagesets
	for (pos = d_imagesets.begin(); pos != d_imagesets.end(); ++pos)
	{
		ismgr.destroyImageset((*pos).name);
	}

	// check fonts
	for (pos = d_fonts.begin(); pos != d_fonts.end(); ++pos)
	{
		fntmgr.destroyFont((*pos).name);
	}

	// check factories
	std::vector<UIModule>::iterator	cmod = d_widgetModules.begin();
	for (;cmod != d_widgetModules.end(); ++cmod)
	{
		std::vector<UIElementFactory>::const_iterator	elem = (*cmod).factories.begin();
		for (; elem != (*cmod).factories.end(); ++elem)
		{
			wfmgr.removeFactory((*elem).name);
		}

		// create and load dynamic module as required
		if ((*cmod).module != NULL)
		{
			delete (*cmod).module;
			(*cmod).module = NULL;
		}

	}

	Logger::getSingleton().logEvent((utf8*)"---- Resource cleanup for GUI scheme '" + d_name + "' completed ----", Informative);
}

/*************************************************************************
	Check if all resources for this Scheme are loaded
*************************************************************************/
bool Scheme::resourcesLoaded(void) const
{
	ImagesetManager& ismgr		= ImagesetManager::getSingleton();
	FontManager& fntmgr			= FontManager::getSingleton();
	WindowFactoryManager& wfmgr = WindowFactoryManager::getSingleton();

	std::vector<LoadableUIElement>::const_iterator	pos;

	// check imagesets
	for (pos = d_imagesets.begin(); pos != d_imagesets.end(); ++pos)
	{
		if (!ismgr.isImagesetPresent((*pos).name))
		{
			return false;
		}

	}

	// check fonts
	for (pos = d_fonts.begin(); pos != d_fonts.end(); ++pos)
	{
		if (!fntmgr.isFontPresent((*pos).name))
		{
			return false;
		}

	}

	// check factories
	std::vector<UIModule>::const_iterator	cmod = d_widgetModules.begin();
	for (;cmod != d_widgetModules.end(); ++cmod)
	{
		std::vector<UIElementFactory>::const_iterator	elem = (*cmod).factories.begin();

		for (; elem != (*cmod).factories.end(); ++elem)
		{
			if (!wfmgr.isFactoryPresent((*elem).name))
			{
				return false;
			}

		}

	}

	return true;
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

/*************************************************************************
	SAX2 Handler methods
*************************************************************************/
void Scheme::xmlHandler::startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const XERCES_CPP_NAMESPACE::Attributes& attrs)
{
	XERCES_CPP_NAMESPACE_USE
	std::string element(XMLString::transcode(localname));

	UIModule	module;

	// handle an Imageset element
	if (element == ImagesetElement)
	{
		LoadableUIElement	imageset;

		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		imageset.name = (utf8*)val_str.get();

		attr_name.reset(XMLString::transcode(FilenameAttribute));
		val_str.reset(XMLString::transcode(attrs.getValue(attr_name.get())));
		imageset.filename = (utf8*)val_str.get();

		d_scheme->d_imagesets.push_back(imageset);
	}
	// handle a font element
	else if (element == FontElement)
	{
		LoadableUIElement	font;

		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		font.name = (utf8*)val_str.get();

		attr_name.reset(XMLString::transcode(FilenameAttribute));
		val_str.reset(XMLString::transcode(attrs.getValue(attr_name.get())));
		font.filename = (utf8*)val_str.get();

		d_scheme->d_fonts.push_back(font);
	}
	// handle a WindowSet element
	else if (element == WindowSetElement)
	{
		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(FilenameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		module.name		= (utf8*)val_str.get();
		module.module	= NULL;

		module.factories.clear();
		d_scheme->d_widgetModules.push_back(module);
	}
	// handle a WindowFactory element
	else if (element == WindowFactoryElement)
	{
		UIElementFactory factory;

		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		factory.name = (utf8*)val_str.get();

        module.factories.push_back(factory);
	}
	// handle root Scheme element
	else if (element == GUISchemeElement)
	{
		// get name of scheme we are creating
		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		d_scheme->d_name = (utf8*)val_str.get();

		if (SchemeManager::getSingleton().isSchemePresent(d_scheme->d_name))
		{
			throw	AlreadyExistsException((utf8*)"A GUI Scheme named '" + d_scheme->d_name + "' is already present in the system.");
		}

	}
	// anything else is an error which *should* have already been caught by XML validation
	else
	{
		throw FileIOException("Scheme::xmlHandler::startElement - Unexpected data was found while parsing the Scheme file: '" + element + "' is unknown.");
	}

}

void Scheme::xmlHandler::warning(const XERCES_CPP_NAMESPACE::SAXParseException &exc)
{
	throw(exc);
}

void Scheme::xmlHandler::error(const XERCES_CPP_NAMESPACE::SAXParseException &exc)
{
	throw(exc);
}

void Scheme::xmlHandler::fatalError(const XERCES_CPP_NAMESPACE::SAXParseException &exc)
{
	throw(exc);
}

} // End of  CEGUI namespace section
<commit_msg>Fixed bug: WindowFactory elements read from scheme files were not properly added to the Scheme's data (they were instead added to a local variable and lost).<commit_after>/************************************************************************
	filename: 	CEGUIScheme.cpp
	created:	21/2/2004
	author:		Paul D Turner

	purpose:	Implements GUI Scheme class
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://crayzedsgui.sourceforge.net)
    Copyright (C)2004 Paul D Turner (crayzed@users.sourceforge.net)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIScheme.h"
#include "CEGUIExceptions.h"
#include "CEGUISchemeManager.h"
#include "CEGUILogger.h"
#include "CEGUIImagesetManager.h"
#include "CEGUIImageset.h"
#include "CEGUIFontManager.h"
#include "CEGUIFont.h"
#include "CEGUIWindowFactoryManager.h"
#include "CEGUIFactoryModule.h"

#include "xercesc/sax2/SAX2XMLReader.hpp"
#include "xercesc/sax2/XMLReaderFactory.hpp"

// Start of CEGUI namespace section
namespace CEGUI
{

/*************************************************************************
	Static Data definitions
*************************************************************************/
// name of the xml schema for GUIScheme files
const char Scheme::GUISchemeSchemaName[]					= "GUIScheme.xsd";

// xml file elements and attributes
const char	Scheme::xmlHandler::GUISchemeElement[]			= "GUIScheme";
const char	Scheme::xmlHandler::ImagesetElement[]			= "Imageset";
const char	Scheme::xmlHandler::FontElement[]				= "Font";
const char	Scheme::xmlHandler::WindowSetElement[]			= "WindowSet";
const char	Scheme::xmlHandler::WindowFactoryElement[]		= "WindowFactory";
const char	Scheme::xmlHandler::NameAttribute[]				= "Name";
const char	Scheme::xmlHandler::FilenameAttribute[]			= "Filename";

/*************************************************************************
	Constructor for scheme objects
*************************************************************************/
Scheme::Scheme(const String& filename)
{
	XERCES_CPP_NAMESPACE_USE

	if (filename.empty() || (filename == (utf8*)""))
	{
		throw InvalidRequestException((utf8*)"Scheme::Scheme - Filename supplied for Scheme loading must be valid");
	}

	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();

	// set basic settings we want from parser
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
	parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
	parser->setFeature(XMLUni::fgXercesSchema, true);
	parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);

	// setup schema for Scheme data
	XMLCh* pval = XMLString::transcode(GUISchemeSchemaName);
	ArrayJanitor<XMLCh>	arrayJanitor(pval);
	parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);

	// setup handler object
	xmlHandler handler(this);
	parser->setContentHandler(&handler);
	parser->setErrorHandler(&handler);

	// do parse (which uses handler to create actual data)
	try
	{
		parser->parse(filename.c_str());
	}
	catch(const XMLException& exc)
	{
		if (exc.getCode() != XMLExcepts::NoError)
		{
			delete parser;

			ArrayJanitor<char> excmsg(XMLString::transcode(exc.getMessage()));
			String message((utf8*)"Scheme::Scheme - An error occurred while parsing Scheme file '" + filename + "'.  Additional information: ");
			message += excmsg.get();

			throw FileIOException(message);
		}

	}
	catch(const SAXParseException& exc)
	{
		delete parser;

		ArrayJanitor<char> excmsg(XMLString::transcode(exc.getMessage()));
		String message((utf8*)"Scheme::Scheme - An error occurred while parsing Scheme file '" + filename + "'.  Additional information: ");
		message += excmsg.get();

		throw FileIOException(message);
	}
	catch(...)
	{
		delete parser;

		throw FileIOException((utf8*)"Scheme::Scheme - An unexpected error occurred while parsing Scheme file '" + filename + "'.");
	}

	// cleanup
	delete parser;

	Logger::getSingleton().logEvent((utf8*)"Loaded GUI scheme '" + d_name + "' from data in file '" + filename + "'.", Informative);

	// attempt to load in resources
	loadResources();
}

/*************************************************************************
	Destructor for scheme objects
*************************************************************************/
Scheme::~Scheme(void)
{
	unloadResources();

	Logger::getSingleton().logEvent((utf8*)"GUI scheme '" + d_name + "' has been unloaded.", Informative);
}

/*************************************************************************
	Load all resources for this scheme
*************************************************************************/
void Scheme::loadResources(void)
{
	Logger::getSingleton().logEvent((utf8*)"---- Begining resource loading for GUI scheme '" + d_name + "' ----", Informative);

	ImagesetManager& ismgr		= ImagesetManager::getSingleton();
	FontManager& fntmgr			= FontManager::getSingleton();
	WindowFactoryManager& wfmgr = WindowFactoryManager::getSingleton();

	std::vector<LoadableUIElement>::const_iterator	pos;

	// check imagesets
	for (pos = d_imagesets.begin(); pos != d_imagesets.end(); ++pos)
	{
		if (!ismgr.isImagesetPresent((*pos).name))
		{
			Imageset* iset = ismgr.createImageset((*pos).filename);

			// check for wrong imageset for specified name
			String realname = iset->getName();

			if (realname != (*pos).name)
			{
				ismgr.destroyImageset(iset);
				throw InvalidRequestException((utf8*)"Scheme::loadResources - The Imageset created by file '" +
					(*pos).filename + "' is named '" + realname + "', not '" + (*pos).name + "' as required by Scheme '" + d_name + "'.");
			}

		}

	}

	// check fonts
	for (pos = d_fonts.begin(); pos != d_fonts.end(); ++pos)
	{
		if (!fntmgr.isFontPresent((*pos).name))
		{
			Font* font = fntmgr.createFont((*pos).filename);

			// check for wrong font for specified name
			String realname = font->getName();

			if (realname != (*pos).name)
			{
				fntmgr.destroyFont(font);
				throw InvalidRequestException((utf8*)"Scheme::loadResources - The Font created by file '" +
					(*pos).filename + "' is named '" + realname + "', not '" + (*pos).name + "' as required by Scheme '" + d_name + "'.");
			}

		}

	}

	// check factories
	std::vector<UIModule>::iterator	cmod = d_widgetModules.begin();
	for (;cmod != d_widgetModules.end(); ++cmod)
	{
		// create and load dynamic module as required
		if ((*cmod).module == NULL)
		{
			(*cmod).module = new FactoryModule((*cmod).name);
		}

		std::vector<UIElementFactory>::const_iterator	elem = (*cmod).factories.begin();
		for (; elem != (*cmod).factories.end(); ++elem)
		{
			if (!wfmgr.isFactoryPresent((*elem).name))
			{
				(*cmod).module->registerFactory((*elem).name);
			}

		}

	}

	Logger::getSingleton().logEvent((utf8*)"---- Resource loading for GUI scheme '" + d_name + "' completed ----", Informative);
}

/*************************************************************************
	Unload all resources for this scheme
*************************************************************************/
void Scheme::unloadResources(void)
{
	Logger::getSingleton().logEvent((utf8*)"---- Begining resource cleanup for GUI scheme '" + d_name + "' ----", Informative);

	ImagesetManager& ismgr		= ImagesetManager::getSingleton();
	FontManager& fntmgr			= FontManager::getSingleton();
	WindowFactoryManager& wfmgr = WindowFactoryManager::getSingleton();

	std::vector<LoadableUIElement>::const_iterator	pos;

	// check Imagesets
	for (pos = d_imagesets.begin(); pos != d_imagesets.end(); ++pos)
	{
		ismgr.destroyImageset((*pos).name);
	}

	// check fonts
	for (pos = d_fonts.begin(); pos != d_fonts.end(); ++pos)
	{
		fntmgr.destroyFont((*pos).name);
	}

	// check factories
	std::vector<UIModule>::iterator	cmod = d_widgetModules.begin();
	for (;cmod != d_widgetModules.end(); ++cmod)
	{
		std::vector<UIElementFactory>::const_iterator	elem = (*cmod).factories.begin();
		for (; elem != (*cmod).factories.end(); ++elem)
		{
			wfmgr.removeFactory((*elem).name);
		}

		// create and load dynamic module as required
		if ((*cmod).module != NULL)
		{
			delete (*cmod).module;
			(*cmod).module = NULL;
		}

	}

	Logger::getSingleton().logEvent((utf8*)"---- Resource cleanup for GUI scheme '" + d_name + "' completed ----", Informative);
}

/*************************************************************************
	Check if all resources for this Scheme are loaded
*************************************************************************/
bool Scheme::resourcesLoaded(void) const
{
	ImagesetManager& ismgr		= ImagesetManager::getSingleton();
	FontManager& fntmgr			= FontManager::getSingleton();
	WindowFactoryManager& wfmgr = WindowFactoryManager::getSingleton();

	std::vector<LoadableUIElement>::const_iterator	pos;

	// check imagesets
	for (pos = d_imagesets.begin(); pos != d_imagesets.end(); ++pos)
	{
		if (!ismgr.isImagesetPresent((*pos).name))
		{
			return false;
		}

	}

	// check fonts
	for (pos = d_fonts.begin(); pos != d_fonts.end(); ++pos)
	{
		if (!fntmgr.isFontPresent((*pos).name))
		{
			return false;
		}

	}

	// check factories
	std::vector<UIModule>::const_iterator	cmod = d_widgetModules.begin();
	for (;cmod != d_widgetModules.end(); ++cmod)
	{
		std::vector<UIElementFactory>::const_iterator	elem = (*cmod).factories.begin();

		for (; elem != (*cmod).factories.end(); ++elem)
		{
			if (!wfmgr.isFactoryPresent((*elem).name))
			{
				return false;
			}

		}

	}

	return true;
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

/*************************************************************************
	SAX2 Handler methods
*************************************************************************/
void Scheme::xmlHandler::startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const XERCES_CPP_NAMESPACE::Attributes& attrs)
{
	XERCES_CPP_NAMESPACE_USE
	std::string element(XMLString::transcode(localname));

	// handle an Imageset element
	if (element == ImagesetElement)
	{
		LoadableUIElement	imageset;

		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		imageset.name = (utf8*)val_str.get();

		attr_name.reset(XMLString::transcode(FilenameAttribute));
		val_str.reset(XMLString::transcode(attrs.getValue(attr_name.get())));
		imageset.filename = (utf8*)val_str.get();

		d_scheme->d_imagesets.push_back(imageset);
	}
	// handle a font element
	else if (element == FontElement)
	{
		LoadableUIElement	font;

		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		font.name = (utf8*)val_str.get();

		attr_name.reset(XMLString::transcode(FilenameAttribute));
		val_str.reset(XMLString::transcode(attrs.getValue(attr_name.get())));
		font.filename = (utf8*)val_str.get();

		d_scheme->d_fonts.push_back(font);
	}
	// handle a WindowSet element
	else if (element == WindowSetElement)
	{
		UIModule	module;
		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(FilenameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		module.name		= (utf8*)val_str.get();
		module.module	= NULL;

		module.factories.clear();
		d_scheme->d_widgetModules.push_back(module);
	}
	// handle a WindowFactory element
	else if (element == WindowFactoryElement)
	{
		UIElementFactory factory;

		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		factory.name = (utf8*)val_str.get();

		d_scheme->d_widgetModules[d_scheme->d_widgetModules.size() - 1].factories.push_back(factory);
	}
	// handle root Scheme element
	else if (element == GUISchemeElement)
	{
		// get name of scheme we are creating
		ArrayJanitor<XMLCh>	attr_name(XMLString::transcode(NameAttribute));
		ArrayJanitor<char>  val_str(XMLString::transcode(attrs.getValue(attr_name.get())));
		d_scheme->d_name = (utf8*)val_str.get();

		if (SchemeManager::getSingleton().isSchemePresent(d_scheme->d_name))
		{
			throw	AlreadyExistsException((utf8*)"A GUI Scheme named '" + d_scheme->d_name + "' is already present in the system.");
		}

	}
	// anything else is an error which *should* have already been caught by XML validation
	else
	{
		throw FileIOException("Scheme::xmlHandler::startElement - Unexpected data was found while parsing the Scheme file: '" + element + "' is unknown.");
	}

}

void Scheme::xmlHandler::warning(const XERCES_CPP_NAMESPACE::SAXParseException &exc)
{
	throw(exc);
}

void Scheme::xmlHandler::error(const XERCES_CPP_NAMESPACE::SAXParseException &exc)
{
	throw(exc);
}

void Scheme::xmlHandler::fatalError(const XERCES_CPP_NAMESPACE::SAXParseException &exc)
{
	throw(exc);
}

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include <silicium/single_directory_watcher.hpp>
#include <silicium/observable/consume.hpp>
#include <silicium/observable/spawn_coroutine.hpp>
#include <silicium/open.hpp>
#include <silicium/steady_clock.hpp>
#include <silicium/sink/file_sink.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <fstream>
#include <chrono>
#if SILICIUM_HAS_SINGLE_DIRECTORY_WATCHER
#	include <boost/filesystem/operations.hpp>
#endif

namespace Si
{
#if SILICIUM_HAS_SINGLE_DIRECTORY_WATCHER
	namespace
	{
		void touch(Si::absolute_path const &name)
		{
			//remove existing file to reset the attributes
			Si::remove_file(name);

			std::ofstream file(name.c_str());
			BOOST_REQUIRE(file);
		}

		void test_single_event(
			Si::absolute_path const &watched_dir,
			std::function<void ()> const &provoke_event,
			std::function<void (file_notification const &)> const &on_event,
			Si::steady_clock_if_available::duration extra_timeout = Si::chrono::seconds(0))
		{
			boost::asio::io_service io;
			single_directory_watcher watcher(io, watched_dir);

			bool got_event = false;
			auto consumer = consume<error_or<file_notification>>([&io, &got_event, &on_event](error_or<file_notification> const &event)
			{
				io.stop();
				on_event(event.get());
				got_event = true;
			});
			watcher.async_get_one(Si::observe_by_ref(consumer));

			provoke_event();

			boost::asio::basic_waitable_timer<Si::steady_clock_if_available> timeout(io);
			timeout.expires_from_now(Si::chrono::seconds(1) + extra_timeout);
			timeout.async_wait([&io](boost::system::error_code ec)
			{
				BOOST_REQUIRE(!ec);
				io.stop();
			});

			io.run();

			BOOST_CHECK(got_event);
		}
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_add_regular)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / Si::relative_path("test.txt");
		Si::remove_file(test_file);

		test_single_event(
			watched_dir,
			std::bind(touch, test_file),
			[&test_file](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::add == event.type);
			BOOST_CHECK(equivalent(test_file.to_boost_path(), event.name.to_boost_path()));
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_add_directory)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test";
		Si::remove_file(test_file);

		test_single_event(
			watched_dir,
			[&test_file]
		{
			boost::filesystem::create_directory(test_file.to_boost_path());
		},
			[&test_file](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::add == event.type);
			BOOST_CHECK(equivalent(test_file.to_boost_path(), event.name.to_boost_path()));
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_remove)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		touch(test_file);

		test_single_event(
			watched_dir,
			[&test_file]
		{
			boost::filesystem::remove(test_file.to_boost_path());
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove == event.type);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_remove_directory)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test";

		boost::filesystem::create_directory(test_file.to_boost_path());

		test_single_event(
			watched_dir,
			[&test_file]
		{
			boost::filesystem::remove(test_file.to_boost_path());
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove == event.type);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

#if SILICIUM_HAS_FILE_SINK
	BOOST_AUTO_TEST_CASE(file_system_watcher_change_on_write)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		boost::filesystem::create_directories(watched_dir.to_boost_path());
		Si::file_handle file = Si::overwrite_file(Si::native_path_string(test_file.c_str())).move_value();

		test_single_event(
			watched_dir,
			[&file]
		{
			Si::file_sink sink(file.handle);
			Si::append(sink, Si::file_sink_element(Si::make_c_str_range("hello\n")));
			Si::append(sink, Si::file_sink_element(Si::flush()));
			//we write to the file without closing it
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(event.type == file_notification_type::change_content || event.type == file_notification_type::change_content_or_metadata);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}
#endif

	BOOST_AUTO_TEST_CASE(file_system_watcher_change_on_close)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		touch(test_file);

		std::ofstream file(test_file.c_str());
		BOOST_REQUIRE(file);
		file << "hello\n";
		file.flush();

		test_single_event(
			watched_dir,
			[&file]
		{
			//The closing of the file is expected to trigger a change event.
			file.close();
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(event.type == file_notification_type::change_content || event.type == file_notification_type::change_content_or_metadata);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_change_metadata)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		touch(test_file);

#ifdef _WIN32
		BOOST_REQUIRE(SetFileAttributesW(test_file.c_str(), FILE_ATTRIBUTE_NORMAL));
#else
		BOOST_REQUIRE(!chmod(test_file.c_str(), 0555));
#endif

		test_single_event(
			watched_dir,
			[&test_file]
		{
#ifdef _WIN32
			BOOST_REQUIRE(SetFileAttributesW(test_file.c_str(), FILE_ATTRIBUTE_TEMPORARY));
#else
			BOOST_REQUIRE(!chmod(test_file.c_str(), 0755));
#endif
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::change_content_or_metadata == event.type || file_notification_type::change_metadata == event.type);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_move_out)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";
		Si::absolute_path const original_name = watched_dir / "test.txt";
		Si::absolute_path const new_name = root_dir / "renamed.txt";

		boost::filesystem::remove_all(new_name.to_boost_path());
		boost::filesystem::remove_all(watched_dir.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());
		touch(original_name);

		test_single_event(
			watched_dir,
			[&original_name, &new_name]
		{
			boost::filesystem::rename(original_name.to_boost_path(), new_name.to_boost_path());
		},
			[&original_name, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove == event.type);
			BOOST_CHECK_EQUAL(original_name, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_move_in)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";
		Si::absolute_path const original_name = root_dir / "test.txt";
		Si::absolute_path const new_name = watched_dir / "renamed.txt";

		boost::filesystem::remove_all(watched_dir.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());
		touch(original_name);

		test_single_event(
			watched_dir,
			[&original_name, &new_name]
		{
			boost::filesystem::rename(original_name.to_boost_path(), new_name.to_boost_path());
		},
			[&new_name, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::add == event.type);
			BOOST_CHECK_EQUAL(new_name, watched_dir / event.name);
		});
	}

#ifndef _WIN32
	//we cannot yet detect the renaming of the watched directory
	BOOST_AUTO_TEST_CASE(file_system_watcher_rename_watched_dir)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";
		Si::absolute_path const new_name = root_dir / "renamed";

		boost::filesystem::remove_all(watched_dir.to_boost_path());
		boost::filesystem::remove_all(new_name.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());

		test_single_event(
			watched_dir,
			[&watched_dir, &new_name]
		{
			boost::filesystem::rename(watched_dir.to_boost_path(), new_name.to_boost_path());
		},
			[&watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::move_self == event.type);
			BOOST_CHECK_EQUAL("", event.name.underlying());
		},
			//travis needs more time here
			Si::chrono::seconds(10)
		);
	}
#endif

#ifndef _WIN32
	//we cannot yet detect the removal of the watched directory
	BOOST_AUTO_TEST_CASE(file_system_watcher_remove_watched_dir)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";

		boost::filesystem::remove_all(watched_dir.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());

		test_single_event(
			watched_dir,
			[&watched_dir]
		{
			boost::filesystem::remove(watched_dir.to_boost_path());
		},
			[&watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove_self == event.type);
			BOOST_CHECK_EQUAL("", event.name.underlying());
		});
	}
#endif

#if SILICIUM_HAS_SPAWN_COROUTINE
	BOOST_AUTO_TEST_CASE(file_system_watcher_rename_in_dir)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file_a = watched_dir / "test_a.txt";
		Si::absolute_path const test_file_b = watched_dir / "test_b.txt";

		touch(test_file_a);
		boost::filesystem::remove(test_file_b.to_boost_path());

		boost::asio::io_service io;
		single_directory_watcher watcher(io, watched_dir);

		bool got_something = false;

		spawn_coroutine([&watcher, &test_file_a, &test_file_b, &got_something](spawn_context &yield)
		{
			optional<error_or<file_notification>> first_event = yield.get_one(Si::ref(watcher));
			BOOST_REQUIRE(first_event);
			optional<error_or<file_notification>> second_event = yield.get_one(Si::ref(watcher));
			BOOST_REQUIRE(second_event);

			got_something = true;

			file_notification *remove = &first_event->get();
			file_notification *add = &second_event->get();
			if (add->type != file_notification_type::add)
			{
				using std::swap;
				swap(remove, add);
			}

			BOOST_CHECK(file_notification_type::remove == remove->type);
			BOOST_CHECK_EQUAL(leaf(test_file_a), remove->name);

			BOOST_CHECK(file_notification_type::add == add->type);
			BOOST_CHECK_EQUAL(leaf(test_file_b), add->name);
		});

		boost::filesystem::rename(test_file_a.to_boost_path(), test_file_b.to_boost_path());

		boost::asio::basic_waitable_timer<Si::steady_clock_if_available> timeout(io);
		timeout.expires_from_now(Si::chrono::seconds(1));
		timeout.async_wait([&io](boost::system::error_code)
		{
			io.stop();
		});

		io.run();

		BOOST_CHECK(got_something);
	}
#endif
#endif
}
<commit_msg>the extra timeout for travis did not help<commit_after>#include <silicium/single_directory_watcher.hpp>
#include <silicium/observable/consume.hpp>
#include <silicium/observable/spawn_coroutine.hpp>
#include <silicium/open.hpp>
#include <silicium/steady_clock.hpp>
#include <silicium/sink/file_sink.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <fstream>
#include <chrono>
#if SILICIUM_HAS_SINGLE_DIRECTORY_WATCHER
#	include <boost/filesystem/operations.hpp>
#endif

namespace Si
{
#if SILICIUM_HAS_SINGLE_DIRECTORY_WATCHER
	namespace
	{
		void touch(Si::absolute_path const &name)
		{
			//remove existing file to reset the attributes
			Si::remove_file(name);

			std::ofstream file(name.c_str());
			BOOST_REQUIRE(file);
		}

		void test_single_event(
			Si::absolute_path const &watched_dir,
			std::function<void ()> const &provoke_event,
			std::function<void (file_notification const &)> const &on_event)
		{
			boost::asio::io_service io;
			single_directory_watcher watcher(io, watched_dir);

			bool got_event = false;
			auto consumer = consume<error_or<file_notification>>([&io, &got_event, &on_event](error_or<file_notification> const &event)
			{
				io.stop();
				on_event(event.get());
				got_event = true;
			});
			watcher.async_get_one(Si::observe_by_ref(consumer));

			provoke_event();

			boost::asio::basic_waitable_timer<Si::steady_clock_if_available> timeout(io);
			timeout.expires_from_now(Si::chrono::seconds(1));
			timeout.async_wait([&io](boost::system::error_code ec)
			{
				BOOST_REQUIRE(!ec);
				io.stop();
			});

			io.run();

			BOOST_CHECK(got_event);
		}
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_add_regular)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / Si::relative_path("test.txt");
		Si::remove_file(test_file);

		test_single_event(
			watched_dir,
			std::bind(touch, test_file),
			[&test_file](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::add == event.type);
			BOOST_CHECK(equivalent(test_file.to_boost_path(), event.name.to_boost_path()));
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_add_directory)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test";
		Si::remove_file(test_file);

		test_single_event(
			watched_dir,
			[&test_file]
		{
			boost::filesystem::create_directory(test_file.to_boost_path());
		},
			[&test_file](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::add == event.type);
			BOOST_CHECK(equivalent(test_file.to_boost_path(), event.name.to_boost_path()));
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_remove)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		touch(test_file);

		test_single_event(
			watched_dir,
			[&test_file]
		{
			boost::filesystem::remove(test_file.to_boost_path());
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove == event.type);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_remove_directory)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test";

		boost::filesystem::create_directory(test_file.to_boost_path());

		test_single_event(
			watched_dir,
			[&test_file]
		{
			boost::filesystem::remove(test_file.to_boost_path());
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove == event.type);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

#if SILICIUM_HAS_FILE_SINK
	BOOST_AUTO_TEST_CASE(file_system_watcher_change_on_write)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		boost::filesystem::create_directories(watched_dir.to_boost_path());
		Si::file_handle file = Si::overwrite_file(Si::native_path_string(test_file.c_str())).move_value();

		test_single_event(
			watched_dir,
			[&file]
		{
			Si::file_sink sink(file.handle);
			Si::append(sink, Si::file_sink_element(Si::make_c_str_range("hello\n")));
			Si::append(sink, Si::file_sink_element(Si::flush()));
			//we write to the file without closing it
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(event.type == file_notification_type::change_content || event.type == file_notification_type::change_content_or_metadata);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}
#endif

	BOOST_AUTO_TEST_CASE(file_system_watcher_change_on_close)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		touch(test_file);

		std::ofstream file(test_file.c_str());
		BOOST_REQUIRE(file);
		file << "hello\n";
		file.flush();

		test_single_event(
			watched_dir,
			[&file]
		{
			//The closing of the file is expected to trigger a change event.
			file.close();
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(event.type == file_notification_type::change_content || event.type == file_notification_type::change_content_or_metadata);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_change_metadata)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file = watched_dir / "test.txt";

		touch(test_file);

#ifdef _WIN32
		BOOST_REQUIRE(SetFileAttributesW(test_file.c_str(), FILE_ATTRIBUTE_NORMAL));
#else
		BOOST_REQUIRE(!chmod(test_file.c_str(), 0555));
#endif

		test_single_event(
			watched_dir,
			[&test_file]
		{
#ifdef _WIN32
			BOOST_REQUIRE(SetFileAttributesW(test_file.c_str(), FILE_ATTRIBUTE_TEMPORARY));
#else
			BOOST_REQUIRE(!chmod(test_file.c_str(), 0755));
#endif
		},
			[&test_file, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::change_content_or_metadata == event.type || file_notification_type::change_metadata == event.type);
			BOOST_CHECK_EQUAL(test_file, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_move_out)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";
		Si::absolute_path const original_name = watched_dir / "test.txt";
		Si::absolute_path const new_name = root_dir / "renamed.txt";

		boost::filesystem::remove_all(new_name.to_boost_path());
		boost::filesystem::remove_all(watched_dir.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());
		touch(original_name);

		test_single_event(
			watched_dir,
			[&original_name, &new_name]
		{
			boost::filesystem::rename(original_name.to_boost_path(), new_name.to_boost_path());
		},
			[&original_name, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove == event.type);
			BOOST_CHECK_EQUAL(original_name, watched_dir / event.name);
		});
	}

	BOOST_AUTO_TEST_CASE(file_system_watcher_move_in)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";
		Si::absolute_path const original_name = root_dir / "test.txt";
		Si::absolute_path const new_name = watched_dir / "renamed.txt";

		boost::filesystem::remove_all(watched_dir.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());
		touch(original_name);

		test_single_event(
			watched_dir,
			[&original_name, &new_name]
		{
			boost::filesystem::rename(original_name.to_boost_path(), new_name.to_boost_path());
		},
			[&new_name, &watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::add == event.type);
			BOOST_CHECK_EQUAL(new_name, watched_dir / event.name);
		});
	}

#ifndef _WIN32
	//we cannot yet detect the renaming of the watched directory
	BOOST_AUTO_TEST_CASE(file_system_watcher_rename_watched_dir)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";
		Si::absolute_path const new_name = root_dir / "renamed";

		boost::filesystem::remove_all(watched_dir.to_boost_path());
		boost::filesystem::remove_all(new_name.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());

		test_single_event(
			watched_dir,
			[&watched_dir, &new_name]
		{
			boost::filesystem::rename(watched_dir.to_boost_path(), new_name.to_boost_path());
		},
			[&watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::move_self == event.type);
			BOOST_CHECK_EQUAL("", event.name.underlying());
		});
	}
#endif

#ifndef _WIN32
	//we cannot yet detect the removal of the watched directory
	BOOST_AUTO_TEST_CASE(file_system_watcher_remove_watched_dir)
	{
		Si::absolute_path const root_dir = Si::get_current_working_directory();
		Si::absolute_path const watched_dir = root_dir / "watched";

		boost::filesystem::remove_all(watched_dir.to_boost_path());

		boost::filesystem::create_directories(watched_dir.to_boost_path());

		test_single_event(
			watched_dir,
			[&watched_dir]
		{
			boost::filesystem::remove(watched_dir.to_boost_path());
		},
			[&watched_dir](file_notification const &event)
		{
			BOOST_CHECK(file_notification_type::remove_self == event.type);
			BOOST_CHECK_EQUAL("", event.name.underlying());
		});
	}
#endif

#if SILICIUM_HAS_SPAWN_COROUTINE
	BOOST_AUTO_TEST_CASE(file_system_watcher_rename_in_dir)
	{
		Si::absolute_path const watched_dir = Si::get_current_working_directory();
		Si::absolute_path const test_file_a = watched_dir / "test_a.txt";
		Si::absolute_path const test_file_b = watched_dir / "test_b.txt";

		touch(test_file_a);
		boost::filesystem::remove(test_file_b.to_boost_path());

		boost::asio::io_service io;
		single_directory_watcher watcher(io, watched_dir);

		bool got_something = false;

		spawn_coroutine([&watcher, &test_file_a, &test_file_b, &got_something](spawn_context &yield)
		{
			optional<error_or<file_notification>> first_event = yield.get_one(Si::ref(watcher));
			BOOST_REQUIRE(first_event);
			optional<error_or<file_notification>> second_event = yield.get_one(Si::ref(watcher));
			BOOST_REQUIRE(second_event);

			got_something = true;

			file_notification *remove = &first_event->get();
			file_notification *add = &second_event->get();
			if (add->type != file_notification_type::add)
			{
				using std::swap;
				swap(remove, add);
			}

			BOOST_CHECK(file_notification_type::remove == remove->type);
			BOOST_CHECK_EQUAL(leaf(test_file_a), remove->name);

			BOOST_CHECK(file_notification_type::add == add->type);
			BOOST_CHECK_EQUAL(leaf(test_file_b), add->name);
		});

		boost::filesystem::rename(test_file_a.to_boost_path(), test_file_b.to_boost_path());

		boost::asio::basic_waitable_timer<Si::steady_clock_if_available> timeout(io);
		timeout.expires_from_now(Si::chrono::seconds(1));
		timeout.async_wait([&io](boost::system::error_code)
		{
			io.stop();
		});

		io.run();

		BOOST_CHECK(got_something);
	}
#endif
#endif
}
<|endoftext|>


<commit_before>/**
 * @file	src/DataManager.cpp
 * @date	Feb. 2016
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2016 Ph. Renaud-Goud / Opticalp

 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 "DataManager.h"
#include "ThreadManager.h"

#include "OutPort.h"
#include "DataItem.h"

#include "DataPocoLogger.h"

#include "Poco/Exception.h"
#include "Poco/Util/Application.h"

DataManager::DataManager()
{
    // Register data loggers in the factory using the C++ class name

    loggerFactory.registerClass<DataPocoLogger>("DataPocoLogger");
    loggerClasses.insert(classPair("DataPocoLogger", DataPocoLogger::description()));
}

DataManager::~DataManager()
{
    uninitialize(); // should have been already called by the system.

    // dataStore should clean itself nicely
}

void DataManager::initialize(Poco::Util::Application& app)
{
    // TODO: init loggers from config file?
}

void DataManager::uninitialize()
{
    poco_information(logger(),"Data manager uninitializing");
    // TODO: remove loggers
    // TODO: empty all data (expired, etc)
}

void DataManager::addOutPort(OutPort* port)
{
    allDataLock.writeLock();
    allData.push_back(SharedPtr<DataItem*>(new DataItem*(port->dataItem())));
    allDataLock.unlock();
}

void DataManager::removeOutPort(OutPort* port)
{
    allDataLock.writeLock();

    for (std::vector< SharedPtr<DataItem*> >::iterator it = allData.begin(),
            ite = allData.end(); it != ite; it++)
    {
        if (port->dataItem() == **it)
        {
            // unregister data item loggers
            std::set< SharedPtr<DataLogger*> > itemLoggers = port->dataItem()->loggers();
            for (std::set< SharedPtr<DataLogger*> >::iterator setIt = itemLoggers.begin(),
                    setIte = itemLoggers.end(); setIt != setIte; setIt++ )
                (**setIt)->detach();

            // replace the pointed data item by something throwing exceptions
            **it = &emptyDataItem;
            allData.erase(it);
            // poco_information(logger(), port->name() + " port DataItem "
            //         "erased from DataManager::allData. ");
            allDataLock.unlock();
            return;
        }
    }

    allDataLock.unlock();
    poco_error(logger(), "removeOutPort(): "
            "the port was not found");
}

void DataManager::newData(DataItem* self)
{
    if (!self->hasLoggers())
        return;

    std::set< SharedPtr<DataLogger*> > itemLoggers = self->loggers();

    for (std::set< SharedPtr<DataLogger*> >::iterator it = itemLoggers.begin(),
            ite = itemLoggers.end(); it != ite; it++ )
        (**it)->acquireLock();

    for (std::set< SharedPtr<DataLogger*> >::iterator it = itemLoggers.begin(),
            ite = itemLoggers.end(); it != ite; it++ )
    {
        // launch logger threads via thread manager.
        Poco::Util::Application::instance()
            .getSubsystem<ThreadManager>()
            .start(**it);
    }
}

SharedPtr<DataItem*> DataManager::getDataItem(DataItem* dataItem)
{
    allDataLock.readLock();
    for (std::vector< SharedPtr<DataItem*> >::iterator it = allData.begin(),
            ite = allData.end(); it != ite; it++)
    {
        if (dataItem==**it)
        {
            allDataLock.unlock();
            return *it;
        }
    }

    allDataLock.unlock();
    throw Poco::NotFoundException("getDataItem", "Data not found: "
            "Should have been deleted during the query");
}

SharedPtr<DataLogger*> DataManager::newDataLogger(std::string className)
{
    DataLogger* logger = loggerFactory.createInstance(className);
    SharedPtr<DataLogger*> tmpPtr(new (DataLogger*)(logger));

    loggersLock.writeLock();
    loggers.insert(tmpPtr);
    loggersLock.unlock();

    return tmpPtr;
}

std::set<SharedPtr<DataLogger*> > DataManager::dataLoggers()
{
    std::set< SharedPtr<DataLogger*> > tmpLoggers;
    loggersLock.readLock();
    tmpLoggers = loggers;
    loggersLock.unlock();

    return tmpLoggers;
}

SharedPtr<DataLogger*> DataManager::getDataLogger(DataLogger* dataLogger)
{
    loggersLock.readLock();

    for (std::set< SharedPtr<DataLogger*> >::iterator it = loggers.begin(),
            ite = loggers.end(); it != ite; it++ )
    {
        if (**it == dataLogger)
        {
            SharedPtr<DataLogger*> tmp = *it;
            loggersLock.unlock();
            return tmp;
        }
    }

    loggersLock.unlock();
    throw Poco::NotFoundException("DataManager",
            "The given data logger was not found");

}

void DataManager::registerLogger(SharedPtr<DataItem*> data,
        SharedPtr<DataLogger*> dataLogger)
{
    if (*data == &emptyDataItem)
        throw Poco::NotFoundException("registerLogger",
                                        "Data item not found");

    (*dataLogger)->registerData(*data);
}

SharedPtr<DataItem*> DataManager::getSourceDataItem(
        SharedPtr<DataLogger*> dataLogger)
{
    DataItem* data = (*dataLogger)->data();

    if (data)
        return getDataItem(data);
    else
        throw Poco::NotFoundException("DataManager::getsourceDataItem",
                "No source data item found. "
                "The logger may be detached. ");
}

void DataManager::removeDataLogger(SharedPtr<DataLogger*> logger)
{
    // switch the logger into empty state
    (*logger)->setEmpty();

    // remove the data logger from loggers. nothing to delete.
    loggers.erase(logger);
}
<commit_msg>DataManager destructor does not call uninit<commit_after>/**
 * @file	src/DataManager.cpp
 * @date	Feb. 2016
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2016 Ph. Renaud-Goud / Opticalp

 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 "DataManager.h"
#include "ThreadManager.h"

#include "OutPort.h"
#include "DataItem.h"

#include "DataPocoLogger.h"

#include "Poco/Exception.h"
#include "Poco/Util/Application.h"

DataManager::DataManager()
{
    // Register data loggers in the factory using the C++ class name

    loggerFactory.registerClass<DataPocoLogger>("DataPocoLogger");
    loggerClasses.insert(classPair("DataPocoLogger", DataPocoLogger::description()));
}

DataManager::~DataManager()
{
    // uninitialize(); // should have been already called by the system.

    // dataStore should clean itself nicely
}

void DataManager::initialize(Poco::Util::Application& app)
{
    // TODO: init loggers from config file?
}

void DataManager::uninitialize()
{
    poco_information(logger(),"Data manager uninitializing");
    // TODO: remove loggers
    // TODO: empty all data (expired, etc)
}

void DataManager::addOutPort(OutPort* port)
{
    allDataLock.writeLock();
    allData.push_back(SharedPtr<DataItem*>(new DataItem*(port->dataItem())));
    allDataLock.unlock();
}

void DataManager::removeOutPort(OutPort* port)
{
    allDataLock.writeLock();

    for (std::vector< SharedPtr<DataItem*> >::iterator it = allData.begin(),
            ite = allData.end(); it != ite; it++)
    {
        if (port->dataItem() == **it)
        {
            // unregister data item loggers
            std::set< SharedPtr<DataLogger*> > itemLoggers = port->dataItem()->loggers();
            for (std::set< SharedPtr<DataLogger*> >::iterator setIt = itemLoggers.begin(),
                    setIte = itemLoggers.end(); setIt != setIte; setIt++ )
                (**setIt)->detach();

            // replace the pointed data item by something throwing exceptions
            **it = &emptyDataItem;
            allData.erase(it);
            // poco_information(logger(), port->name() + " port DataItem "
            //         "erased from DataManager::allData. ");
            allDataLock.unlock();
            return;
        }
    }

    allDataLock.unlock();
    poco_error(logger(), "removeOutPort(): "
            "the port was not found");
}

void DataManager::newData(DataItem* self)
{
    if (!self->hasLoggers())
        return;

    std::set< SharedPtr<DataLogger*> > itemLoggers = self->loggers();

    for (std::set< SharedPtr<DataLogger*> >::iterator it = itemLoggers.begin(),
            ite = itemLoggers.end(); it != ite; it++ )
        (**it)->acquireLock();

    for (std::set< SharedPtr<DataLogger*> >::iterator it = itemLoggers.begin(),
            ite = itemLoggers.end(); it != ite; it++ )
    {
        // launch logger threads via thread manager.
        Poco::Util::Application::instance()
            .getSubsystem<ThreadManager>()
            .start(**it);
    }
}

SharedPtr<DataItem*> DataManager::getDataItem(DataItem* dataItem)
{
    allDataLock.readLock();
    for (std::vector< SharedPtr<DataItem*> >::iterator it = allData.begin(),
            ite = allData.end(); it != ite; it++)
    {
        if (dataItem==**it)
        {
            allDataLock.unlock();
            return *it;
        }
    }

    allDataLock.unlock();
    throw Poco::NotFoundException("getDataItem", "Data not found: "
            "Should have been deleted during the query");
}

SharedPtr<DataLogger*> DataManager::newDataLogger(std::string className)
{
    DataLogger* logger = loggerFactory.createInstance(className);
    SharedPtr<DataLogger*> tmpPtr(new (DataLogger*)(logger));

    loggersLock.writeLock();
    loggers.insert(tmpPtr);
    loggersLock.unlock();

    return tmpPtr;
}

std::set<SharedPtr<DataLogger*> > DataManager::dataLoggers()
{
    std::set< SharedPtr<DataLogger*> > tmpLoggers;
    loggersLock.readLock();
    tmpLoggers = loggers;
    loggersLock.unlock();

    return tmpLoggers;
}

SharedPtr<DataLogger*> DataManager::getDataLogger(DataLogger* dataLogger)
{
    loggersLock.readLock();

    for (std::set< SharedPtr<DataLogger*> >::iterator it = loggers.begin(),
            ite = loggers.end(); it != ite; it++ )
    {
        if (**it == dataLogger)
        {
            SharedPtr<DataLogger*> tmp = *it;
            loggersLock.unlock();
            return tmp;
        }
    }

    loggersLock.unlock();
    throw Poco::NotFoundException("DataManager",
            "The given data logger was not found");

}

void DataManager::registerLogger(SharedPtr<DataItem*> data,
        SharedPtr<DataLogger*> dataLogger)
{
    if (*data == &emptyDataItem)
        throw Poco::NotFoundException("registerLogger",
                                        "Data item not found");

    (*dataLogger)->registerData(*data);
}

SharedPtr<DataItem*> DataManager::getSourceDataItem(
        SharedPtr<DataLogger*> dataLogger)
{
    DataItem* data = (*dataLogger)->data();

    if (data)
        return getDataItem(data);
    else
        throw Poco::NotFoundException("DataManager::getsourceDataItem",
                "No source data item found. "
                "The logger may be detached. ");
}

void DataManager::removeDataLogger(SharedPtr<DataLogger*> logger)
{
    // switch the logger into empty state
    (*logger)->setEmpty();

    // remove the data logger from loggers. nothing to delete.
    loggers.erase(logger);
}
<|endoftext|>


<commit_before>#include "Environment.h"

#include <algorithm>

namespace Draupnir {

/**
 * Construct a new execution environment
 *
 * @param out  Ostream to use for output
 * @param err  Ostream to use for errors
 */
Environment::Environment(std::ostream &out, std::ostream &err) noexcept : stack{}, sout{out}, serr{err} {}

/**
 * Remove the given number of elements from the top of the stack
 *
 * @param n  Number of elements to remove
 * @return the resulting Environment
 */
Environment &Environment::drop(std::size_t n) noexcept {
  std::size_t nn = std::max(0ul, std::min(stack.size(), n));
  if (0 != nn) {
    stack.erase(stack.end() - static_cast<stack_offset_type>(nn), stack.end());
  }
  return *this;
}

/**
 * Copy the given number of elements at the top of the stack the given number of times
 *
 * @param n  Number of times to copy
 * @param m  Number of elements to copy
 * @return the resulting Environment
 */
Environment &Environment::copy(std::size_t n, std::size_t m) noexcept {
  std::size_t mm = std::max(0ul, std::min(stack.size(), m));
  if (0 != mm) {
    for (std::size_t i = 0; i < n; i++) {
      for (std::size_t j = 0; j < mm; j++) {
        stack.push_back(value_ptr<Sponge>(stack[stack.size() - mm + j]->clone()));
      }
    }
  }
  return *this;
}

/**
 * Move the given number of elements downwards from the top of the stack the given number of positions
 *
 * @param n  Number of elements to move
 * @param m  Number of positions to move them
 * @return the resulting Environment
 */
Environment &Environment::sink(std::size_t n, std::size_t m) noexcept {
  n = std::min(n, stack.size());
  m = std::min(m, stack.size() - n);

  if (0 != n && 0 != m) {
    std::rotate(
        stack.end() - static_cast<stack_offset_type>(n + m),
        stack.end() - static_cast<stack_offset_type>(n    ),
        stack.end()
    );
  }

  return *this;
}

}

<commit_msg>Add raw() to Environment<commit_after>#include "Environment.h"

#include <algorithm>
#include <iomanip>

namespace Draupnir {

/**
 * Construct a new execution environment
 *
 * @param out  Ostream to use for output
 * @param err  Ostream to use for errors
 */
Environment::Environment(std::ostream &out, std::ostream &err) noexcept : stack{}, sout{out}, serr{err} {}

/**
 * Remove the given number of elements from the top of the stack
 *
 * @param n  Number of elements to remove
 * @return the resulting Environment
 */
Environment &Environment::drop(std::size_t n) noexcept {
  std::size_t nn = std::max(0ul, std::min(stack.size(), n));
  if (0 != nn) {
    stack.erase(stack.end() - static_cast<stack_offset_type>(nn), stack.end());
  }
  return *this;
}

/**
 * Copy the given number of elements at the top of the stack the given number of times
 *
 * @param n  Number of times to copy
 * @param m  Number of elements to copy
 * @return the resulting Environment
 */
Environment &Environment::copy(std::size_t n, std::size_t m) noexcept {
  std::size_t mm = std::max(0ul, std::min(stack.size(), m));
  if (0 != mm) {
    for (std::size_t i = 0; i < n; i++) {
      for (std::size_t j = 0; j < mm; j++) {
        stack.push_back(value_ptr<Sponge>(stack[stack.size() - mm + j]->clone()));
      }
    }
  }
  return *this;
}

/**
 * Move the given number of elements downwards from the top of the stack the given number of positions
 *
 * @param n  Number of elements to move
 * @param m  Number of positions to move them
 * @return the resulting Environment
 */
Environment &Environment::sink(std::size_t n, std::size_t m) noexcept {
  n = std::min(n, stack.size());
  m = std::min(m, stack.size() - n);

  if (0 != n && 0 != m) {
    std::rotate(
        stack.end() - static_cast<stack_offset_type>(n + m),
        stack.end() - static_cast<stack_offset_type>(n    ),
        stack.end()
    );
  }

  return *this;
}

/**
 * Generate the given number of raw bytes from the topmost Sponge
 *
 * @param count  Number of bytes to generate
 * @param hex  If true, generate the bytes as hex strings
 * @return the resulting Environment
 */
Environment &Environment::raw(std::size_t count, bool hex) noexcept {
  std::ios::fmtflags flags(sout.flags());

  if (hex) { sout << std::hex; }

  while (count--) {
    sout << stack.back()->squeeze();
  }

  sout.flags(flags);

  return *this;
}

}

<|endoftext|>


<commit_before>//===-- LowerSubregs.cpp - Subregister Lowering instruction pass ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a MachineFunction pass which runs after register
// allocation that turns subreg insert/extract instructions into register
// copies, as needed. This ensures correct codegen even if the coalescer
// isn't able to remove all subreg instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "lowersubregs"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {
  struct LowerSubregsInstructionPass : public MachineFunctionPass {
  private:
    const TargetRegisterInfo *TRI;
    const TargetInstrInfo *TII;

  public:
    static char ID; // Pass identification, replacement for typeid
    LowerSubregsInstructionPass() : MachineFunctionPass(&ID) {}

    const char *getPassName() const {
      return "Subregister lowering instruction pass";
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addPreservedID(MachineLoopInfoID);
      AU.addPreservedID(MachineDominatorsID);
      MachineFunctionPass::getAnalysisUsage(AU);
    }

    /// runOnMachineFunction - pass entry point
    bool runOnMachineFunction(MachineFunction&);

  private:
    bool LowerExtract(MachineInstr *MI);
    bool LowerInsert(MachineInstr *MI);
    bool LowerSubregToReg(MachineInstr *MI);

    void TransferDeadFlag(MachineInstr *MI, unsigned DstReg,
                          const TargetRegisterInfo *TRI);
    void TransferKillFlag(MachineInstr *MI, unsigned SrcReg,
                          const TargetRegisterInfo *TRI,
                          bool AddIfNotFound = false);
  };

  char LowerSubregsInstructionPass::ID = 0;
}

FunctionPass *llvm::createLowerSubregsPass() {
  return new LowerSubregsInstructionPass();
}

/// TransferDeadFlag - MI is a pseudo-instruction with DstReg dead,
/// and the lowered replacement instructions immediately precede it.
/// Mark the replacement instructions with the dead flag.
void
LowerSubregsInstructionPass::TransferDeadFlag(MachineInstr *MI,
                                              unsigned DstReg,
                                              const TargetRegisterInfo *TRI) {
  for (MachineBasicBlock::iterator MII =
        prior(MachineBasicBlock::iterator(MI)); ; --MII) {
    if (MII->addRegisterDead(DstReg, TRI))
      break;
    assert(MII != MI->getParent()->begin() &&
           "copyRegToReg output doesn't reference destination register!");
  }
}

/// TransferKillFlag - MI is a pseudo-instruction with SrcReg killed,
/// and the lowered replacement instructions immediately precede it.
/// Mark the replacement instructions with the kill flag.
void
LowerSubregsInstructionPass::TransferKillFlag(MachineInstr *MI,
                                              unsigned SrcReg,
                                              const TargetRegisterInfo *TRI,
                                              bool AddIfNotFound) {
  for (MachineBasicBlock::iterator MII =
        prior(MachineBasicBlock::iterator(MI)); ; --MII) {
    if (MII->addRegisterKilled(SrcReg, TRI, AddIfNotFound))
      break;
    assert(MII != MI->getParent()->begin() &&
           "copyRegToReg output doesn't reference source register!");
  }
}

bool LowerSubregsInstructionPass::LowerExtract(MachineInstr *MI) {
  MachineBasicBlock *MBB = MI->getParent();

  assert(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
         MI->getOperand(1).isReg() && MI->getOperand(1).isUse() &&
         MI->getOperand(2).isImm() && "Malformed extract_subreg");

  unsigned DstReg   = MI->getOperand(0).getReg();
  unsigned SuperReg = MI->getOperand(1).getReg();
  unsigned SubIdx   = MI->getOperand(2).getImm();
  unsigned SrcReg   = TRI->getSubReg(SuperReg, SubIdx);

  assert(TargetRegisterInfo::isPhysicalRegister(SuperReg) &&
         "Extract supperg source must be a physical register");
  assert(TargetRegisterInfo::isPhysicalRegister(DstReg) &&
         "Extract destination must be in a physical register");
  assert(SrcReg && "invalid subregister index for register");

  DEBUG(errs() << "subreg: CONVERTING: " << *MI);

  if (SrcReg == DstReg) {
    // No need to insert an identity copy instruction.
    if (MI->getOperand(1).isKill()) {
      // We must make sure the super-register gets killed. Replace the
      // instruction with KILL.
      MI->setDesc(TII->get(TargetInstrInfo::KILL));
      MI->RemoveOperand(2);     // SubIdx
      DEBUG(errs() << "subreg: replace by: " << *MI);
      return true;
    }

    DEBUG(errs() << "subreg: eliminated!");
  } else {
    // Insert copy
    const TargetRegisterClass *TRCS = TRI->getPhysicalRegisterRegClass(DstReg);
    const TargetRegisterClass *TRCD = TRI->getPhysicalRegisterRegClass(SrcReg);
    bool Emitted = TII->copyRegToReg(*MBB, MI, DstReg, SrcReg, TRCD, TRCS);
    (void)Emitted;
    assert(Emitted && "Subreg and Dst must be of compatible register class");
    // Transfer the kill/dead flags, if needed.
    if (MI->getOperand(0).isDead())
      TransferDeadFlag(MI, DstReg, TRI);
    if (MI->getOperand(1).isKill())
      TransferKillFlag(MI, SuperReg, TRI, true);
    DEBUG({
        MachineBasicBlock::iterator dMI = MI;
        errs() << "subreg: " << *(--dMI);
      });
  }

  DEBUG(errs() << '\n');
  MBB->erase(MI);
  return true;
}

bool LowerSubregsInstructionPass::LowerSubregToReg(MachineInstr *MI) {
  MachineBasicBlock *MBB = MI->getParent();
  assert((MI->getOperand(0).isReg() && MI->getOperand(0).isDef()) &&
         MI->getOperand(1).isImm() &&
         (MI->getOperand(2).isReg() && MI->getOperand(2).isUse()) &&
          MI->getOperand(3).isImm() && "Invalid subreg_to_reg");

  unsigned DstReg  = MI->getOperand(0).getReg();
  unsigned InsReg  = MI->getOperand(2).getReg();
  unsigned InsSIdx = MI->getOperand(2).getSubReg();
  unsigned SubIdx  = MI->getOperand(3).getImm();

  assert(SubIdx != 0 && "Invalid index for insert_subreg");
  unsigned DstSubReg = TRI->getSubReg(DstReg, SubIdx);

  assert(TargetRegisterInfo::isPhysicalRegister(DstReg) &&
         "Insert destination must be in a physical register");
  assert(TargetRegisterInfo::isPhysicalRegister(InsReg) &&
         "Inserted value must be in a physical register");

  DEBUG(errs() << "subreg: CONVERTING: " << *MI);

  if (DstSubReg == InsReg && InsSIdx == 0) {
    // No need to insert an identify copy instruction.
    // Watch out for case like this:
    // %RAX<def> = ...
    // %RAX<def> = SUBREG_TO_REG 0, %EAX:3<kill>, 3
    // The first def is defining RAX, not EAX so the top bits were not
    // zero extended.
    DEBUG(errs() << "subreg: eliminated!");
  } else {
    // Insert sub-register copy
    const TargetRegisterClass *TRC0= TRI->getPhysicalRegisterRegClass(DstSubReg);
    const TargetRegisterClass *TRC1= TRI->getPhysicalRegisterRegClass(InsReg);
    bool Emitted = TII->copyRegToReg(*MBB, MI, DstSubReg, InsReg, TRC0, TRC1);
    (void)Emitted;
    assert(Emitted && "Subreg and Dst must be of compatible register class");
    // Transfer the kill/dead flags, if needed.
    if (MI->getOperand(0).isDead())
      TransferDeadFlag(MI, DstSubReg, TRI);
    if (MI->getOperand(2).isKill())
      TransferKillFlag(MI, InsReg, TRI);
    DEBUG({
        MachineBasicBlock::iterator dMI = MI;
        errs() << "subreg: " << *(--dMI);
      });
  }

  DEBUG(errs() << '\n');
  MBB->erase(MI);
  return true;
}

bool LowerSubregsInstructionPass::LowerInsert(MachineInstr *MI) {
  MachineBasicBlock *MBB = MI->getParent();
  assert((MI->getOperand(0).isReg() && MI->getOperand(0).isDef()) &&
         (MI->getOperand(1).isReg() && MI->getOperand(1).isUse()) &&
         (MI->getOperand(2).isReg() && MI->getOperand(2).isUse()) &&
          MI->getOperand(3).isImm() && "Invalid insert_subreg");

  unsigned DstReg = MI->getOperand(0).getReg();
#ifndef NDEBUG
  unsigned SrcReg = MI->getOperand(1).getReg();
#endif
  unsigned InsReg = MI->getOperand(2).getReg();
  unsigned SubIdx = MI->getOperand(3).getImm();

  assert(DstReg == SrcReg && "insert_subreg not a two-address instruction?");
  assert(SubIdx != 0 && "Invalid index for insert_subreg");
  unsigned DstSubReg = TRI->getSubReg(DstReg, SubIdx);
  assert(DstSubReg && "invalid subregister index for register");
  assert(TargetRegisterInfo::isPhysicalRegister(SrcReg) &&
         "Insert superreg source must be in a physical register");
  assert(TargetRegisterInfo::isPhysicalRegister(InsReg) &&
         "Inserted value must be in a physical register");

  DEBUG(errs() << "subreg: CONVERTING: " << *MI);

  if (DstSubReg == InsReg) {
    // No need to insert an identity copy instruction. If the SrcReg was
    // <undef>, we need to make sure it is alive by inserting a KILL
    if (MI->getOperand(1).isUndef() && !MI->getOperand(0).isDead()) {
      MachineInstrBuilder MIB = BuildMI(*MBB, MI, MI->getDebugLoc(),
                                TII->get(TargetInstrInfo::KILL), DstReg);
      if (MI->getOperand(2).isUndef())
        MIB.addReg(InsReg, RegState::Undef);
      else
        MIB.addReg(InsReg, RegState::Kill);
    } else {
      DEBUG(errs() << "subreg: eliminated!\n");
      MBB->erase(MI);
      return true;
    }
  } else {
    // Insert sub-register copy
    const TargetRegisterClass *TRC0= TRI->getPhysicalRegisterRegClass(DstSubReg);
    const TargetRegisterClass *TRC1= TRI->getPhysicalRegisterRegClass(InsReg);
    if (MI->getOperand(2).isUndef())
      // If the source register being inserted is undef, then this becomes a
      // KILL.
      BuildMI(*MBB, MI, MI->getDebugLoc(),
              TII->get(TargetInstrInfo::KILL), DstSubReg);
    else {
      bool Emitted = TII->copyRegToReg(*MBB, MI, DstSubReg, InsReg, TRC0, TRC1);
      (void)Emitted;
      assert(Emitted && "Subreg and Dst must be of compatible register class");
    }
    MachineBasicBlock::iterator CopyMI = MI;
    --CopyMI;

    // INSERT_SUBREG is a two-address instruction so it implicitly kills SrcReg.
    if (!MI->getOperand(1).isUndef())
      CopyMI->addOperand(MachineOperand::CreateReg(DstReg, false, true, true));

    // Transfer the kill/dead flags, if needed.
    if (MI->getOperand(0).isDead()) {
      TransferDeadFlag(MI, DstSubReg, TRI);
    } else {
      // Make sure the full DstReg is live after this replacement.
      CopyMI->addOperand(MachineOperand::CreateReg(DstReg, true, true));
    }

    // Make sure the inserted register gets killed
    if (MI->getOperand(2).isKill() && !MI->getOperand(2).isUndef())
      TransferKillFlag(MI, InsReg, TRI);
  }

  DEBUG({
      MachineBasicBlock::iterator dMI = MI;
      errs() << "subreg: " << *(--dMI) << "\n";
    });

  MBB->erase(MI);
  return true;
}

/// runOnMachineFunction - Reduce subregister inserts and extracts to register
/// copies.
///
bool LowerSubregsInstructionPass::runOnMachineFunction(MachineFunction &MF) {
  DEBUG(errs() << "Machine Function\n"
               << "********** LOWERING SUBREG INSTRS **********\n"
               << "********** Function: "
               << MF.getFunction()->getName() << '\n');
  TRI = MF.getTarget().getRegisterInfo();
  TII = MF.getTarget().getInstrInfo();

  bool MadeChange = false;

  for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end();
       mbbi != mbbe; ++mbbi) {
    for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end();
         mi != me;) {
      MachineBasicBlock::iterator nmi = llvm::next(mi);
      MachineInstr *MI = mi;
      if (MI->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) {
        MadeChange |= LowerExtract(MI);
      } else if (MI->getOpcode() == TargetInstrInfo::INSERT_SUBREG) {
        MadeChange |= LowerInsert(MI);
      } else if (MI->getOpcode() == TargetInstrInfo::SUBREG_TO_REG) {
        MadeChange |= LowerSubregToReg(MI);
      }
      mi = nmi;
    }
  }

  return MadeChange;
}
<commit_msg><commit_after>//===-- LowerSubregs.cpp - Subregister Lowering instruction pass ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a MachineFunction pass which runs after register
// allocation that turns subreg insert/extract instructions into register
// copies, as needed. This ensures correct codegen even if the coalescer
// isn't able to remove all subreg instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "lowersubregs"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {
  struct LowerSubregsInstructionPass : public MachineFunctionPass {
  private:
    const TargetRegisterInfo *TRI;
    const TargetInstrInfo *TII;

  public:
    static char ID; // Pass identification, replacement for typeid
    LowerSubregsInstructionPass() : MachineFunctionPass(&ID) {}

    const char *getPassName() const {
      return "Subregister lowering instruction pass";
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addPreservedID(MachineLoopInfoID);
      AU.addPreservedID(MachineDominatorsID);
      MachineFunctionPass::getAnalysisUsage(AU);
    }

    /// runOnMachineFunction - pass entry point
    bool runOnMachineFunction(MachineFunction&);

  private:
    bool LowerExtract(MachineInstr *MI);
    bool LowerInsert(MachineInstr *MI);
    bool LowerSubregToReg(MachineInstr *MI);

    void TransferDeadFlag(MachineInstr *MI, unsigned DstReg,
                          const TargetRegisterInfo *TRI);
    void TransferKillFlag(MachineInstr *MI, unsigned SrcReg,
                          const TargetRegisterInfo *TRI,
                          bool AddIfNotFound = false);
  };

  char LowerSubregsInstructionPass::ID = 0;
}

FunctionPass *llvm::createLowerSubregsPass() {
  return new LowerSubregsInstructionPass();
}

/// TransferDeadFlag - MI is a pseudo-instruction with DstReg dead,
/// and the lowered replacement instructions immediately precede it.
/// Mark the replacement instructions with the dead flag.
void
LowerSubregsInstructionPass::TransferDeadFlag(MachineInstr *MI,
                                              unsigned DstReg,
                                              const TargetRegisterInfo *TRI) {
  for (MachineBasicBlock::iterator MII =
        prior(MachineBasicBlock::iterator(MI)); ; --MII) {
    if (MII->addRegisterDead(DstReg, TRI))
      break;
    assert(MII != MI->getParent()->begin() &&
           "copyRegToReg output doesn't reference destination register!");
  }
}

/// TransferKillFlag - MI is a pseudo-instruction with SrcReg killed,
/// and the lowered replacement instructions immediately precede it.
/// Mark the replacement instructions with the kill flag.
void
LowerSubregsInstructionPass::TransferKillFlag(MachineInstr *MI,
                                              unsigned SrcReg,
                                              const TargetRegisterInfo *TRI,
                                              bool AddIfNotFound) {
  for (MachineBasicBlock::iterator MII =
        prior(MachineBasicBlock::iterator(MI)); ; --MII) {
    if (MII->addRegisterKilled(SrcReg, TRI, AddIfNotFound))
      break;
    assert(MII != MI->getParent()->begin() &&
           "copyRegToReg output doesn't reference source register!");
  }
}

bool LowerSubregsInstructionPass::LowerExtract(MachineInstr *MI) {
  MachineBasicBlock *MBB = MI->getParent();

  assert(MI->getOperand(0).isReg() && MI->getOperand(0).isDef() &&
         MI->getOperand(1).isReg() && MI->getOperand(1).isUse() &&
         MI->getOperand(2).isImm() && "Malformed extract_subreg");

  unsigned DstReg   = MI->getOperand(0).getReg();
  unsigned SuperReg = MI->getOperand(1).getReg();
  unsigned SubIdx   = MI->getOperand(2).getImm();
  unsigned SrcReg   = TRI->getSubReg(SuperReg, SubIdx);

  assert(TargetRegisterInfo::isPhysicalRegister(SuperReg) &&
         "Extract supperg source must be a physical register");
  assert(TargetRegisterInfo::isPhysicalRegister(DstReg) &&
         "Extract destination must be in a physical register");
  assert(SrcReg && "invalid subregister index for register");

  DEBUG(dbgs() << "subreg: CONVERTING: " << *MI);

  if (SrcReg == DstReg) {
    // No need to insert an identity copy instruction.
    if (MI->getOperand(1).isKill()) {
      // We must make sure the super-register gets killed. Replace the
      // instruction with KILL.
      MI->setDesc(TII->get(TargetInstrInfo::KILL));
      MI->RemoveOperand(2);     // SubIdx
      DEBUG(dbgs() << "subreg: replace by: " << *MI);
      return true;
    }

    DEBUG(dbgs() << "subreg: eliminated!");
  } else {
    // Insert copy
    const TargetRegisterClass *TRCS = TRI->getPhysicalRegisterRegClass(DstReg);
    const TargetRegisterClass *TRCD = TRI->getPhysicalRegisterRegClass(SrcReg);
    bool Emitted = TII->copyRegToReg(*MBB, MI, DstReg, SrcReg, TRCD, TRCS);
    (void)Emitted;
    assert(Emitted && "Subreg and Dst must be of compatible register class");
    // Transfer the kill/dead flags, if needed.
    if (MI->getOperand(0).isDead())
      TransferDeadFlag(MI, DstReg, TRI);
    if (MI->getOperand(1).isKill())
      TransferKillFlag(MI, SuperReg, TRI, true);
    DEBUG({
        MachineBasicBlock::iterator dMI = MI;
        dbgs() << "subreg: " << *(--dMI);
      });
  }

  DEBUG(dbgs() << '\n');
  MBB->erase(MI);
  return true;
}

bool LowerSubregsInstructionPass::LowerSubregToReg(MachineInstr *MI) {
  MachineBasicBlock *MBB = MI->getParent();
  assert((MI->getOperand(0).isReg() && MI->getOperand(0).isDef()) &&
         MI->getOperand(1).isImm() &&
         (MI->getOperand(2).isReg() && MI->getOperand(2).isUse()) &&
          MI->getOperand(3).isImm() && "Invalid subreg_to_reg");

  unsigned DstReg  = MI->getOperand(0).getReg();
  unsigned InsReg  = MI->getOperand(2).getReg();
  unsigned InsSIdx = MI->getOperand(2).getSubReg();
  unsigned SubIdx  = MI->getOperand(3).getImm();

  assert(SubIdx != 0 && "Invalid index for insert_subreg");
  unsigned DstSubReg = TRI->getSubReg(DstReg, SubIdx);

  assert(TargetRegisterInfo::isPhysicalRegister(DstReg) &&
         "Insert destination must be in a physical register");
  assert(TargetRegisterInfo::isPhysicalRegister(InsReg) &&
         "Inserted value must be in a physical register");

  DEBUG(dbgs() << "subreg: CONVERTING: " << *MI);

  if (DstSubReg == InsReg && InsSIdx == 0) {
    // No need to insert an identify copy instruction.
    // Watch out for case like this:
    // %RAX<def> = ...
    // %RAX<def> = SUBREG_TO_REG 0, %EAX:3<kill>, 3
    // The first def is defining RAX, not EAX so the top bits were not
    // zero extended.
    DEBUG(dbgs() << "subreg: eliminated!");
  } else {
    // Insert sub-register copy
    const TargetRegisterClass *TRC0= TRI->getPhysicalRegisterRegClass(DstSubReg);
    const TargetRegisterClass *TRC1= TRI->getPhysicalRegisterRegClass(InsReg);
    bool Emitted = TII->copyRegToReg(*MBB, MI, DstSubReg, InsReg, TRC0, TRC1);
    (void)Emitted;
    assert(Emitted && "Subreg and Dst must be of compatible register class");
    // Transfer the kill/dead flags, if needed.
    if (MI->getOperand(0).isDead())
      TransferDeadFlag(MI, DstSubReg, TRI);
    if (MI->getOperand(2).isKill())
      TransferKillFlag(MI, InsReg, TRI);
    DEBUG({
        MachineBasicBlock::iterator dMI = MI;
        dbgs() << "subreg: " << *(--dMI);
      });
  }

  DEBUG(dbgs() << '\n');
  MBB->erase(MI);
  return true;
}

bool LowerSubregsInstructionPass::LowerInsert(MachineInstr *MI) {
  MachineBasicBlock *MBB = MI->getParent();
  assert((MI->getOperand(0).isReg() && MI->getOperand(0).isDef()) &&
         (MI->getOperand(1).isReg() && MI->getOperand(1).isUse()) &&
         (MI->getOperand(2).isReg() && MI->getOperand(2).isUse()) &&
          MI->getOperand(3).isImm() && "Invalid insert_subreg");

  unsigned DstReg = MI->getOperand(0).getReg();
#ifndef NDEBUG
  unsigned SrcReg = MI->getOperand(1).getReg();
#endif
  unsigned InsReg = MI->getOperand(2).getReg();
  unsigned SubIdx = MI->getOperand(3).getImm();

  assert(DstReg == SrcReg && "insert_subreg not a two-address instruction?");
  assert(SubIdx != 0 && "Invalid index for insert_subreg");
  unsigned DstSubReg = TRI->getSubReg(DstReg, SubIdx);
  assert(DstSubReg && "invalid subregister index for register");
  assert(TargetRegisterInfo::isPhysicalRegister(SrcReg) &&
         "Insert superreg source must be in a physical register");
  assert(TargetRegisterInfo::isPhysicalRegister(InsReg) &&
         "Inserted value must be in a physical register");

  DEBUG(dbgs() << "subreg: CONVERTING: " << *MI);

  if (DstSubReg == InsReg) {
    // No need to insert an identity copy instruction. If the SrcReg was
    // <undef>, we need to make sure it is alive by inserting a KILL
    if (MI->getOperand(1).isUndef() && !MI->getOperand(0).isDead()) {
      MachineInstrBuilder MIB = BuildMI(*MBB, MI, MI->getDebugLoc(),
                                TII->get(TargetInstrInfo::KILL), DstReg);
      if (MI->getOperand(2).isUndef())
        MIB.addReg(InsReg, RegState::Undef);
      else
        MIB.addReg(InsReg, RegState::Kill);
    } else {
      DEBUG(dbgs() << "subreg: eliminated!\n");
      MBB->erase(MI);
      return true;
    }
  } else {
    // Insert sub-register copy
    const TargetRegisterClass *TRC0= TRI->getPhysicalRegisterRegClass(DstSubReg);
    const TargetRegisterClass *TRC1= TRI->getPhysicalRegisterRegClass(InsReg);
    if (MI->getOperand(2).isUndef())
      // If the source register being inserted is undef, then this becomes a
      // KILL.
      BuildMI(*MBB, MI, MI->getDebugLoc(),
              TII->get(TargetInstrInfo::KILL), DstSubReg);
    else {
      bool Emitted = TII->copyRegToReg(*MBB, MI, DstSubReg, InsReg, TRC0, TRC1);
      (void)Emitted;
      assert(Emitted && "Subreg and Dst must be of compatible register class");
    }
    MachineBasicBlock::iterator CopyMI = MI;
    --CopyMI;

    // INSERT_SUBREG is a two-address instruction so it implicitly kills SrcReg.
    if (!MI->getOperand(1).isUndef())
      CopyMI->addOperand(MachineOperand::CreateReg(DstReg, false, true, true));

    // Transfer the kill/dead flags, if needed.
    if (MI->getOperand(0).isDead()) {
      TransferDeadFlag(MI, DstSubReg, TRI);
    } else {
      // Make sure the full DstReg is live after this replacement.
      CopyMI->addOperand(MachineOperand::CreateReg(DstReg, true, true));
    }

    // Make sure the inserted register gets killed
    if (MI->getOperand(2).isKill() && !MI->getOperand(2).isUndef())
      TransferKillFlag(MI, InsReg, TRI);
  }

  DEBUG({
      MachineBasicBlock::iterator dMI = MI;
      dbgs() << "subreg: " << *(--dMI) << "\n";
    });

  MBB->erase(MI);
  return true;
}

/// runOnMachineFunction - Reduce subregister inserts and extracts to register
/// copies.
///
bool LowerSubregsInstructionPass::runOnMachineFunction(MachineFunction &MF) {
  DEBUG(dbgs() << "Machine Function\n"
               << "********** LOWERING SUBREG INSTRS **********\n"
               << "********** Function: "
               << MF.getFunction()->getName() << '\n');
  TRI = MF.getTarget().getRegisterInfo();
  TII = MF.getTarget().getInstrInfo();

  bool MadeChange = false;

  for (MachineFunction::iterator mbbi = MF.begin(), mbbe = MF.end();
       mbbi != mbbe; ++mbbi) {
    for (MachineBasicBlock::iterator mi = mbbi->begin(), me = mbbi->end();
         mi != me;) {
      MachineBasicBlock::iterator nmi = llvm::next(mi);
      MachineInstr *MI = mi;
      if (MI->getOpcode() == TargetInstrInfo::EXTRACT_SUBREG) {
        MadeChange |= LowerExtract(MI);
      } else if (MI->getOpcode() == TargetInstrInfo::INSERT_SUBREG) {
        MadeChange |= LowerInsert(MI);
      } else if (MI->getOpcode() == TargetInstrInfo::SUBREG_TO_REG) {
        MadeChange |= LowerSubregToReg(MI);
      }
      mi = nmi;
    }
  }

  return MadeChange;
}
<|endoftext|>