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

   Copyright (c): 2008 - 2013 Hericus Software, LLC

   License: The MIT License (MIT)

   Authors: Steven M. Cherry

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

#include <cstdlib>

#include <AnException.h>
#include <EnEx.h>
#include <Log.h>
#include <XmlHelpers.h>
#include <Timer.h>
#include <Tools.h>
using namespace SLib;

#include "HelixFS.h"
#include "HelixConfig.h"
#include "HelixBuilder.h"
#include "HelixWorker.h"
#include "HelixJSApiGenTask.h"
using namespace Helix::Build;

HelixBuilder::HelixBuilder()
{
	EnEx ee(FL, "HelixBuilder::HelixBuilder( HelixFS& helixfs )");

}

HelixBuilder::~HelixBuilder()
{
	EnEx ee(FL, "HelixBuilder::~HelixBuilder()");

}

void HelixBuilder::Build( const twine& folderPath )
{
	EnEx ee(FL, "HelixBuilder::Build( const twine& folderPath )");

	if(HelixWorker::getInstance().HasError()){
		return; // Bail out early on any previous errors
	}

	// Some special cases
	if(folderPath == "HelixMain" || folderPath == "HelixDaemon"){
		dptr<HelixLinkTask> lt = new HelixLinkTask( std::make_shared<HelixFSFolder_Bare>(folderPath)  );
		if(lt->RequiresLink()){
			HelixWorker::getInstance().Add( lt.release() );
		}
		return;
	}

	HelixFSFolder folder = HelixFS::getInstance().FindPath( folderPath );
	if(!folder){
		WARN(FL, "Unknown target build path: %s", folderPath() );
		return;
	}

	INFO(FL, "Checking path: %s", folderPath() );
	bool relinkRequired = false;

	// Main folder given
	for(auto file : folder->Files()){
		if(folderPath == "glob" && file->FileName() == "Jvm.cpp") continue; // Skip this one
#ifdef _WIN32
		if(folderPath == "server" && file->FileName() == "HelixDaemon.cpp") continue; // Skip this one
#else
		if(folderPath == "server" && file->FileName() == "HelixSvc.cpp") continue; // Skip this one
#endif
		if( (file->FileName().endsWith(".c") || file->FileName().endsWith(".cpp")) && file->NeedsRebuild( )){
			HelixWorker::getInstance().Add( new HelixCompileTask( folder, file ) );
			relinkRequired = true;
		}
	}

	// Check for a sqldo sub-folder
	HelixFSFolder sqldo = folder->FindFolder( "sqldo" );
	if(sqldo){
		for(auto file : sqldo->Files()){
			if( file->FileName().endsWith(".cpp") && file->NeedsRebuild( )){
				HelixWorker::getInstance().Add( new HelixCompileTask( sqldo, file ) );
				relinkRequired = true;
			}
		}
	}

	dptr<HelixLinkTask> linkTask = new HelixLinkTask( folder );
	if(relinkRequired || linkTask->RequiresLink()){
		HelixWorker::getInstance().Add( linkTask.release() );
	}

}

void HelixBuilder::Clean( const twine& folderPath )
{
	EnEx ee(FL, "HelixBuilder::Clean( const twine& folderPath )");

	// Some special cases
	if(folderPath == "HelixMain"){
		INFO(FL, "Cleaning HelixMain");
		CleanAllRuntime( "./bin" );
		return;
	} else if(folderPath == "HelixDaemon"){
		INFO(FL, "Cleaning HelixDaemon");
		CleanAllRuntime( "./bin" );
		return;
	}

	HelixFSFolder folder = HelixFS::getInstance().FindPath( folderPath );
	if(!folder){
		WARN(FL, "Unknown target build path: %s", folderPath() );
		return;
	}

	INFO(FL, "Cleaning path: %s", folderPath() );

	// Main folder given
	for(auto file : folder->Files()){
		if( file->FileName().endsWith(".c") || file->FileName().endsWith(".cpp") ){
			DEBUG(FL, "Cleaning File: %s/%s", file->FolderName()(), file->DotOh()() );
			File::Delete( folder->PhysicalFolderName() + "/" + file->DotOh() );
		}
	}
	CleanAllRuntime( folder->PhysicalFolderName() );

	// Check for a sqldo sub-folder
	HelixFSFolder sqldo = folder->FindFolder( "sqldo" );
	if(sqldo){
		for(auto file : sqldo->Files()){
			if( file->FileName().endsWith(".cpp") ){
				DEBUG(FL, "Cleaning File: %s/%s", file->FolderName()(), file->DotOh()() );
				File::Delete( sqldo->PhysicalFolderName() + "/" + file->DotOh() );
			}
		}
		CleanAllRuntime( sqldo->PhysicalFolderName() );
	}

	HelixLinkTask hlt( folder );
	twine linkTarget( hlt.LinkTarget() );
	if(!linkTarget.empty() && File::Exists( linkTarget ) ){
		DEBUG(FL, "Cleaning %s", linkTarget() );
		File::Delete( linkTarget );
	}

}

void HelixBuilder::CleanAllRuntime( const twine& physicalPath )
{
	EnEx ee(FL, "HelixBuilder::CleanAllRuntime( const twine& physicalPath )");

	auto files = File::listFiles( physicalPath );
	for(auto const& file : files){
		if(file.endsWith( ".exe" ) ||
			file.endsWith( ".dll" ) ||
			file.endsWith( ".lib" ) ||
			file.endsWith( ".exp" ) ||
			file.endsWith( ".obj" ) ||
			file.endsWith( ".o" ) ||
			file.endsWith( ".so" ) ||
			file == "AutoAsset" ||
			file == "CopyCommon" ||
			file == "CopyIcons" ||
			file == "ExtractStrings" ||
			file == "GenerateSqlClasses" ||
			file == "HelixDaemon" ||
			file == "HelixMain" ||
			file == "LogDump" ||
			file == "MakeMakefiles" ||
			file == "SLogDump" ||
			file == "SqlDoCheck" ||
			file == "SqlShell" ||
			file == "hbuild"
		){
			try {
				File::Delete( physicalPath + "/" + file );
			} catch (AnException& ){
				// Ignore this
			}
		}
	}
}

void HelixBuilder::BuildCS()
{
	EnEx ee(FL, "HelixBuilder::BuildCS()");

	if(HelixConfig::getInstance().SkipPdfGen() == true){
		return; // Don't do this one
	}

	if(HelixWorker::getInstance().HasError()){
		return; // Bail out early on any previous errors
	}

	INFO(FL, "Building HelixPdfGen" );
	twine pdfGen = "..\\c#\\HelixPdfGen";

	twine cmd;
	// Run the restore of all NuGet packages
	cmd = "cd " + pdfGen + " && c:\\software\\NuGet.exe restore HelixPdfGen.sln";
	if(std::system( cmd() ) != 0) throw AnException(0, FL, "C# - NuGet restore failed.");

	// Run the build of the project
	cmd = "cd " + pdfGen + " && msbuild HelixPdfGen.sln /p:Configuration=Release /p:Platform=\"Any CPU\" /t:Rebuild";
	if(std::system( cmd() ) != 0) throw AnException(0, FL, "C# - Build failed.");

	// Make sure we have the right output path created
	File::EnsurePath( "./HelixPdfGen/" );

	// Copy the release files over into our output folder
	for(auto& file : File::listFiles( pdfGen + "/HelixPdfGen/bin/Release" )){
		if(file.endsWith( ".dll" ) ||
			file.endsWith( ".exe" ) ||
			file.endsWith( ".xml" )
		){
			File::Copy( pdfGen + "/HelixPdfGen/bin/Release/" + file, "./HelixPdfGen/" + file );
		}
	}

}

void HelixBuilder::CleanCS()
{
	EnEx ee(FL, "HelixBuilder::CleanCS()");

	if(HelixConfig::getInstance().SkipPdfGen() == true){
		return; // Don't do this one
	}

	INFO(FL, "Cleaning HelixPdfGen" );
	twine pdfGen = "../c#/HelixPdfGen/HelixPdfGen/";

	// Several folders that we want to remove from the C# project:
	File::RmDir( pdfGen + "bin/" );
	File::RmDir( pdfGen + "obj/" );

	// Remove all cs files from the DO subfolders
	for(auto& folder : File::listFolders( pdfGen + "DO/" )){
		if(folder == "." || folder == "..") continue; // Skip these
		for(auto& file : File::listFiles( pdfGen + "DO/" + folder )){
			if(file.endsWith( ".cs" )){
				twine rmTarget( pdfGen + "DO/" + folder + "/" + file );
				INFO(FL, "Removing file: %s", rmTarget() );
				File::Delete( rmTarget );
			}
		}
	}
}

void HelixBuilder::GenerateSqldo(bool forceRegen)
{
	EnEx ee(FL, "HelixBuilder::GenerateSqldo(bool forceRegen)");

	// Find all .sql.xml files
	vector<HelixFSFile> allSqldo = HelixFS::getInstance().FindFilesByType( ".sql.xml" );

	twine currentFolderName;
	HelixFSFolder currentFolder = nullptr;
	HelixFSFolder currentSqldoFolder = nullptr;
	for(auto file : allSqldo){
		if(currentFolderName != file->FolderName()){
			// Look up the folder so we can access more details
			currentFolder = HelixFS::getInstance().FindPath( file->FolderName() );
			if(!currentFolder){
				throw AnException(0, FL, "Unable to find folder: %s\n", file->FolderName()() );
			}
			currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
			if(!currentSqldoFolder){
				currentFolder->SubFolders().push_back(
					std::make_shared<HelixFSFolder_Bare>( currentFolder->FolderName() + "/sqldo")
				);
				currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
				if(!currentSqldoFolder){
					throw AnException(0, FL, "Could not find new sqldo folder after adding it.");
				}
			}

			currentFolderName = file->FolderName();
		}

		// What's the data object being generated?  Usually matches the name of the .sql.xml file, but double-check
		twine doName( file->DataObjectName() );

		// Check our sql.xml file against the sqldo/cpp file
		HelixFSFile sqldoFile = currentSqldoFolder->FindFile( doName + ".cpp" );
		if( file->IsNewerThan( sqldoFile ) ){
			DEBUG(FL, "Data Object: %s is newer than .cpp - triggering regeneration.", file->PhysicalFileName()() );
			HelixWorker::getInstance().Add( new HelixGenTask( currentSqldoFolder, file ) );
		} else if(forceRegen){
			DEBUG(FL, "Data Object: %s - forcing regeneration.", file->PhysicalFileName()() );
			HelixWorker::getInstance().Add( new HelixGenTask( currentSqldoFolder, file ) );
		}

	}

	// Update the HelixPdfGen.csproj file to include references to all data objects
	if(HelixConfig::getInstance().SkipPdfGen() == false){
		UpdateHelixPdfGenProj( allSqldo );
	}

	// Wait for all generator threads to finish
	HelixWorker::getInstance().WaitForGenerators();
	if(HelixWorker::getInstance().HasError()){
		return;
	}

}

void HelixBuilder::GenerateJSApi()
{
	EnEx ee(FL, "HelixBuilder::GenerateJSApi()");

	HelixJSApiGenTask jsApiGen;
	for(auto app : HelixConfig::getInstance().QxApps()){
		jsApiGen.Generate( app );
	}

}

void HelixBuilder::UpdateHelixPdfGenProj(vector<HelixFSFile>& allSqldo)
{
	EnEx ee(FL, "HelixBuilder::UpdateHelixPdfGenProj(vector<HelixFSFile>& allSqldo)");

	bool modified = false;
	twine csprojName; csprojName = "../c#/HelixPdfGen/HelixPdfGen/HelixPdfGen.csproj";
	sptr<xmlDoc, xmlFreeDoc> csproj = xmlParseFile( csprojName() );
	if(csproj == nullptr){
		throw AnException(0, FL, "Error opening HelixPdfGen.csproj for update");
	}
	xmlNodePtr root = xmlDocGetRootElement( csproj );
	for(auto item : XmlHelpers::FindChildren( root, "ItemGroup" )){
		// Check to see if we have compile items in this group:
		xmlNodePtr check = XmlHelpers::FindChild( item, "Compile" );
		if(check == nullptr) continue; // Find another ItemGroup

		// Found compiles - check to ensure all of our sqldo items are present
		// If not, add them.
		for(auto sqldo : allSqldo){
			twine includeName( "DO\\" + sqldo->LastFolderName() + "\\" + sqldo->DataObjectName() + ".cs" );
			xmlNodePtr csInclude = XmlHelpers::FindChildWithAttribute( item, "Compile", "Include", includeName() );
			if(csInclude == nullptr){
				// Add it in:
				csInclude = xmlNewChild( item, NULL, (const xmlChar*)"Compile", NULL);
				xmlSetProp( csInclude, (const xmlChar*)"Include", includeName );
				modified = true;
			}
		}
		break; // We found the ItemGroup with compiles in it - no need to keep searching the file
	}

	if(modified){
		// Save the updated file:
		xmlSaveFile( csprojName(), csproj );
	}
}

void HelixBuilder::CleanSqldo()
{
	EnEx ee(FL, "HelixBuilder::CleanSqldo()");
	INFO(FL, "Cleaning Sqldo" );

	// Find all .sql.xml files
	vector<HelixFSFile> allSqldo = HelixFS::getInstance().FindFilesByType( ".sql.xml" );

	twine currentFolderName;
	HelixFSFolder currentFolder;
	HelixFSFolder currentSqldoFolder;
	for(auto file : allSqldo){
		if(currentFolderName != file->FolderName()){
			// Look up the folder so we can access more details
			currentFolder = HelixFS::getInstance().FindPath( file->FolderName() );
			if(!currentFolder){
				throw AnException(0, FL, "Unable to find folder: %s\n", file->FolderName()() );
			}
			currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
			if(!currentSqldoFolder){
				currentFolder->SubFolders().push_back(
					std::make_shared<HelixFSFolder_Bare>( currentFolder->FolderName() + "/sqldo")
				);
				currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
				if(!currentSqldoFolder){
					throw AnException(0, FL, "Could not find new sqldo folder after adding it.");
				}
			}

			currentFolderName = file->FolderName();
		}

		// What's the data object being generated?  Usually matches the name of the .sql.xml file, but double-check
		twine doName( file->DataObjectName() );

		// Remove the h and cpp file
		DEBUG(FL, "Removing Generated SqlDo File: %s.h and %s.cpp", doName(), doName() );
		currentSqldoFolder->DeleteFile( doName + ".h" );
		currentSqldoFolder->DeleteFile( doName + ".cpp" );
	}
}

<commit_msg>Copy HelixPdfGen into bin/ not into ./<commit_after>/* **************************************************************************

   Copyright (c): 2008 - 2013 Hericus Software, LLC

   License: The MIT License (MIT)

   Authors: Steven M. Cherry

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

#include <cstdlib>

#include <AnException.h>
#include <EnEx.h>
#include <Log.h>
#include <XmlHelpers.h>
#include <Timer.h>
#include <Tools.h>
using namespace SLib;

#include "HelixFS.h"
#include "HelixConfig.h"
#include "HelixBuilder.h"
#include "HelixWorker.h"
#include "HelixJSApiGenTask.h"
using namespace Helix::Build;

HelixBuilder::HelixBuilder()
{
	EnEx ee(FL, "HelixBuilder::HelixBuilder( HelixFS& helixfs )");

}

HelixBuilder::~HelixBuilder()
{
	EnEx ee(FL, "HelixBuilder::~HelixBuilder()");

}

void HelixBuilder::Build( const twine& folderPath )
{
	EnEx ee(FL, "HelixBuilder::Build( const twine& folderPath )");

	if(HelixWorker::getInstance().HasError()){
		return; // Bail out early on any previous errors
	}

	// Some special cases
	if(folderPath == "HelixMain" || folderPath == "HelixDaemon"){
		dptr<HelixLinkTask> lt = new HelixLinkTask( std::make_shared<HelixFSFolder_Bare>(folderPath)  );
		if(lt->RequiresLink()){
			HelixWorker::getInstance().Add( lt.release() );
		}
		return;
	}

	HelixFSFolder folder = HelixFS::getInstance().FindPath( folderPath );
	if(!folder){
		WARN(FL, "Unknown target build path: %s", folderPath() );
		return;
	}

	INFO(FL, "Checking path: %s", folderPath() );
	bool relinkRequired = false;

	// Main folder given
	for(auto file : folder->Files()){
		if(folderPath == "glob" && file->FileName() == "Jvm.cpp") continue; // Skip this one
#ifdef _WIN32
		if(folderPath == "server" && file->FileName() == "HelixDaemon.cpp") continue; // Skip this one
#else
		if(folderPath == "server" && file->FileName() == "HelixSvc.cpp") continue; // Skip this one
#endif
		if( (file->FileName().endsWith(".c") || file->FileName().endsWith(".cpp")) && file->NeedsRebuild( )){
			HelixWorker::getInstance().Add( new HelixCompileTask( folder, file ) );
			relinkRequired = true;
		}
	}

	// Check for a sqldo sub-folder
	HelixFSFolder sqldo = folder->FindFolder( "sqldo" );
	if(sqldo){
		for(auto file : sqldo->Files()){
			if( file->FileName().endsWith(".cpp") && file->NeedsRebuild( )){
				HelixWorker::getInstance().Add( new HelixCompileTask( sqldo, file ) );
				relinkRequired = true;
			}
		}
	}

	dptr<HelixLinkTask> linkTask = new HelixLinkTask( folder );
	if(relinkRequired || linkTask->RequiresLink()){
		HelixWorker::getInstance().Add( linkTask.release() );
	}

}

void HelixBuilder::Clean( const twine& folderPath )
{
	EnEx ee(FL, "HelixBuilder::Clean( const twine& folderPath )");

	// Some special cases
	if(folderPath == "HelixMain"){
		INFO(FL, "Cleaning HelixMain");
		CleanAllRuntime( "./bin" );
		return;
	} else if(folderPath == "HelixDaemon"){
		INFO(FL, "Cleaning HelixDaemon");
		CleanAllRuntime( "./bin" );
		return;
	}

	HelixFSFolder folder = HelixFS::getInstance().FindPath( folderPath );
	if(!folder){
		WARN(FL, "Unknown target build path: %s", folderPath() );
		return;
	}

	INFO(FL, "Cleaning path: %s", folderPath() );

	// Main folder given
	for(auto file : folder->Files()){
		if( file->FileName().endsWith(".c") || file->FileName().endsWith(".cpp") ){
			DEBUG(FL, "Cleaning File: %s/%s", file->FolderName()(), file->DotOh()() );
			File::Delete( folder->PhysicalFolderName() + "/" + file->DotOh() );
		}
	}
	CleanAllRuntime( folder->PhysicalFolderName() );

	// Check for a sqldo sub-folder
	HelixFSFolder sqldo = folder->FindFolder( "sqldo" );
	if(sqldo){
		for(auto file : sqldo->Files()){
			if( file->FileName().endsWith(".cpp") ){
				DEBUG(FL, "Cleaning File: %s/%s", file->FolderName()(), file->DotOh()() );
				File::Delete( sqldo->PhysicalFolderName() + "/" + file->DotOh() );
			}
		}
		CleanAllRuntime( sqldo->PhysicalFolderName() );
	}

	HelixLinkTask hlt( folder );
	twine linkTarget( hlt.LinkTarget() );
	if(!linkTarget.empty() && File::Exists( linkTarget ) ){
		DEBUG(FL, "Cleaning %s", linkTarget() );
		File::Delete( linkTarget );
	}

}

void HelixBuilder::CleanAllRuntime( const twine& physicalPath )
{
	EnEx ee(FL, "HelixBuilder::CleanAllRuntime( const twine& physicalPath )");

	auto files = File::listFiles( physicalPath );
	for(auto const& file : files){
		if(file.endsWith( ".exe" ) ||
			file.endsWith( ".dll" ) ||
			file.endsWith( ".lib" ) ||
			file.endsWith( ".exp" ) ||
			file.endsWith( ".obj" ) ||
			file.endsWith( ".o" ) ||
			file.endsWith( ".so" ) ||
			file == "AutoAsset" ||
			file == "CopyCommon" ||
			file == "CopyIcons" ||
			file == "ExtractStrings" ||
			file == "GenerateSqlClasses" ||
			file == "HelixDaemon" ||
			file == "HelixMain" ||
			file == "LogDump" ||
			file == "MakeMakefiles" ||
			file == "SLogDump" ||
			file == "SqlDoCheck" ||
			file == "SqlShell" ||
			file == "hbuild"
		){
			try {
				File::Delete( physicalPath + "/" + file );
			} catch (AnException& ){
				// Ignore this
			}
		}
	}
}

void HelixBuilder::BuildCS()
{
	EnEx ee(FL, "HelixBuilder::BuildCS()");

	if(HelixConfig::getInstance().SkipPdfGen() == true){
		return; // Don't do this one
	}

	if(HelixWorker::getInstance().HasError()){
		return; // Bail out early on any previous errors
	}

	INFO(FL, "Building HelixPdfGen" );
	twine pdfGen = "..\\c#\\HelixPdfGen";

	twine cmd;
	// Run the restore of all NuGet packages
	cmd = "cd " + pdfGen + " && c:\\software\\NuGet.exe restore HelixPdfGen.sln";
	if(std::system( cmd() ) != 0) throw AnException(0, FL, "C# - NuGet restore failed.");

	// Run the build of the project
	cmd = "cd " + pdfGen + " && msbuild HelixPdfGen.sln /p:Configuration=Release /p:Platform=\"Any CPU\" /t:Rebuild";
	if(std::system( cmd() ) != 0) throw AnException(0, FL, "C# - Build failed.");

	// Make sure we have the right output path created
	File::EnsurePath( "./bin/HelixPdfGen/" );

	// Copy the release files over into our output folder
	for(auto& file : File::listFiles( pdfGen + "/HelixPdfGen/bin/Release" )){
		if(file.endsWith( ".dll" ) ||
			file.endsWith( ".exe" ) ||
			file.endsWith( ".xml" )
		){
			File::Copy( pdfGen + "/HelixPdfGen/bin/Release/" + file, "./bin/HelixPdfGen/" + file );
		}
	}

}

void HelixBuilder::CleanCS()
{
	EnEx ee(FL, "HelixBuilder::CleanCS()");

	if(HelixConfig::getInstance().SkipPdfGen() == true){
		return; // Don't do this one
	}

	INFO(FL, "Cleaning HelixPdfGen" );
	twine pdfGen = "../c#/HelixPdfGen/HelixPdfGen/";

	// Several folders that we want to remove from the C# project:
	File::RmDir( pdfGen + "bin/" );
	File::RmDir( pdfGen + "obj/" );

	// Remove all cs files from the DO subfolders
	for(auto& folder : File::listFolders( pdfGen + "DO/" )){
		if(folder == "." || folder == "..") continue; // Skip these
		for(auto& file : File::listFiles( pdfGen + "DO/" + folder )){
			if(file.endsWith( ".cs" )){
				twine rmTarget( pdfGen + "DO/" + folder + "/" + file );
				INFO(FL, "Removing file: %s", rmTarget() );
				File::Delete( rmTarget );
			}
		}
	}
}

void HelixBuilder::GenerateSqldo(bool forceRegen)
{
	EnEx ee(FL, "HelixBuilder::GenerateSqldo(bool forceRegen)");

	// Find all .sql.xml files
	vector<HelixFSFile> allSqldo = HelixFS::getInstance().FindFilesByType( ".sql.xml" );

	twine currentFolderName;
	HelixFSFolder currentFolder = nullptr;
	HelixFSFolder currentSqldoFolder = nullptr;
	for(auto file : allSqldo){
		if(currentFolderName != file->FolderName()){
			// Look up the folder so we can access more details
			currentFolder = HelixFS::getInstance().FindPath( file->FolderName() );
			if(!currentFolder){
				throw AnException(0, FL, "Unable to find folder: %s\n", file->FolderName()() );
			}
			currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
			if(!currentSqldoFolder){
				currentFolder->SubFolders().push_back(
					std::make_shared<HelixFSFolder_Bare>( currentFolder->FolderName() + "/sqldo")
				);
				currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
				if(!currentSqldoFolder){
					throw AnException(0, FL, "Could not find new sqldo folder after adding it.");
				}
			}

			currentFolderName = file->FolderName();
		}

		// What's the data object being generated?  Usually matches the name of the .sql.xml file, but double-check
		twine doName( file->DataObjectName() );

		// Check our sql.xml file against the sqldo/cpp file
		HelixFSFile sqldoFile = currentSqldoFolder->FindFile( doName + ".cpp" );
		if( file->IsNewerThan( sqldoFile ) ){
			DEBUG(FL, "Data Object: %s is newer than .cpp - triggering regeneration.", file->PhysicalFileName()() );
			HelixWorker::getInstance().Add( new HelixGenTask( currentSqldoFolder, file ) );
		} else if(forceRegen){
			DEBUG(FL, "Data Object: %s - forcing regeneration.", file->PhysicalFileName()() );
			HelixWorker::getInstance().Add( new HelixGenTask( currentSqldoFolder, file ) );
		}

	}

	// Update the HelixPdfGen.csproj file to include references to all data objects
	if(HelixConfig::getInstance().SkipPdfGen() == false){
		UpdateHelixPdfGenProj( allSqldo );
	}

	// Wait for all generator threads to finish
	HelixWorker::getInstance().WaitForGenerators();
	if(HelixWorker::getInstance().HasError()){
		return;
	}

}

void HelixBuilder::GenerateJSApi()
{
	EnEx ee(FL, "HelixBuilder::GenerateJSApi()");

	HelixJSApiGenTask jsApiGen;
	for(auto app : HelixConfig::getInstance().QxApps()){
		jsApiGen.Generate( app );
	}

}

void HelixBuilder::UpdateHelixPdfGenProj(vector<HelixFSFile>& allSqldo)
{
	EnEx ee(FL, "HelixBuilder::UpdateHelixPdfGenProj(vector<HelixFSFile>& allSqldo)");

	bool modified = false;
	twine csprojName; csprojName = "../c#/HelixPdfGen/HelixPdfGen/HelixPdfGen.csproj";
	sptr<xmlDoc, xmlFreeDoc> csproj = xmlParseFile( csprojName() );
	if(csproj == nullptr){
		throw AnException(0, FL, "Error opening HelixPdfGen.csproj for update");
	}
	xmlNodePtr root = xmlDocGetRootElement( csproj );
	for(auto item : XmlHelpers::FindChildren( root, "ItemGroup" )){
		// Check to see if we have compile items in this group:
		xmlNodePtr check = XmlHelpers::FindChild( item, "Compile" );
		if(check == nullptr) continue; // Find another ItemGroup

		// Found compiles - check to ensure all of our sqldo items are present
		// If not, add them.
		for(auto sqldo : allSqldo){
			twine includeName( "DO\\" + sqldo->LastFolderName() + "\\" + sqldo->DataObjectName() + ".cs" );
			xmlNodePtr csInclude = XmlHelpers::FindChildWithAttribute( item, "Compile", "Include", includeName() );
			if(csInclude == nullptr){
				// Add it in:
				csInclude = xmlNewChild( item, NULL, (const xmlChar*)"Compile", NULL);
				xmlSetProp( csInclude, (const xmlChar*)"Include", includeName );
				modified = true;
			}
		}
		break; // We found the ItemGroup with compiles in it - no need to keep searching the file
	}

	if(modified){
		// Save the updated file:
		xmlSaveFile( csprojName(), csproj );
	}
}

void HelixBuilder::CleanSqldo()
{
	EnEx ee(FL, "HelixBuilder::CleanSqldo()");
	INFO(FL, "Cleaning Sqldo" );

	// Find all .sql.xml files
	vector<HelixFSFile> allSqldo = HelixFS::getInstance().FindFilesByType( ".sql.xml" );

	twine currentFolderName;
	HelixFSFolder currentFolder;
	HelixFSFolder currentSqldoFolder;
	for(auto file : allSqldo){
		if(currentFolderName != file->FolderName()){
			// Look up the folder so we can access more details
			currentFolder = HelixFS::getInstance().FindPath( file->FolderName() );
			if(!currentFolder){
				throw AnException(0, FL, "Unable to find folder: %s\n", file->FolderName()() );
			}
			currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
			if(!currentSqldoFolder){
				currentFolder->SubFolders().push_back(
					std::make_shared<HelixFSFolder_Bare>( currentFolder->FolderName() + "/sqldo")
				);
				currentSqldoFolder = currentFolder->FindFolder( "sqldo" );
				if(!currentSqldoFolder){
					throw AnException(0, FL, "Could not find new sqldo folder after adding it.");
				}
			}

			currentFolderName = file->FolderName();
		}

		// What's the data object being generated?  Usually matches the name of the .sql.xml file, but double-check
		twine doName( file->DataObjectName() );

		// Remove the h and cpp file
		DEBUG(FL, "Removing Generated SqlDo File: %s.h and %s.cpp", doName(), doName() );
		currentSqldoFolder->DeleteFile( doName + ".h" );
		currentSqldoFolder->DeleteFile( doName + ".cpp" );
	}
}

<|endoftext|>


<commit_before>// Copyright (C) 2008  Timothy Moore timoore@redhat.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <osg/StateSet>
#include <osg/Texture2D>

#include "EffectCullVisitor.hxx"

#include "EffectGeode.hxx"
#include "Effect.hxx"
#include "Technique.hxx"

#include <scene\util\RenderConstants.hxx>

namespace simgear
{

using osgUtil::CullVisitor;

EffectCullVisitor::EffectCullVisitor(bool collectLights) :
    _collectLights(collectLights)
{
}

EffectCullVisitor::EffectCullVisitor(const EffectCullVisitor& rhs) :
    osg::Referenced(rhs),
    CullVisitor(rhs)
{
}

CullVisitor* EffectCullVisitor::clone() const
{
    return new EffectCullVisitor(*this);
}

void EffectCullVisitor::apply(osg::Geode& node)
{
    if (isCulled(node))
        return;
    EffectGeode *eg = dynamic_cast<EffectGeode*>(&node);
    if (!eg) {
        CullVisitor::apply(node);
        return;
    }
    if (_collectLights && ( eg->getNodeMask() & MODELLIGHT_BIT ) ) {
        _lightList.push_back( eg );
    }
    Effect* effect = eg->getEffect();
    Technique* technique = 0;
    if (!effect) {
        CullVisitor::apply(node);
        return;
    } else if (!(technique = effect->chooseTechnique(&getRenderInfo()))) {
        return;
    }
    // push the node's state.
    osg::StateSet* node_state = node.getStateSet();
    if (node_state)
        pushStateSet(node_state);
    for (EffectGeode::DrawablesIterator beginItr = eg->drawablesBegin(),
             e = eg->drawablesEnd();
         beginItr != e;
         beginItr = technique->processDrawables(beginItr, e, this,
                                                eg->isCullingActive()))
        ;
    // pop the node's state off the geostate stack.
    if (node_state)
        popStateSet();

}

void EffectCullVisitor::reset()
{
    _lightList.clear();

    osgUtil::CullVisitor::reset();
}

void EffectCullVisitor::clearBufferList()
{
    _bufferList.clear();
}

void EffectCullVisitor::addBuffer(int i, osg::Texture2D* tex)
{
    _bufferList.insert(std::make_pair(i,tex));
}

osg::Texture2D* EffectCullVisitor::getBuffer(int i)
{
    return _bufferList[i];
}

}
<commit_msg>Fix path in include directive<commit_after>// Copyright (C) 2008  Timothy Moore timoore@redhat.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifdef HAVE_CONFIG_H
#  include <simgear_config.h>
#endif

#include <osg/StateSet>
#include <osg/Texture2D>

#include "EffectCullVisitor.hxx"

#include "EffectGeode.hxx"
#include "Effect.hxx"
#include "Technique.hxx"

#include <simgear/scene/util/RenderConstants.hxx>

namespace simgear
{

using osgUtil::CullVisitor;

EffectCullVisitor::EffectCullVisitor(bool collectLights) :
    _collectLights(collectLights)
{
}

EffectCullVisitor::EffectCullVisitor(const EffectCullVisitor& rhs) :
    osg::Referenced(rhs),
    CullVisitor(rhs)
{
}

CullVisitor* EffectCullVisitor::clone() const
{
    return new EffectCullVisitor(*this);
}

void EffectCullVisitor::apply(osg::Geode& node)
{
    if (isCulled(node))
        return;
    EffectGeode *eg = dynamic_cast<EffectGeode*>(&node);
    if (!eg) {
        CullVisitor::apply(node);
        return;
    }
    if (_collectLights && ( eg->getNodeMask() & MODELLIGHT_BIT ) ) {
        _lightList.push_back( eg );
    }
    Effect* effect = eg->getEffect();
    Technique* technique = 0;
    if (!effect) {
        CullVisitor::apply(node);
        return;
    } else if (!(technique = effect->chooseTechnique(&getRenderInfo()))) {
        return;
    }
    // push the node's state.
    osg::StateSet* node_state = node.getStateSet();
    if (node_state)
        pushStateSet(node_state);
    for (EffectGeode::DrawablesIterator beginItr = eg->drawablesBegin(),
             e = eg->drawablesEnd();
         beginItr != e;
         beginItr = technique->processDrawables(beginItr, e, this,
                                                eg->isCullingActive()))
        ;
    // pop the node's state off the geostate stack.
    if (node_state)
        popStateSet();

}

void EffectCullVisitor::reset()
{
    _lightList.clear();

    osgUtil::CullVisitor::reset();
}

void EffectCullVisitor::clearBufferList()
{
    _bufferList.clear();
}

void EffectCullVisitor::addBuffer(int i, osg::Texture2D* tex)
{
    _bufferList.insert(std::make_pair(i,tex));
}

osg::Texture2D* EffectCullVisitor::getBuffer(int i)
{
    return _bufferList[i];
}

}
<|endoftext|>


<commit_before>#include "caffe2/operators/lengths_top_k_op.h"

namespace caffe2 {

template <typename T, class Context>
bool LengthsTopKOp<T, Context>::RunOnDevice() {
  auto& X = Input(X_IN);
  auto& Y = Input(Y_IN);
  auto N = Y.dim(0);
  const T* X_data = X.template data<T>();
  const int* input_len = Y.template data<int>();
  auto* output_topk_values = Output(TOPK_VALUES_OUT);
  auto* output_topk_indices = Output(TOPK_INDICES_OUT);

  output_topk_values->Resize(N * k_);
  output_topk_indices->Resize(N * k_);
  std::vector<int> output_dims = std::vector<int>({N, k_});
  output_topk_values->Reshape(output_dims);
  output_topk_indices->Reshape(output_dims);
  T* output_topk_values_data = output_topk_values->template mutable_data<T>();
  int* output_topk_indices_data =
      output_topk_indices->template mutable_data<int>();

  auto cmp = [](std::pair<T, TIndex>& lhs, std::pair<T, TIndex>& rhs) {
    return lhs.first > rhs.first ||
        (lhs.first == rhs.first && lhs.second < rhs.second);
  };

  // Sort preserving indices
  int next_index = 0;
  for (TIndex i = 0; i < N; ++i) {
    // Build a min-heap, the heap element is pair of (value, idx)
    // the top of the heap is the smallest value
    std::priority_queue<
        std::pair<T, TIndex>,
        std::vector<std::pair<T, TIndex>>,
        decltype(cmp)>
        p_queue(cmp);

    // Maintain the size of heap to be less or equal to k_, so the
    // heap will hold the k_ largest values
    for (TIndex j = 0; j < input_len[i]; ++j) {
      const auto value = X_data[next_index++];
      if (p_queue.size() < k_ || value > p_queue.top().first) {
        p_queue.push(std::make_pair(value, j));
      }
      if (p_queue.size() > k_) {
        p_queue.pop();
      }
    }

    int last_index = p_queue.size();
    for (TIndex j = 0; j < k_; ++j) {
      if (p_queue.size() > 0) {
        auto& pqElem = p_queue.top();
        output_topk_values_data[i * k_ + last_index - j - 1] = pqElem.first;
        output_topk_indices_data[i * k_ + last_index - j - 1] = pqElem.second;
        p_queue.pop();
      } else {
        output_topk_values_data[i * k_ + j] = 0;
        output_topk_indices_data[i * k_ + j] = -1;
      }
    }
  }

  return true;
}

template <typename T, class Context>
bool LengthsTopKGradientOp<T, Context>::RunOnDevice() {
  auto& input_len = Input(LENGTH_IN);
  int N = input_len.size();
  auto& input_indices = Input(INDICES_IN);
  CAFFE_ENFORCE_GE(input_indices.ndim(), 2, "input dim must be >= 2");
  CAFFE_ENFORCE_EQ(
      input_indices.size(), N * k_, "input_indices shape is not correct");
  auto& input_topk = Input(DER_TOPK_IN);
  CAFFE_ENFORCE_EQ(
      input_topk.size(), N * k_, "input_topk shape is not correct");
  auto* X_out = Output(DER_X_OUT);

  const int* input_len_data = input_len.template data<int>();
  const int* input_indices_data = input_indices.template data<int>();
  const T* input_topk_data = input_topk.template data<T>();

  int num_indices = 0;
  for (int i = 0; i < N; i++) {
    num_indices += input_len_data[i];
  }
  X_out->Resize(num_indices);
  std::vector<int> output_dims = std::vector<int>({num_indices});
  X_out->Reshape(output_dims);
  T* X_out_data = X_out->template mutable_data<T>();
  math::Set<T, Context>(num_indices, 0.0, X_out_data, &context_);

  int index_offset = 0;
  for (int i = 0; i < N; i++) {
    for (int j = 0; j < std::min(input_len_data[i], k_); j++) {
      int cur_index = index_offset + input_indices_data[i * k_ + j];
      CAFFE_ENFORCE_LT(
          cur_index, num_indices, "cur_index should be less than num_indices");
      X_out_data[cur_index] = input_topk_data[i * k_ + j];
    }
    index_offset += input_len_data[i];
  }

  return true;
}

REGISTER_CPU_OPERATOR(LengthsTopK, LengthsTopKOp<float, CPUContext>);
REGISTER_CPU_OPERATOR(
    LengthsTopKGradient,
    LengthsTopKGradientOp<float, CPUContext>);
OPERATOR_SCHEMA(LengthsTopK)
    .NumInputs(2)
    .NumOutputs(2)
    .SetDoc(R"DOC(
Apply TopK to each segment of the input tensor, where segments are defined by
their LENGTHS, and concatenate them in an output tensor of
shape=(SIZE(LENGTHs), k). In case there's less than k values in a segment,
the output value will be padded by 0, and the corresponding output indices will
be padded by -1.
)DOC")
    .Input(
        0,
        "DATA",
        "Tensor of rank 1. First dimension must be equal to the sum of "
        "lengths")
    .Input(1, "LENGTHS", "Tensor of int32 lengths of rank 1")
    .Output(
        0,
        "TopKValue",
        "Output top k elements for each segment, with"
        "shape=(SIZE(lengths), k)")
    .Output(
        1,
        "TopKIndices",
        "Output indices in DATA corresponding to value in TopKValue")
    .Arg(
        "k",
        "the number of top values to return for each segment, if the number "
        "of values is smaller than k, the values would be padded with 0 and "
        "indices would be padded with -1.");
OPERATOR_SCHEMA(LengthsTopKGradient).NumInputs(3).NumOutputs(1);

namespace {

class GetLengthsTopKGradient : public GradientMakerBase {
  using GradientMakerBase::GradientMakerBase;
  vector<OperatorDef> GetGradientDefs() override {
    return SingleGradientDef(
        "LengthsTopKGradient",
        "",
        vector<string>{I(1), O(1), GO(0)},
        vector<string>{GI(0)});
  }
};

} // namespace

REGISTER_GRADIENT(LengthsTopK, GetLengthsTopKGradient);
} // namespace caffe2
<commit_msg>fix Windows build breaks by LengthsTopKOp<commit_after>#include "caffe2/operators/lengths_top_k_op.h"

namespace caffe2 {

template <typename T, class Context>
bool LengthsTopKOp<T, Context>::RunOnDevice() {
  auto& X = Input(X_IN);
  auto& Y = Input(Y_IN);
  int N = Y.dim32(0);
  const T* X_data = X.template data<T>();
  const int* input_len = Y.template data<int>();
  auto* output_topk_values = Output(TOPK_VALUES_OUT);
  auto* output_topk_indices = Output(TOPK_INDICES_OUT);

  output_topk_values->Resize(N * k_);
  output_topk_indices->Resize(N * k_);
  std::vector<int> output_dims = std::vector<int>({N, k_});
  output_topk_values->Reshape(output_dims);
  output_topk_indices->Reshape(output_dims);
  T* output_topk_values_data = output_topk_values->template mutable_data<T>();
  int* output_topk_indices_data =
      output_topk_indices->template mutable_data<int>();

  auto cmp = [](std::pair<T, TIndex>& lhs, std::pair<T, TIndex>& rhs) {
    return lhs.first > rhs.first ||
        (lhs.first == rhs.first && lhs.second < rhs.second);
  };

  // Sort preserving indices
  int next_index = 0;
  for (TIndex i = 0; i < N; ++i) {
    // Build a min-heap, the heap element is pair of (value, idx)
    // the top of the heap is the smallest value
    std::priority_queue<
        std::pair<T, TIndex>,
        std::vector<std::pair<T, TIndex>>,
        decltype(cmp)>
        p_queue(cmp);

    // Maintain the size of heap to be less or equal to k_, so the
    // heap will hold the k_ largest values
    for (TIndex j = 0; j < input_len[i]; ++j) {
      const auto value = X_data[next_index++];
      if (p_queue.size() < k_ || value > p_queue.top().first) {
        p_queue.push(std::make_pair(value, j));
      }
      if (p_queue.size() > k_) {
        p_queue.pop();
      }
    }

    int last_index = p_queue.size();
    for (TIndex j = 0; j < k_; ++j) {
      if (p_queue.size() > 0) {
        auto& pqElem = p_queue.top();
        output_topk_values_data[i * k_ + last_index - j - 1] = pqElem.first;
        output_topk_indices_data[i * k_ + last_index - j - 1] = pqElem.second;
        p_queue.pop();
      } else {
        output_topk_values_data[i * k_ + j] = 0;
        output_topk_indices_data[i * k_ + j] = -1;
      }
    }
  }

  return true;
}

template <typename T, class Context>
bool LengthsTopKGradientOp<T, Context>::RunOnDevice() {
  auto& input_len = Input(LENGTH_IN);
  int N = input_len.size();
  auto& input_indices = Input(INDICES_IN);
  CAFFE_ENFORCE_GE(input_indices.ndim(), 2, "input dim must be >= 2");
  CAFFE_ENFORCE_EQ(
      input_indices.size(), N * k_, "input_indices shape is not correct");
  auto& input_topk = Input(DER_TOPK_IN);
  CAFFE_ENFORCE_EQ(
      input_topk.size(), N * k_, "input_topk shape is not correct");
  auto* X_out = Output(DER_X_OUT);

  const int* input_len_data = input_len.template data<int>();
  const int* input_indices_data = input_indices.template data<int>();
  const T* input_topk_data = input_topk.template data<T>();

  int num_indices = 0;
  for (int i = 0; i < N; i++) {
    num_indices += input_len_data[i];
  }
  X_out->Resize(num_indices);
  std::vector<int> output_dims = std::vector<int>({num_indices});
  X_out->Reshape(output_dims);
  T* X_out_data = X_out->template mutable_data<T>();
  math::Set<T, Context>(num_indices, 0.0, X_out_data, &context_);

  int index_offset = 0;
  for (int i = 0; i < N; i++) {
    for (int j = 0; j < std::min(input_len_data[i], k_); j++) {
      int cur_index = index_offset + input_indices_data[i * k_ + j];
      CAFFE_ENFORCE_LT(
          cur_index, num_indices, "cur_index should be less than num_indices");
      X_out_data[cur_index] = input_topk_data[i * k_ + j];
    }
    index_offset += input_len_data[i];
  }

  return true;
}

REGISTER_CPU_OPERATOR(LengthsTopK, LengthsTopKOp<float, CPUContext>);
REGISTER_CPU_OPERATOR(
    LengthsTopKGradient,
    LengthsTopKGradientOp<float, CPUContext>);
OPERATOR_SCHEMA(LengthsTopK)
    .NumInputs(2)
    .NumOutputs(2)
    .SetDoc(R"DOC(
Apply TopK to each segment of the input tensor, where segments are defined by
their LENGTHS, and concatenate them in an output tensor of
shape=(SIZE(LENGTHs), k). In case there's less than k values in a segment,
the output value will be padded by 0, and the corresponding output indices will
be padded by -1.
)DOC")
    .Input(
        0,
        "DATA",
        "Tensor of rank 1. First dimension must be equal to the sum of "
        "lengths")
    .Input(1, "LENGTHS", "Tensor of int32 lengths of rank 1")
    .Output(
        0,
        "TopKValue",
        "Output top k elements for each segment, with"
        "shape=(SIZE(lengths), k)")
    .Output(
        1,
        "TopKIndices",
        "Output indices in DATA corresponding to value in TopKValue")
    .Arg(
        "k",
        "the number of top values to return for each segment, if the number "
        "of values is smaller than k, the values would be padded with 0 and "
        "indices would be padded with -1.");
OPERATOR_SCHEMA(LengthsTopKGradient).NumInputs(3).NumOutputs(1);

namespace {

class GetLengthsTopKGradient : public GradientMakerBase {
  using GradientMakerBase::GradientMakerBase;
  vector<OperatorDef> GetGradientDefs() override {
    return SingleGradientDef(
        "LengthsTopKGradient",
        "",
        vector<string>{I(1), O(1), GO(0)},
        vector<string>{GI(0)});
  }
};

} // namespace

REGISTER_GRADIENT(LengthsTopK, GetLengthsTopKGradient);
} // namespace caffe2
<|endoftext|>


<commit_before>// Copyright (C) 2017 Rob Caelers <rob.caelers@gmail.com>
//
// 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.

#ifndef OS_SLOT_HPP
#define OS_SLOT_HPP

#include "os/MainLoop.hpp"
#include "os/Closure.hpp"
#include "os/lambda.hpp"

namespace os
{
  template <typename T>
  class Slot;

  template<typename... Args>
  class Slot<void(Args...)>
  {
  private:
    using callback_type = std::function<void(Args...)>;
    using closure_type = os::Closure<callback_type, Args...>;

  public:
    Slot(std::shared_ptr<os::MainLoop> loop, callback_type callback)
      : loop(loop), callback(callback)
    {
    }

    Slot(const Slot&) = default;
    Slot &operator=(const Slot&) = default;

    Slot(Slot &&lhs)
      : loop(lhs.loop),
        callback(std::move(lhs.callback))
    {
    }

    Slot &operator=(Slot &&lhs)
    {
      if (this != &lhs)
        {
          loop = lhs.loop;
          callback = std::move(lhs.callback);
        }
      return *this;
    }

    void call(Args... args) const
    {
      if (loop)
        {
          loop->post(std::make_shared<closure_type>(callback, std::move(args)...));
        }
      else
        {
          callback(std::move(args)...);
        }
    }

  private:
    std::shared_ptr<os::MainLoop> loop;
    std::function<void(Args...)> callback;
  };

  template<typename F>
  auto make_slot(std::shared_ptr<os::MainLoop> loop, F &&func)
  {
    using fpointer_type = get_signature<F>;

    return Slot<fpointer_type>(loop, std::forward<std::function<fpointer_type>>(func));
  }

}

#endif // OS_SLOT_HPP
<commit_msg>Allow empty slot<commit_after>// Copyright (C) 2017 Rob Caelers <rob.caelers@gmail.com>
//
// 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.

#ifndef OS_SLOT_HPP
#define OS_SLOT_HPP

#include "os/MainLoop.hpp"
#include "os/Closure.hpp"
#include "os/lambda.hpp"

namespace os
{
  template <typename T>
  class Slot;

  template<typename... Args>
  class Slot<void(Args...)>
  {
  private:
    using callback_type = std::function<void(Args...)>;
    using closure_type = os::Closure<callback_type, Args...>;

  public:
    Slot() = default;

    Slot(std::shared_ptr<os::MainLoop> loop, callback_type callback)
      : loop(loop), callback(callback)
    {
    }

    Slot(const Slot&) = default;
    Slot &operator=(const Slot&) = default;

    Slot(Slot &&lhs)
      : loop(lhs.loop),
        callback(std::move(lhs.callback))
    {
    }

    Slot &operator=(Slot &&lhs)
    {
      if (this != &lhs)
        {
          loop = lhs.loop;
          callback = std::move(lhs.callback);
        }
      return *this;
    }

    void call(Args... args) const
    {
      if (callback)
        {
          if (loop)
            {
              loop->post(std::make_shared<closure_type>(callback, std::move(args)...));
            }
          else
            {
              callback(std::move(args)...);
            }
        }
    }

  private:
    std::shared_ptr<os::MainLoop> loop;
    std::function<void(Args...)> callback;
  };

  template<typename F>
  auto make_slot(std::shared_ptr<os::MainLoop> loop, F &&func)
  {
    using fpointer_type = get_signature<F>;

    return Slot<fpointer_type>(loop, std::forward<std::function<fpointer_type>>(func));
  }

}

#endif // OS_SLOT_HPP
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <GL3DBarChart.hxx>

#include <GL/glew.h>

#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>

#include "3DChartObjects.hxx"
#include "GL3DRenderer.hxx"
#include <ExplicitCategoriesProvider.hxx>
#include <DataSeriesHelper.hxx>

using namespace com::sun::star;

namespace chart {

GL3DBarChart::GL3DBarChart(
    const css::uno::Reference<css::chart2::XChartType>& xChartType,
    OpenGLWindow& rWindow) :
    mxChartType(xChartType),
    mpRenderer(new opengl3D::OpenGL3DRenderer()),
    mrWindow(rWindow),
    mpCamera(NULL),
    mbValidContext(true)
{
    Size aSize = mrWindow.GetSizePixel();
    mpRenderer->SetSize(aSize);
    mrWindow.setRenderer(this);
    mpRenderer->init();
}

GL3DBarChart::~GL3DBarChart()
{
    if(mbValidContext)
        mrWindow.setRenderer(NULL);
}

namespace {

const float TEXT_HEIGHT = 15.0f;

float calculateTextWidth(const OUString& rText)
{
    return rText.getLength() * 7.5;
}

}

void GL3DBarChart::create3DShapes(const boost::ptr_vector<VDataSeries>& rDataSeriesContainer,
        ExplicitCategoriesProvider& rCatProvider)
{
    // Each series of data flows from left to right, and multiple series are
    // stacked vertically along y axis.

    // NOTE: These objects are created and positioned in a totally blind
    // fashion since we don't even have a way to see them on screen.  So, no
    // guarantee they are positioned correctly.  In fact, they are guaranteed
    // to be positioned incorrectly.

    const float nBarSizeX = 10.0f;
    const float nBarSizeY = 30.0f;
    const float nBarDistanceX = 5.0f;
    const float nBarDistanceY = 5.0;

    sal_uInt32 nId = 1;
    float nXEnd = 0.0;
    float nYPos = 0.0;

    const Color aSeriesColor[] = {
        COL_RED, COL_GREEN, COL_YELLOW, COL_BROWN, COL_GRAY
    };

    maShapes.clear();
    maShapes.push_back(new opengl3D::Camera(mpRenderer.get()));
    mpCamera = static_cast<opengl3D::Camera*>(&maShapes.back());

    sal_Int32 nSeriesIndex = 0;
    for (boost::ptr_vector<VDataSeries>::const_iterator itr = rDataSeriesContainer.begin(),
            itrEnd = rDataSeriesContainer.end(); itr != itrEnd; ++itr)
    {
        nYPos = nSeriesIndex * (nBarSizeY + nBarDistanceY);

        const VDataSeries& rDataSeries = *itr;
        sal_Int32 nPointCount = rDataSeries.getTotalPointCount();

        bool bMappedFillProperty = rDataSeries.hasPropertyMapping("FillColor");

        // Create series name text object.
        OUString aSeriesName =
            DataSeriesHelper::getDataSeriesLabel(
                rDataSeries.getModel(), mxChartType->getRoleOfSequenceForSeriesLabel());

        maShapes.push_back(new opengl3D::Text(mpRenderer.get(), aSeriesName, nId++));
        opengl3D::Text* p = static_cast<opengl3D::Text*>(&maShapes.back());
        glm::vec3 aTopLeft, aTopRight, aBottomRight;
        aTopLeft.x = calculateTextWidth(aSeriesName) * -1.0;
        aTopLeft.y = nYPos;
        aTopRight.y = nYPos;
        aBottomRight = aTopRight;
        aBottomRight.y += TEXT_HEIGHT;
        p->setPosition(aTopLeft, aTopRight, aBottomRight);

        sal_Int32 nColor = aSeriesColor[nSeriesIndex % SAL_N_ELEMENTS(aSeriesColor)].GetColor();
        for(sal_Int32 nIndex = 0; nIndex < nPointCount; ++nIndex)
        {
            if(bMappedFillProperty)
            {
                nColor = static_cast<sal_uInt32>(rDataSeries.getValueByProperty(nIndex, "FillColor"));
            }

            float nVal = rDataSeries.getYValue(nIndex);
            float nXPos = nIndex * (nBarSizeX + nBarDistanceX);

            glm::mat4 aScaleMatrix = glm::scale(nBarSizeX, nBarSizeY, nVal);
            glm::mat4 aTranslationMatrix = glm::translate(nXPos, nYPos, 0.0f);
            glm::mat4 aBarPosition = aTranslationMatrix * aScaleMatrix;

            maShapes.push_back(new opengl3D::Bar(mpRenderer.get(), aBarPosition, nColor, nId++));
        }

        float nThisXEnd = nPointCount * (nBarSizeX + nBarDistanceX);
        if (nXEnd < nThisXEnd)
            nXEnd = nThisXEnd;

        ++nSeriesIndex;
    }

    nYPos += nBarSizeY + nBarDistanceY;

    // X axis
    maShapes.push_back(new opengl3D::Line(mpRenderer.get(), nId++));
    opengl3D::Line* pAxis = static_cast<opengl3D::Line*>(&maShapes.back());
    glm::vec3 aBegin;
    aBegin.y = nYPos;
    glm::vec3 aEnd = aBegin;
    aEnd.x = nXEnd;
    pAxis->setPosition(aBegin, aEnd);
    pAxis->setLineColor(COL_BLUE);

    // Y axis
    maShapes.push_back(new opengl3D::Line(mpRenderer.get(), nId++));
    pAxis = static_cast<opengl3D::Line*>(&maShapes.back());
    aBegin.x = aBegin.y = 0;
    aEnd = aBegin;
    aEnd.y = nYPos;
    pAxis->setPosition(aBegin, aEnd);
    pAxis->setLineColor(COL_BLUE);

    // Chart background.
    maShapes.push_back(new opengl3D::Rectangle(mpRenderer.get(), nId++));
    opengl3D::Rectangle* pRect = static_cast<opengl3D::Rectangle*>(&maShapes.back());
    glm::vec3 aTopLeft;
    glm::vec3 aTopRight = aTopLeft;
    aTopRight.x = nXEnd;
    glm::vec3 aBottomRight = aTopRight;
    aBottomRight.y = nYPos;
    pRect->setPosition(aTopLeft, aTopRight, aBottomRight);
    pRect->setFillColor(COL_BLACK);
    pRect->setLineColor(COL_BLUE);

    // Create category texts along X-axis at the bottom.
    uno::Sequence<OUString> aCats = rCatProvider.getSimpleCategories();
    for (sal_Int32 i = 0; i < aCats.getLength(); ++i)
    {
        float nXPos = i * (nBarSizeX + nBarDistanceX);

        maShapes.push_back(new opengl3D::Text(mpRenderer.get(), aCats[i], nId++));
        opengl3D::Text* p = static_cast<opengl3D::Text*>(&maShapes.back());
        aTopLeft.x = nXPos;
        aTopLeft.y = nYPos;
        aTopRight = aTopLeft;
        aTopRight.x += calculateTextWidth(aCats[i]);
        aBottomRight = aTopRight;
        aBottomRight.y += TEXT_HEIGHT;
        p->setPosition(aTopLeft, aTopRight, aBottomRight);
    }
}

void GL3DBarChart::render()
{
    if(!mbValidContext)
        return;

    mrWindow.getContext()->makeCurrent();
    Size aSize = mrWindow.GetSizePixel();
    mpRenderer->SetSize(aSize);
    mrWindow.getContext()->setWinSize(aSize);
    for(boost::ptr_vector<opengl3D::Renderable3DObject>::iterator itr = maShapes.begin(),
            itrEnd = maShapes.end(); itr != itrEnd; ++itr)
    {
        itr->render();
    }
    mpRenderer->ProcessUnrenderedShape();
    mrWindow.getContext()->swapBuffers();
}

void GL3DBarChart::update()
{
    render();
}

namespace {

class PickingModeSetter
{
private:
    opengl3D::OpenGL3DRenderer* mpRenderer;

public:
    PickingModeSetter(opengl3D::OpenGL3DRenderer* pRenderer):
        mpRenderer(pRenderer)
    {
        mpRenderer->SetPickingMode(true);
    }

    ~PickingModeSetter()
    {
        mpRenderer->SetPickingMode(false);
    }
};

}

void GL3DBarChart::clickedAt(const Point& rPos)
{
    sal_uInt32 nId = 1;
    {
        PickingModeSetter aPickingModeSetter(mpRenderer.get());
        render();
        nId = mpRenderer->GetPixelColorFromPoint(rPos.X(), rPos.Y());
    }
    if (mpCamera && nId != COL_WHITE)
        mpCamera->zoom(nId);
}

void GL3DBarChart::contextDestroyed()
{
    mbValidContext = false;
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>avoid the creation of empty text<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <GL3DBarChart.hxx>

#include <GL/glew.h>

#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>

#include "3DChartObjects.hxx"
#include "GL3DRenderer.hxx"
#include <ExplicitCategoriesProvider.hxx>
#include <DataSeriesHelper.hxx>

using namespace com::sun::star;

namespace chart {

GL3DBarChart::GL3DBarChart(
    const css::uno::Reference<css::chart2::XChartType>& xChartType,
    OpenGLWindow& rWindow) :
    mxChartType(xChartType),
    mpRenderer(new opengl3D::OpenGL3DRenderer()),
    mrWindow(rWindow),
    mpCamera(NULL),
    mbValidContext(true)
{
    Size aSize = mrWindow.GetSizePixel();
    mpRenderer->SetSize(aSize);
    mrWindow.setRenderer(this);
    mpRenderer->init();
}

GL3DBarChart::~GL3DBarChart()
{
    if(mbValidContext)
        mrWindow.setRenderer(NULL);
}

namespace {

const float TEXT_HEIGHT = 15.0f;

float calculateTextWidth(const OUString& rText)
{
    return rText.getLength() * 7.5;
}

}

void GL3DBarChart::create3DShapes(const boost::ptr_vector<VDataSeries>& rDataSeriesContainer,
        ExplicitCategoriesProvider& rCatProvider)
{
    // Each series of data flows from left to right, and multiple series are
    // stacked vertically along y axis.

    // NOTE: These objects are created and positioned in a totally blind
    // fashion since we don't even have a way to see them on screen.  So, no
    // guarantee they are positioned correctly.  In fact, they are guaranteed
    // to be positioned incorrectly.

    const float nBarSizeX = 10.0f;
    const float nBarSizeY = 30.0f;
    const float nBarDistanceX = 5.0f;
    const float nBarDistanceY = 5.0;

    sal_uInt32 nId = 1;
    float nXEnd = 0.0;
    float nYPos = 0.0;

    const Color aSeriesColor[] = {
        COL_RED, COL_GREEN, COL_YELLOW, COL_BROWN, COL_GRAY
    };

    maShapes.clear();
    maShapes.push_back(new opengl3D::Camera(mpRenderer.get()));
    mpCamera = static_cast<opengl3D::Camera*>(&maShapes.back());

    sal_Int32 nSeriesIndex = 0;
    for (boost::ptr_vector<VDataSeries>::const_iterator itr = rDataSeriesContainer.begin(),
            itrEnd = rDataSeriesContainer.end(); itr != itrEnd; ++itr)
    {
        nYPos = nSeriesIndex * (nBarSizeY + nBarDistanceY);

        const VDataSeries& rDataSeries = *itr;
        sal_Int32 nPointCount = rDataSeries.getTotalPointCount();

        bool bMappedFillProperty = rDataSeries.hasPropertyMapping("FillColor");

        // Create series name text object.
        OUString aSeriesName =
            DataSeriesHelper::getDataSeriesLabel(
                rDataSeries.getModel(), mxChartType->getRoleOfSequenceForSeriesLabel());

        if(!aSeriesName.isEmpty())
        {
            maShapes.push_back(new opengl3D::Text(mpRenderer.get(), aSeriesName, nId++));
            opengl3D::Text* p = static_cast<opengl3D::Text*>(&maShapes.back());
            glm::vec3 aTopLeft, aTopRight, aBottomRight;
            aTopLeft.x = calculateTextWidth(aSeriesName) * -1.0;
            aTopLeft.y = nYPos;
            aTopRight.y = nYPos;
            aBottomRight = aTopRight;
            aBottomRight.y += TEXT_HEIGHT;
            p->setPosition(aTopLeft, aTopRight, aBottomRight);
        }

        sal_Int32 nColor = aSeriesColor[nSeriesIndex % SAL_N_ELEMENTS(aSeriesColor)].GetColor();
        for(sal_Int32 nIndex = 0; nIndex < nPointCount; ++nIndex)
        {
            if(bMappedFillProperty)
            {
                nColor = static_cast<sal_uInt32>(rDataSeries.getValueByProperty(nIndex, "FillColor"));
            }

            float nVal = rDataSeries.getYValue(nIndex);
            float nXPos = nIndex * (nBarSizeX + nBarDistanceX);

            glm::mat4 aScaleMatrix = glm::scale(nBarSizeX, nBarSizeY, nVal);
            glm::mat4 aTranslationMatrix = glm::translate(nXPos, nYPos, 0.0f);
            glm::mat4 aBarPosition = aTranslationMatrix * aScaleMatrix;

            maShapes.push_back(new opengl3D::Bar(mpRenderer.get(), aBarPosition, nColor, nId++));
        }

        float nThisXEnd = nPointCount * (nBarSizeX + nBarDistanceX);
        if (nXEnd < nThisXEnd)
            nXEnd = nThisXEnd;

        ++nSeriesIndex;
    }

    nYPos += nBarSizeY + nBarDistanceY;

    // X axis
    maShapes.push_back(new opengl3D::Line(mpRenderer.get(), nId++));
    opengl3D::Line* pAxis = static_cast<opengl3D::Line*>(&maShapes.back());
    glm::vec3 aBegin;
    aBegin.y = nYPos;
    glm::vec3 aEnd = aBegin;
    aEnd.x = nXEnd;
    pAxis->setPosition(aBegin, aEnd);
    pAxis->setLineColor(COL_BLUE);

    // Y axis
    maShapes.push_back(new opengl3D::Line(mpRenderer.get(), nId++));
    pAxis = static_cast<opengl3D::Line*>(&maShapes.back());
    aBegin.x = aBegin.y = 0;
    aEnd = aBegin;
    aEnd.y = nYPos;
    pAxis->setPosition(aBegin, aEnd);
    pAxis->setLineColor(COL_BLUE);

    // Chart background.
    maShapes.push_back(new opengl3D::Rectangle(mpRenderer.get(), nId++));
    opengl3D::Rectangle* pRect = static_cast<opengl3D::Rectangle*>(&maShapes.back());
    glm::vec3 aTopLeft;
    glm::vec3 aTopRight = aTopLeft;
    aTopRight.x = nXEnd;
    glm::vec3 aBottomRight = aTopRight;
    aBottomRight.y = nYPos;
    pRect->setPosition(aTopLeft, aTopRight, aBottomRight);
    pRect->setFillColor(COL_BLACK);
    pRect->setLineColor(COL_BLUE);

    // Create category texts along X-axis at the bottom.
    uno::Sequence<OUString> aCats = rCatProvider.getSimpleCategories();
    for (sal_Int32 i = 0; i < aCats.getLength(); ++i)
    {
        if(aCats[i].isEmpty())
            continue;

        float nXPos = i * (nBarSizeX + nBarDistanceX);

        maShapes.push_back(new opengl3D::Text(mpRenderer.get(), aCats[i], nId++));
        opengl3D::Text* p = static_cast<opengl3D::Text*>(&maShapes.back());
        aTopLeft.x = nXPos;
        aTopLeft.y = nYPos;
        aTopRight = aTopLeft;
        aTopRight.x += calculateTextWidth(aCats[i]);
        aBottomRight = aTopRight;
        aBottomRight.y += TEXT_HEIGHT;
        p->setPosition(aTopLeft, aTopRight, aBottomRight);
    }
}

void GL3DBarChart::render()
{
    if(!mbValidContext)
        return;

    mrWindow.getContext()->makeCurrent();
    Size aSize = mrWindow.GetSizePixel();
    mpRenderer->SetSize(aSize);
    mrWindow.getContext()->setWinSize(aSize);
    for(boost::ptr_vector<opengl3D::Renderable3DObject>::iterator itr = maShapes.begin(),
            itrEnd = maShapes.end(); itr != itrEnd; ++itr)
    {
        itr->render();
    }
    mpRenderer->ProcessUnrenderedShape();
    mrWindow.getContext()->swapBuffers();
}

void GL3DBarChart::update()
{
    render();
}

namespace {

class PickingModeSetter
{
private:
    opengl3D::OpenGL3DRenderer* mpRenderer;

public:
    PickingModeSetter(opengl3D::OpenGL3DRenderer* pRenderer):
        mpRenderer(pRenderer)
    {
        mpRenderer->SetPickingMode(true);
    }

    ~PickingModeSetter()
    {
        mpRenderer->SetPickingMode(false);
    }
};

}

void GL3DBarChart::clickedAt(const Point& rPos)
{
    sal_uInt32 nId = 1;
    {
        PickingModeSetter aPickingModeSetter(mpRenderer.get());
        render();
        nId = mpRenderer->GetPixelColorFromPoint(rPos.X(), rPos.Y());
    }
    if (mpCamera && nId != COL_WHITE)
        mpCamera->zoom(nId);
}

void GL3DBarChart::contextDestroyed()
{
    mbValidContext = false;
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "infosPerso.h"
#include <QSqlError>
#include <QSqlDriver>
#include <QtCore/QtCore>
#include <QLayout>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    _layout(new QStackedLayout())
{
    ui->setupUi(this);
    ui->centralWidget->setLayout(_layout);

    _layout->addWidget(new InfosPerso);
    connect(ui->actionInfos_Perso, SIGNAL(triggered(bool)), this, SLOT(on_infosPerso_triggered()));
}

void MainWindow::on_infosPerso_triggered ()
{
    _layout->setCurrentIndex(0);
}

MainWindow::~MainWindow() {
    delete ui;
}
<commit_msg>plop est temporaire<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "infosPerso.h"
#include <QSqlError>
#include <QSqlDriver>
#include <QtCore/QtCore>
#include <QLayout>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    _layout(new QStackedLayout())
{
    ui->setupUi(this);
    ui->centralWidget->setLayout(_layout);

    _layout->addWidget(new InfosPerso);
    connect(ui->actionInfos_Perso, SIGNAL(triggered(bool)), this, SLOT(on_infosPerso_triggered()));
}

void MainWindow::on_infosPerso_triggered ()
{
    _layout->setCurrentIndex(0);
}

void plop () {
    qDebug() << QSqlDatabase::drivers();
    qDebug() << QSqlDatabase::isDriverAvailable("QMYSQL");
    this->bdd = QSqlDatabase::addDatabase("QMYSQL", "Ligue");
    qDebug() << bdd.connectionName();
    this->bdd.setHostName("localhost");
    this->bdd.setPort(3306);
    this->bdd.setDatabaseName("LigueKaladesh");
    this->bdd.setUserName("root");
    this->bdd.setPassword("root");
    if (this->bdd.open()) {
        ui->actionConnecter->setEnabled(false);
        ui->actionDeconnecter->setEnabled(true);
        ui->menuJoueurs->setEnabled(true);
        ui->menuResultats->setEnabled(true);

        switchCentralWidget(new QWidget());
    }
}

MainWindow::~MainWindow() {
    delete ui;
}
<|endoftext|>


<commit_before>//===--- tools/extra/clang-rename/USRFinder.cpp - Clang rename tool -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
/// point.
///
//===----------------------------------------------------------------------===//

#include "USRFinder.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallVector.h"

using namespace llvm;

namespace clang {
namespace rename {

// NamedDeclFindingASTVisitor recursively visits each AST node to find the
// symbol underneath the cursor.
// FIXME: move to seperate .h/.cc file if this gets too large.
namespace {
class NamedDeclFindingASTVisitor
    : public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> {
public:
  // \brief Finds the NamedDecl at a point in the source.
  // \param Point the location in the source to search for the NamedDecl.
  explicit NamedDeclFindingASTVisitor(const SourceLocation Point,
                                      const ASTContext &Context)
      : Result(nullptr), Point(Point), Context(Context) {}

  // \brief Finds the NamedDecl for a name in the source.
  // \param Name the fully qualified name.
  explicit NamedDeclFindingASTVisitor(const std::string &Name,
                                      const ASTContext &Context)
      : Result(nullptr), Name(Name), Context(Context) {}

  // Declaration visitors:

  // \brief Checks if the point falls within the NameDecl. This covers every
  // declaration of a named entity that we may come across. Usually, just
  // checking if the point lies within the length of the name of the declaration
  // and the start location is sufficient.
  bool VisitNamedDecl(const NamedDecl *Decl) {
    return dyn_cast<CXXConversionDecl>(Decl)
               ? true
               : setResult(Decl, Decl->getLocation(),
                           Decl->getNameAsString().length());
  }

  // Expression visitors:

  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
    const NamedDecl *Decl = Expr->getFoundDecl();
    return setResult(Decl, Expr->getLocation(),
                     Decl->getNameAsString().length());
  }

  bool VisitMemberExpr(const MemberExpr *Expr) {
    const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
    return setResult(Decl, Expr->getMemberLoc(),
                     Decl->getNameAsString().length());
  }

  // Other visitors:

  bool VisitTypeLoc(const TypeLoc Loc) {
    const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
    const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(
                             TypeBeginLoc, 0, Context.getSourceManager(),
                             Context.getLangOpts());
    if (const auto *TemplateTypeParm =
            dyn_cast<TemplateTypeParmType>(Loc.getType())) {
      return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc);
    }
    if (const auto *TemplateSpecType =
            dyn_cast<TemplateSpecializationType>(Loc.getType())) {
      return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
                       TypeBeginLoc, TypeEndLoc);
    }
    return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc,
                     TypeEndLoc);
  }

  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
    for (const auto *Initializer : ConstructorDecl->inits()) {
      if (!Initializer->isWritten()) {
        // Ignore implicit initializers.
        continue;
      }
      if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
        const SourceLocation InitBeginLoc = Initializer->getSourceLocation(),
                             InitEndLoc = Lexer::getLocForEndOfToken(
                                 InitBeginLoc, 0, Context.getSourceManager(),
                                 Context.getLangOpts());
        if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc)) {
          return false;
        }
      }
    }
    return true;
  }

  // Other:

  const NamedDecl *getNamedDecl() { return Result; }

  // \brief Determines if a namespace qualifier contains the point.
  // \returns false on success and sets Result.
  void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
    while (NameLoc) {
      const NamespaceDecl *Decl =
          NameLoc.getNestedNameSpecifier()->getAsNamespace();
      setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());
      NameLoc = NameLoc.getPrefix();
    }
  }

private:
  // \brief Sets Result to Decl if the Point is within Start and End.
  // \returns false on success.
  bool setResult(const NamedDecl *Decl, SourceLocation Start,
                 SourceLocation End) {
    if (!Decl) {
      return true;
    }
    if (Name.empty()) {
      // Offset is used to find the declaration.
      if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
          !End.isFileID() || !isPointWithin(Start, End)) {
        return true;
      }
    } else {
      // Fully qualified name is used to find the declaration.
      if (Name != Decl->getQualifiedNameAsString()) {
        return true;
      }
    }
    Result = Decl;
    return false;
  }

  // \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
  // \returns false on success.
  bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) {
    // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).
    return Offset == 0 ||
           setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
  }

  // \brief Determines if the Point is within Start and End.
  bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
    // FIXME: Add tests for Point == End.
    return Point == Start || Point == End ||
           (Context.getSourceManager().isBeforeInTranslationUnit(Start,
                                                                 Point) &&
            Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
  }

  const NamedDecl *Result;
  const SourceLocation Point; // The location to find the NamedDecl.
  const std::string Name;
  const ASTContext &Context;
};
} // namespace

const NamedDecl *getNamedDeclAt(const ASTContext &Context,
                                const SourceLocation Point) {
  StringRef SearchFile = Context.getSourceManager().getFilename(Point);
  NamedDeclFindingASTVisitor Visitor(Point, Context);

  // We only want to search the decls that exist in the same file as the point.
  for (const auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
    const SourceLocation FileLoc = CurrDecl->getLocStart();
    StringRef FileName = Context.getSourceManager().getFilename(FileLoc);
    // FIXME: Add test.
    if (FileName == SearchFile) {
      Visitor.TraverseDecl(CurrDecl);
    }
  }

  NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));
  for (const auto &Location : Finder.getNestedNameSpecifierLocations()) {
    Visitor.handleNestedNameSpecifierLoc(Location);
  }

  return Visitor.getNamedDecl();
}

const NamedDecl *getNamedDeclFor(const ASTContext &Context,
                                 const std::string &Name) {
  NamedDeclFindingASTVisitor Visitor(Name, Context);
  Visitor.TraverseDecl(Context.getTranslationUnitDecl());

  return Visitor.getNamedDecl();
}

std::string getUSRForDecl(const Decl *Decl) {
  llvm::SmallVector<char, 128> Buff;

  // FIXME: Add test for the nullptr case.
  if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
    return "";

  return std::string(Buff.data(), Buff.size());
}

} // namespace rename
} // namespace clang
<commit_msg>[clang-rename] fix broken build<commit_after>//===--- tools/extra/clang-rename/USRFinder.cpp - Clang rename tool -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file Implements a recursive AST visitor that finds the USR of a symbol at a
/// point.
///
//===----------------------------------------------------------------------===//

#include "USRFinder.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallVector.h"

using namespace llvm;

namespace clang {
namespace rename {

// NamedDeclFindingASTVisitor recursively visits each AST node to find the
// symbol underneath the cursor.
// FIXME: move to seperate .h/.cc file if this gets too large.
namespace {
class NamedDeclFindingASTVisitor
    : public clang::RecursiveASTVisitor<NamedDeclFindingASTVisitor> {
public:
  // \brief Finds the NamedDecl at a point in the source.
  // \param Point the location in the source to search for the NamedDecl.
  explicit NamedDeclFindingASTVisitor(const SourceLocation Point,
                                      const ASTContext &Context)
      : Result(nullptr), Point(Point), Context(Context) {}

  // \brief Finds the NamedDecl for a name in the source.
  // \param Name the fully qualified name.
  explicit NamedDeclFindingASTVisitor(const std::string &Name,
                                      const ASTContext &Context)
      : Result(nullptr), Name(Name), Context(Context) {}

  // Declaration visitors:

  // \brief Checks if the point falls within the NameDecl. This covers every
  // declaration of a named entity that we may come across. Usually, just
  // checking if the point lies within the length of the name of the declaration
  // and the start location is sufficient.
  bool VisitNamedDecl(const NamedDecl *Decl) {
    return dyn_cast<CXXConversionDecl>(Decl)
               ? true
               : setResult(Decl, Decl->getLocation(),
                           Decl->getNameAsString().length());
  }

  // Expression visitors:

  bool VisitDeclRefExpr(const DeclRefExpr *Expr) {
    const NamedDecl *Decl = Expr->getFoundDecl();
    return setResult(Decl, Expr->getLocation(),
                     Decl->getNameAsString().length());
  }

  bool VisitMemberExpr(const MemberExpr *Expr) {
    const NamedDecl *Decl = Expr->getFoundDecl().getDecl();
    return setResult(Decl, Expr->getMemberLoc(),
                     Decl->getNameAsString().length());
  }

  // Other visitors:

  bool VisitTypeLoc(const TypeLoc Loc) {
    const SourceLocation TypeBeginLoc = Loc.getBeginLoc();
    const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(
                             TypeBeginLoc, 0, Context.getSourceManager(),
                             Context.getLangOpts());
    if (const auto *TemplateTypeParm =
            dyn_cast<TemplateTypeParmType>(Loc.getType())) {
      return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc);
    }
    if (const auto *TemplateSpecType =
            dyn_cast<TemplateSpecializationType>(Loc.getType())) {
      return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(),
                       TypeBeginLoc, TypeEndLoc);
    }
    return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc,
                     TypeEndLoc);
  }

  bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) {
    for (const auto *Initializer : ConstructorDecl->inits()) {
      if (!Initializer->isWritten()) {
        // Ignore implicit initializers.
        continue;
      }
      if (const clang::FieldDecl *FieldDecl = Initializer->getMember()) {
        const SourceLocation InitBeginLoc = Initializer->getSourceLocation(),
                             InitEndLoc = Lexer::getLocForEndOfToken(
                                 InitBeginLoc, 0, Context.getSourceManager(),
                                 Context.getLangOpts());
        if (!setResult(FieldDecl, InitBeginLoc, InitEndLoc)) {
          return false;
        }
      }
    }
    return true;
  }

  // Other:

  const NamedDecl *getNamedDecl() { return Result; }

  // \brief Determines if a namespace qualifier contains the point.
  // \returns false on success and sets Result.
  void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) {
    while (NameLoc) {
      const NamespaceDecl *Decl =
          NameLoc.getNestedNameSpecifier()->getAsNamespace();
      setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc());
      NameLoc = NameLoc.getPrefix();
    }
  }

private:
  // \brief Sets Result to Decl if the Point is within Start and End.
  // \returns false on success.
  bool setResult(const NamedDecl *Decl, SourceLocation Start,
                 SourceLocation End) {
    if (!Decl) {
      return true;
    }
    if (Name.empty()) {
      // Offset is used to find the declaration.
      if (!Start.isValid() || !Start.isFileID() || !End.isValid() ||
          !End.isFileID() || !isPointWithin(Start, End)) {
        return true;
      }
    } else {
      // Fully qualified name is used to find the declaration.
      if (Name != Decl->getQualifiedNameAsString()) {
        return true;
      }
    }
    Result = Decl;
    return false;
  }

  // \brief Sets Result to Decl if Point is within Loc and Loc + Offset.
  // \returns false on success.
  bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) {
    // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc).
    return Offset == 0 ||
           setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1));
  }

  // \brief Determines if the Point is within Start and End.
  bool isPointWithin(const SourceLocation Start, const SourceLocation End) {
    // FIXME: Add tests for Point == End.
    return Point == Start || Point == End ||
           (Context.getSourceManager().isBeforeInTranslationUnit(Start,
                                                                 Point) &&
            Context.getSourceManager().isBeforeInTranslationUnit(Point, End));
  }

  const NamedDecl *Result;
  const SourceLocation Point; // The location to find the NamedDecl.
  const std::string Name;
  const ASTContext &Context;
};
} // namespace

const NamedDecl *getNamedDeclAt(const ASTContext &Context,
                                const SourceLocation Point) {
  StringRef SearchFile = Context.getSourceManager().getFilename(Point);
  NamedDeclFindingASTVisitor Visitor(Point, Context);

  // We only want to search the decls that exist in the same file as the point.
  for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) {
    const SourceLocation FileLoc = CurrDecl->getLocStart();
    StringRef FileName = Context.getSourceManager().getFilename(FileLoc);
    // FIXME: Add test.
    if (FileName == SearchFile) {
      Visitor.TraverseDecl(CurrDecl);
    }
  }

  NestedNameSpecifierLocFinder Finder(const_cast<ASTContext &>(Context));
  for (const auto &Location : Finder.getNestedNameSpecifierLocations()) {
    Visitor.handleNestedNameSpecifierLoc(Location);
  }

  return Visitor.getNamedDecl();
}

const NamedDecl *getNamedDeclFor(const ASTContext &Context,
                                 const std::string &Name) {
  NamedDeclFindingASTVisitor Visitor(Name, Context);
  Visitor.TraverseDecl(Context.getTranslationUnitDecl());

  return Visitor.getNamedDecl();
}

std::string getUSRForDecl(const Decl *Decl) {
  llvm::SmallVector<char, 128> Buff;

  // FIXME: Add test for the nullptr case.
  if (Decl == nullptr || index::generateUSRForDecl(Decl, Buff))
    return "";

  return std::string(Buff.data(), Buff.size());
}

} // namespace rename
} // namespace clang
<|endoftext|>