<commit_before>/* -*-c++-*- VirtualPlanetBuilder - Copyright (C) 1998-2007 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commericial and non commericial applications,
 * as long as this copyright notice is maintained.
 *
 * This application 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.
*/

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>

#include <iostream>
#include <sstream>

#include <curl/curl.h>
#include <curl/types.h>

class ReaderWriterCURL : public osgDB::ReaderWriter
{
    public:

        static size_t StreamMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
        {
            size_t realsize = size * nmemb;
            std::ostream* buffer = (std::ostream*)data;

            buffer->write((const char*)ptr, realsize);

            return realsize;
        }

        ReaderWriterCURL()
        {
            _curl = curl_easy_init();

            curl_easy_setopt(_curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
            curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, StreamMemoryCallback);
        }

        ~ReaderWriterCURL()
        {
            if (_curl) curl_easy_cleanup(_curl);

            _curl = 0;
        }

        virtual const char* className() const { return "HTTP Protocol Model Reader"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"curl");
        }

        enum ObjectType
        {
            OBJECT,
            ARCHIVE,
            IMAGE,
            HEIGHTFIELD,
            NODE
        };

        virtual ReadResult openArchive(const std::string& fileName,ArchiveStatus status, unsigned int , const Options* options) const
        {
            if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED);
            else return readFile(ARCHIVE,fileName,options);
        }

        virtual ReadResult readObject(const std::string& fileName, const Options* options) const
        {
            return readFile(OBJECT,fileName,options);
        }

        virtual ReadResult readImage(const std::string& fileName, const Options *options) const
        {
            return readFile(IMAGE,fileName,options);
        }

        virtual ReadResult readHeightField(const std::string& fileName, const Options *options) const
        {
            return readFile(HEIGHTFIELD,fileName,options);
        }

        virtual ReadResult readNode(const std::string& fileName, const Options *options) const
        {
            return readFile(NODE,fileName,options);
        }

        ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const Options *options) const
        {
            switch(objectType)
            {
            case(OBJECT): return rw->readObject(fin,options);
            case(ARCHIVE): return rw->openArchive(fin,options);
            case(IMAGE): return rw->readImage(fin,options);
            case(HEIGHTFIELD): return rw->readHeightField(fin,options);
            case(NODE): return rw->readNode(fin,options);
            default: break;
            }
            return ReadResult::FILE_NOT_HANDLED;
        }

        virtual ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const Options *options) const
        {
            if (!osgDB::containsServerAddress(fullFileName))
            {
                osg::notify(osg::NOTICE)<<"File '"<<fullFileName<<"' does not contain server address, cannort load with libcurl plugin."<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }

            std::string fileName;
            std::string ext = osgDB::getFileExtension(fullFileName);
            if (ext=="curl")
            {
                fileName = osgDB::getNameLessExtension(fullFileName);
            }
            else
            {
                fileName = fullFileName;
            }

            osgDB::ReaderWriter *reader =
                osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(fileName));

            if (!reader)
            {
                osg::notify(osg::NOTICE)<<"No ReaderWriter for file "<<fileName<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }

            std::stringstream buffer;

            curl_easy_setopt(_curl, CURLOPT_URL, fileName.c_str());
            curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)&buffer);

            CURLcode res = curl_easy_perform(_curl);

            curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)0);

            if (res==0)
            {
                osg::ref_ptr<Options> local_opt = const_cast<Options*>(options);
                if (!local_opt) local_opt = new Options;

                if (local_opt.valid() && local_opt->getDatabasePathList().empty())
                {
                    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
                }

                ReadResult result = readFile(objectType, reader, buffer, local_opt.get() );

                local_opt->getDatabasePathList().pop_front();

                return result;
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Read error, file="<<fileName<<" libcurl result = "<<res<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }
        }

    protected:

        CURL* _curl;

};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(rgb, ReaderWriterCURL)
<commit_msg>Fixed push/popping of filepath, removed verbose debug messages <commit_after>/* -*-c++-*- VirtualPlanetBuilder - Copyright (C) 1998-2007 Robert Osfield
 *
 * This application is open source and may be redistributed and/or modified
 * freely and without restriction, both in commericial and non commericial applications,
 * as long as this copyright notice is maintained.
 *
 * This application 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.
*/

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>

#include <iostream>
#include <sstream>

#include <curl/curl.h>
#include <curl/types.h>

class ReaderWriterCURL : public osgDB::ReaderWriter
{
    public:

        static size_t StreamMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
        {
            size_t realsize = size * nmemb;
            std::ostream* buffer = (std::ostream*)data;

            buffer->write((const char*)ptr, realsize);

            return realsize;
        }

        ReaderWriterCURL()
        {
            _curl = curl_easy_init();

            curl_easy_setopt(_curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
            curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, StreamMemoryCallback);
        }

        ~ReaderWriterCURL()
        {
            if (_curl) curl_easy_cleanup(_curl);

            _curl = 0;
        }

        virtual const char* className() const { return "HTTP Protocol Model Reader"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"curl");
        }

        enum ObjectType
        {
            OBJECT,
            ARCHIVE,
            IMAGE,
            HEIGHTFIELD,
            NODE
        };

        virtual ReadResult openArchive(const std::string& fileName,ArchiveStatus status, unsigned int , const Options* options) const
        {
            if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED);
            else return readFile(ARCHIVE,fileName,options);
        }

        virtual ReadResult readObject(const std::string& fileName, const Options* options) const
        {
            return readFile(OBJECT,fileName,options);
        }

        virtual ReadResult readImage(const std::string& fileName, const Options *options) const
        {
            return readFile(IMAGE,fileName,options);
        }

        virtual ReadResult readHeightField(const std::string& fileName, const Options *options) const
        {
            return readFile(HEIGHTFIELD,fileName,options);
        }

        virtual ReadResult readNode(const std::string& fileName, const Options *options) const
        {
            return readFile(NODE,fileName,options);
        }

        ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const Options *options) const
        {
            switch(objectType)
            {
            case(OBJECT): return rw->readObject(fin,options);
            case(ARCHIVE): return rw->openArchive(fin,options);
            case(IMAGE): return rw->readImage(fin,options);
            case(HEIGHTFIELD): return rw->readHeightField(fin,options);
            case(NODE): return rw->readNode(fin,options);
            default: break;
            }
            return ReadResult::FILE_NOT_HANDLED;
        }

        virtual ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const Options *options) const
        {
            if (!osgDB::containsServerAddress(fullFileName))
            {
                if (options && !(options->getDatabasePathList().empty()))
                {
                    if (osgDB::containsServerAddress(options->getDatabasePathList().front()))
                    {
                        std::string newFileName = options->getDatabasePathList().front() + "/" + fullFileName;

                        return readFile(objectType, newFileName,options);
                    }
                }

                return ReadResult::FILE_NOT_HANDLED;
            }

            std::string fileName;
            std::string ext = osgDB::getFileExtension(fullFileName);
            if (ext=="curl")
            {
                fileName = osgDB::getNameLessExtension(fullFileName);
            }
            else
            {
                fileName = fullFileName;
            }

            osgDB::ReaderWriter *reader =
                osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(fileName));

            if (!reader)
            {
                osg::notify(osg::NOTICE)<<"Error: No ReaderWriter for file "<<fileName<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }

            std::stringstream buffer;

            curl_easy_setopt(_curl, CURLOPT_URL, fileName.c_str());
            curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)&buffer);

            CURLcode res = curl_easy_perform(_curl);

            curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)0);

            if (res==0)
            {
                osg::ref_ptr<Options> local_opt = const_cast<Options*>(options);
                if (!local_opt) local_opt = new Options;

                local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));

                ReadResult result = readFile(objectType, reader, buffer, local_opt.get() );

                local_opt->getDatabasePathList().pop_front();

                return result;
            }
            else
            {
                osg::notify(osg::NOTICE)<<"Error: libcurl read error, file="<<fileName<<" result = "<<res<<std::endl;
                return ReadResult::FILE_NOT_HANDLED;
            }
        }

    protected:

        CURL* _curl;

};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(rgb, ReaderWriterCURL)
<|endoftext|>


<commit_before>// ***************************************************************************
//
//   Generated automatically by genwrapper.
//   Please DO NOT EDIT this file!
//
// ***************************************************************************

#include <osgIntrospection/ReflectionMacros>
#include <osgIntrospection/TypedMethodInfo>
#include <osgIntrospection/StaticMethodInfo>
#include <osgIntrospection/Attributes>

#include <osg/Image>
#include <osg/Shader>
#include <osg/Texture>
#include <osg/TransferFunction>
#include <osg/Vec4>

// Must undefine IN and OUT macros defined in Windows headers
#ifdef IN
#undef IN
#endif
#ifdef OUT
#undef OUT
#endif

BEGIN_ABSTRACT_OBJECT_REFLECTOR(osg::TransferFunction)
	I_BaseType(osg::Object);
	I_Constructor0(____TransferFunction,
	               "",
	               "");
	I_Method0(osg::Image *, getImage,
	          Properties::NON_VIRTUAL,
	          __osg_Image_P1__getImage,
	          "",
	          "");
	I_Method0(const osg::Image *, getImage,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Image_P1__getImage,
	          "",
	          "");
	I_Method0(osg::Texture *, getTexture,
	          Properties::NON_VIRTUAL,
	          __osg_Texture_P1__getTexture,
	          "",
	          "");
	I_Method0(const osg::Texture *, getTexture,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Texture_P1__getTexture,
	          "",
	          "");
	I_Method0(osg::Shader *, getShader,
	          Properties::NON_VIRTUAL,
	          __osg_Shader_P1__getShader,
	          "",
	          "");
	I_Method0(const osg::Shader *, getShader,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Shader_P1__getShader,
	          "",
	          "");
	I_SimpleProperty(osg::Image *, Image,
	                 __osg_Image_P1__getImage,
	                 0);
	I_SimpleProperty(osg::Shader *, Shader,
	                 __osg_Shader_P1__getShader,
	                 0);
	I_SimpleProperty(osg::Texture *, Texture,
	                 __osg_Texture_P1__getTexture,
	                 0);
END_REFLECTOR

BEGIN_ABSTRACT_OBJECT_REFLECTOR(osg::TransferFunction1D)
	I_BaseType(osg::TransferFunction);
	I_Constructor0(____TransferFunction1D,
	               "",
	               "");
	I_Method2(void, setInputRange, IN, float, minimum, IN, float, maximum,
	          Properties::NON_VIRTUAL,
	          __void__setInputRange__float__float,
	          "",
	          "");
	I_Method1(void, allocate, IN, unsigned int, numX,
	          Properties::NON_VIRTUAL,
	          __void__allocate__unsigned_int,
	          "",
	          "");
	I_MethodWithDefaults1(void, clear, IN, const osg::Vec4 &, color, osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
	                      Properties::NON_VIRTUAL,
	                      __void__clear__C5_osg_Vec4_R1,
	                      "",
	                      "");
	I_Method0(unsigned int, getNumberCellsX,
	          Properties::NON_VIRTUAL,
	          __unsigned_int__getNumberCellsX,
	          "",
	          "");
	I_MethodWithDefaults3(osg::Vec4 &, getValue, IN, unsigned int, i, , IN, unsigned int, j, 0, IN, unsigned int, k, 0,
	                      Properties::NON_VIRTUAL,
	                      __osg_Vec4_R1__getValue__unsigned_int__unsigned_int__unsigned_int,
	                      "",
	                      "");
	I_MethodWithDefaults3(const osg::Vec4 &, getValue, IN, unsigned int, i, , IN, unsigned int, j, 0, IN, unsigned int, k, 0,
	                      Properties::NON_VIRTUAL,
	                      __C5_osg_Vec4_R1__getValue__unsigned_int__unsigned_int__unsigned_int,
	                      "",
	                      "");
	I_SimpleProperty(unsigned int, NumberCellsX,
	                 __unsigned_int__getNumberCellsX,
	                 0);
END_REFLECTOR

<commit_msg>Updated wrappers<commit_after>// ***************************************************************************
//
//   Generated automatically by genwrapper.
//   Please DO NOT EDIT this file!
//
// ***************************************************************************

#include <osgIntrospection/ReflectionMacros>
#include <osgIntrospection/TypedMethodInfo>
#include <osgIntrospection/StaticMethodInfo>
#include <osgIntrospection/Attributes>

#include <osg/Image>
#include <osg/Shader>
#include <osg/Texture>
#include <osg/TransferFunction>
#include <osg/Vec4>

// Must undefine IN and OUT macros defined in Windows headers
#ifdef IN
#undef IN
#endif
#ifdef OUT
#undef OUT
#endif

BEGIN_VALUE_REFLECTOR(osg::TransferFunction)
	I_Constructor0(____TransferFunction,
	               "",
	               "");
	I_Method0(osg::Image *, getImage,
	          Properties::NON_VIRTUAL,
	          __osg_Image_P1__getImage,
	          "",
	          "");
	I_Method0(const osg::Image *, getImage,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Image_P1__getImage,
	          "",
	          "");
	I_Method0(osg::Texture *, getTexture,
	          Properties::NON_VIRTUAL,
	          __osg_Texture_P1__getTexture,
	          "",
	          "");
	I_Method0(const osg::Texture *, getTexture,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Texture_P1__getTexture,
	          "",
	          "");
	I_Method0(osg::Shader *, getShader,
	          Properties::NON_VIRTUAL,
	          __osg_Shader_P1__getShader,
	          "",
	          "");
	I_Method0(const osg::Shader *, getShader,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Shader_P1__getShader,
	          "",
	          "");
	I_SimpleProperty(osg::Image *, Image,
	                 __osg_Image_P1__getImage,
	                 0);
	I_SimpleProperty(osg::Shader *, Shader,
	                 __osg_Shader_P1__getShader,
	                 0);
	I_SimpleProperty(osg::Texture *, Texture,
	                 __osg_Texture_P1__getTexture,
	                 0);
END_REFLECTOR

BEGIN_OBJECT_REFLECTOR(osg::TransferFunction1D)
	I_BaseType(osg::TransferFunction);
	I_Constructor0(____TransferFunction1D,
	               "",
	               "");
	I_Method2(void, setInputRange, IN, float, minimum, IN, float, maximum,
	          Properties::NON_VIRTUAL,
	          __void__setInputRange__float__float,
	          "",
	          "");
	I_Method1(void, allocate, IN, unsigned int, numX,
	          Properties::NON_VIRTUAL,
	          __void__allocate__unsigned_int,
	          "",
	          "");
	I_MethodWithDefaults1(void, clear, IN, const osg::Vec4 &, color, osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
	                      Properties::NON_VIRTUAL,
	                      __void__clear__C5_osg_Vec4_R1,
	                      "",
	                      "");
	I_Method0(unsigned int, getNumberCellsX,
	          Properties::NON_VIRTUAL,
	          __unsigned_int__getNumberCellsX,
	          "",
	          "");
	I_Method1(osg::Vec4 &, getValue, IN, unsigned int, i,
	          Properties::NON_VIRTUAL,
	          __osg_Vec4_R1__getValue__unsigned_int,
	          "",
	          "");
	I_Method1(const osg::Vec4 &, getValue, IN, unsigned int, i,
	          Properties::NON_VIRTUAL,
	          __C5_osg_Vec4_R1__getValue__unsigned_int,
	          "",
	          "");
	I_SimpleProperty(unsigned int, NumberCellsX,
	                 __unsigned_int__getNumberCellsX,
	                 0);
END_REFLECTOR

<|endoftext|>


<commit_before>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "parser_clang/pch.h"
#include "parser_clang/coClangSourceParser.h"
#include "pattern/scope/coDefer.h"
#include "lang/result/coResult_f.h"
#include "lang/reflect/coType.h"
#include "lang/reflect/coField.h"
#include "parser/source/coParsedType.h"
#include "parser/source/coParsedField.h"
#include "container/string/coDynamicString_f.h"
#include "container/array/coDynamicArray_f.h"
#include "container/array/coConstArray_f.h"
#include "memory/allocator/coLocalAllocator.h"
#include "io/path/coPath_f.h"
#include "io/path/coPathStatus.h"
#include "io/dir/coDirectory_f.h"

static coConstString co_GetClangErrorString(CXErrorCode _errorCode)
{
	switch (_errorCode)
	{
	case CXError_Success: return "";
	case CXError_Failure: return "Generic error, no further details are available.";
	case CXError_Crashed: return "Libclang crashed while performing the requested operation.";
	case CXError_InvalidArguments: return "The function detected that the arguments violate the function contract.";
	case CXError_ASTReadError: return "An AST deserialization error has occurred.";
	default: return "Unknown error code";
	}
}

coSourceParser* coSourceParser::Create()
{
	return new coClangSourceParser();
}

coClangSourceParser::coClangSourceParser()
	: clangIndex(nullptr)
{

}

coClangSourceParser::~coClangSourceParser()
{
	if (clangIndex)
	{
		clang_disposeIndex(clangIndex);
	}
	coDeleteElementsAndClear(stringBuffer);
}

coResult coClangSourceParser::OnInit(const coObject::InitConfig& _config)
{
	coTRY(Super::OnInit(_config), nullptr);
	const InitConfig& config = static_cast<const InitConfig&>(_config);

	coASSERT(!clangIndex);
	clangIndex = clang_createIndex(1, 1);

	buildDir = config.buildDir;
	coTRY(coCreateDirsIfMissing(buildDir), "Failed to create the build directory: "<<buildDir);

	coTRY(InitCommonParseArgs(config), nullptr);
	if (config.precompiledHeaderSourcePath != "")
	{
		coTRY(InitPrecompiledHeader(config), nullptr);
	}
	coTRY(InitSourceParseArgs(config), nullptr);

	return true;
}

coResult coClangSourceParser::InitCommonParseArgs(const InitConfig& _config)
{
	coTRY(commonParseArgs.count == 0, nullptr);
	commonParseArgs = { "-x", "c++", "-std=c++11", "-fms-compatibility-version=19", "-D", "coREFLECTION_PARSING" };
	for (const coConstString& includeDir : _config.includeDirs)
	{
		coDynamicString* s = new coDynamicString();
		coPushBack(stringBuffer, s);
		coTRY(includeDir != "", "Null include dir specified.");
		*s = "-I";
		*s << includeDir;
		coNullTerminate(*s);
		coPushBack(commonParseArgs, static_cast<const coChar*>(s->data));
	}

	return true;
}

coResult coClangSourceParser::InitSourceParseArgs(const InitConfig& /*_config*/)
{
	coTRY(sourceParseArgs.count == 0, nullptr);
	coPushBackArray(sourceParseArgs, commonParseArgs);
	if (precompiledHeaderPath != "")
	{
		coPushBack(sourceParseArgs, "-include-pch");
		coNullTerminate(precompiledHeaderPath);
		coPushBack(sourceParseArgs, precompiledHeaderPath.data);
	}
	return true;
}

coResult coClangSourceParser::InitPrecompiledHeader(const InitConfig& _config)
{
	coLocalAllocator localAllocator(2048);

	// Check out dir
	/*{
	coPathStatus status;
	coTRY(coGetPathStatus(status, _config.outPath), nullptr);
	coTRY(status.Exists(), "The output directory does not exist: "<<_config.outPath);
	}*/

	// Build file path
	coDynamicString filePath(localAllocator);
	{
		filePath = _config.precompiledHeaderSourcePath;
		coTRY(coIsFile(filePath), "Not a file: " << filePath);
		coNullTerminate(filePath);
	}

	// Build precompiled header path
	{
		coConstString baseName;
		coGetBaseName(baseName, _config.precompiledHeaderSourcePath);
		coJoinPaths(precompiledHeaderPath, buildDir, baseName);
		precompiledHeaderPath << ".pch";
		coNullTerminate(precompiledHeaderPath);
	}

	// Parse
	{
		CXTranslationUnit translationUnit = nullptr;
		//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, commonParseArgs.count, commonParseArgs.data, 0, nullptr);
		const CXErrorCode parseError = clang_parseTranslationUnit2(clangIndex, filePath.data, commonParseArgs.data, commonParseArgs.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
		coTRY(parseError == CXError_Success, "Clang failed to parse the file: " << filePath << " (libclang: "<< co_GetClangErrorString(parseError) << ")");
		coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
		coDEFER() { clang_disposeTranslationUnit(translationUnit); };
		const CXSaveError saveError = static_cast<CXSaveError>(clang_saveTranslationUnit(translationUnit, precompiledHeaderPath.data, 0));
		coTRY(saveError == CXSaveError_None, "Clang failed to save the file: " << precompiledHeaderPath.data);
	}

	return true;
}

coResult coClangSourceParser::Parse(ParseResult& _result, const ParseConfig& _config)
{
	coTRY(Super::Parse(_result, _config), nullptr);
	coLocalAllocator localAllocator(2048);

	coDynamicString filePath(localAllocator);
	filePath = _config.filePath;
	coNullTerminate(filePath);
	CXTranslationUnit translationUnit = nullptr;
	//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, sourceParseArgs.count, sourceParseArgs.data, 0, nullptr);
	const CXErrorCode error = clang_parseTranslationUnit2(clangIndex, filePath.data, sourceParseArgs.data, sourceParseArgs.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
	coTRY(error == CXError_Success, "Clang failed to parse the file: " << filePath << " (libclang: " << co_GetClangErrorString(error) << ")");
	coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
	coDEFER() { clang_disposeTranslationUnit(translationUnit); };
	CXCursor cursor = clang_getTranslationUnitCursor(translationUnit);

	if (_result.parsedTypes)
	{
		coTRY(ParseTypes(_result, cursor), "Failed to parse types");
	}
	return true;
}

CXChildVisitResult coClangSourceParser::ParseTypesVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coClangSourceParser* _this = scope->parser;
	const coBool definition = clang_isCursorDefinition(_child) != 0;
	if (!definition)
		return CXChildVisitResult::CXChildVisit_Continue;

	switch (_child.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		const CXSourceLocation location = clang_getCursorLocation(_child);
		if (clang_Location_isFromMainFile(location))
		{
			const CXCursor reflectedAttr = FindAttribute(_child, "Reflected");
			if (!clang_Cursor_isNull(reflectedAttr))
			{
				coASSERT(scope->result);

				if (!_this->ParseType(*scope->result, _child))
				{
					coERROR("Failed");
					return CXChildVisitResult::CXChildVisit_Break;
				}
			}
		}
		break;
	}
	}
	return CXChildVisitResult::CXChildVisit_Continue;
}

CXChildVisitResult coClangSourceParser::ParseTypeChildrenVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coASSERT(scope);
	coClangSourceParser* _this = scope->parser;
	if (!_this->ParseTypeChild(*scope, _child))
	{
		coERROR("Failed to parse type child");
		CXChildVisitResult::CXChildVisit_Break;
	}

	return CXChildVisitResult::CXChildVisit_Continue;
}

coResult coClangSourceParser::ParseTypeChild(const ScopeInfo& scope, const CXCursor& _cursor)
{
	coTRY(scope.curType, nullptr);
	switch (_cursor.kind)
	{
	case CXCursor_StructDecl:
	{
		int x = 0;
		++x;
		break;
	}
	case CXCursor_FieldDecl:
	{
		coParsedField* parsedField = new coParsedField();
		parsedField->field = new coField();
		coDEFER() { delete parsedField; };
		coTRY(ParseField(*parsedField, _cursor), "Failed to parse field: " << parsedField->field->name);
		coPushBack(scope.curType->parsedFields, parsedField);
		parsedField = nullptr;
		break;
	}
	case CXCursor_VarDecl: // Static field
	{
		break;
	}
	case CXCursor_CXXMethod: // Both static and non-static
	{
		const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
		if (staticMethod)
		{

		}
		else
		{

		}
		break;
	}
	}
	return true;
}

coResult coClangSourceParser::ParseTypes(ParseResult& _result, const CXCursor& _cursor)
{
	coASSERT(_result.parsedTypes);
	ScopeInfo scope;
	scope.parser = this;
	scope.result = &_result;
	clang_visitChildren(_cursor, &ParseTypesVisitor, &scope);
	return true;
}

coResult coClangSourceParser::ParseType(ParseResult& _result, const CXCursor& _cursor)
{
	coParsedType* parsedType = new coParsedType();
	coDEFER() { delete parsedType; };
	parsedType->type = new coType();
	coTRY(ParseSymbol(*parsedType->type, _cursor), nullptr);
	ScopeInfo scope;
	scope.parser = this;
	scope.curType = parsedType;
	clang_visitChildren(_cursor, &ParseTypeChildrenVisitor, &scope);
	coPushBack(*_result.parsedTypes, parsedType);
	parsedType = nullptr; // Release from defer
	return true;
}

coResult coClangSourceParser::ParseField(coParsedField& _parsedField, const CXCursor& _cursor)
{
	coTRY(ParseSymbol(*_parsedField.field, _cursor), nullptr);
	const CXType type = clang_getCursorType(_cursor);
	const CXType canonicalType = clang_getCanonicalType(type);
	const CXCursor typeCursor = clang_getTypeDeclaration(canonicalType);
	const CXString typeSpelling = clang_getCursorSpelling(typeCursor);
	coDEFER() { clang_disposeString(typeSpelling); };
	_parsedField.typeName = clang_getCString(typeSpelling);
	return true;
}

coResult coClangSourceParser::ParseSymbol(coSymbol& _symbol, const CXCursor& _cursor)
{
	const CXString name = clang_getCursorSpelling(_cursor);
	coDEFER() { clang_disposeString(name); };
	_symbol.name = clang_getCString(name);

	const CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(_cursor);
	if (access == CX_CXXPublic)
		_symbol.symbolFlags |= coType::public_;
	return true;
}

coResult coClangSourceParser::ParseMethod(coParsedFunction& /*_function*/, const CXCursor& _cursor)
{
	const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
	if (staticMethod)
	{

	}
	else
	{

	}
	return true;
}

CXCursor coClangSourceParser::FindAttribute(const CXCursor& _cursor, const coConstString& _attr)
{
	switch (_cursor.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		struct Result
		{
			Result(const coConstString& _structName) : cursor(clang_getNullCursor()), structName(_structName) {}
			CXCursor cursor;
			const coConstString& structName;
		};
		static const coConstString attributePrefix("_attribute_");
		coDynamicString structName;
		structName << attributePrefix;
		structName << _attr;
		Result result(structName);
		auto AttributeVisitor = [](CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
		{
			if (_child.kind == CXCursor_StructDecl)
			{
				CXString cursorStr = clang_getCursorDisplayName(_child);
				coDEFER() { clang_disposeString(cursorStr); };
				const coConstString name = clang_getCString(cursorStr);
				Result* result = static_cast<Result*>(_clientData);
				if (name == result->structName)
				{
					result->cursor = _child;
					return CXChildVisit_Break;
				}
			}
			return CXChildVisit_Continue;
		};
		clang_visitChildren(_cursor, AttributeVisitor, &result);
		return result.cursor;
		break;
	}
	}

	return clang_getNullCursor();
}
<commit_msg>Removed pragma once outside header warning.<commit_after>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "parser_clang/pch.h"
#include "parser_clang/coClangSourceParser.h"
#include "pattern/scope/coDefer.h"
#include "lang/result/coResult_f.h"
#include "lang/reflect/coType.h"
#include "lang/reflect/coField.h"
#include "parser/source/coParsedType.h"
#include "parser/source/coParsedField.h"
#include "container/string/coDynamicString_f.h"
#include "container/array/coDynamicArray_f.h"
#include "container/array/coConstArray_f.h"
#include "memory/allocator/coLocalAllocator.h"
#include "io/path/coPath_f.h"
#include "io/path/coPathStatus.h"
#include "io/dir/coDirectory_f.h"

static coConstString co_GetClangErrorString(CXErrorCode _errorCode)
{
	switch (_errorCode)
	{
	case CXError_Success: return "";
	case CXError_Failure: return "Generic error, no further details are available.";
	case CXError_Crashed: return "Libclang crashed while performing the requested operation.";
	case CXError_InvalidArguments: return "The function detected that the arguments violate the function contract.";
	case CXError_ASTReadError: return "An AST deserialization error has occurred.";
	default: return "Unknown error code";
	}
}

coSourceParser* coSourceParser::Create()
{
	return new coClangSourceParser();
}

coClangSourceParser::coClangSourceParser()
	: clangIndex(nullptr)
{

}

coClangSourceParser::~coClangSourceParser()
{
	if (clangIndex)
	{
		clang_disposeIndex(clangIndex);
	}
	coDeleteElementsAndClear(stringBuffer);
}

coResult coClangSourceParser::OnInit(const coObject::InitConfig& _config)
{
	coTRY(Super::OnInit(_config), nullptr);
	const InitConfig& config = static_cast<const InitConfig&>(_config);

	coASSERT(!clangIndex);
	clangIndex = clang_createIndex(1, 1);

	buildDir = config.buildDir;
	coTRY(coCreateDirsIfMissing(buildDir), "Failed to create the build directory: "<<buildDir);

	coTRY(InitCommonParseArgs(config), nullptr);
	if (config.precompiledHeaderSourcePath != "")
	{
		coTRY(InitPrecompiledHeader(config), nullptr);
	}
	coTRY(InitSourceParseArgs(config), nullptr);

	return true;
}

coResult coClangSourceParser::InitCommonParseArgs(const InitConfig& _config)
{
	coTRY(commonParseArgs.count == 0, nullptr);
	commonParseArgs = { "-x", "c++", "-std=c++11", "-fms-compatibility-version=19", "-Wno-pragma-once-outside-header", "-D", "coREFLECTION_PARSING" };
	for (const coConstString& includeDir : _config.includeDirs)
	{
		coDynamicString* s = new coDynamicString();
		coPushBack(stringBuffer, s);
		coTRY(includeDir != "", "Null include dir specified.");
		*s = "-I";
		*s << includeDir;
		coNullTerminate(*s);
		coPushBack(commonParseArgs, static_cast<const coChar*>(s->data));
	}

	return true;
}

coResult coClangSourceParser::InitSourceParseArgs(const InitConfig& /*_config*/)
{
	coTRY(sourceParseArgs.count == 0, nullptr);
	coPushBackArray(sourceParseArgs, commonParseArgs);
	if (precompiledHeaderPath != "")
	{
		coPushBack(sourceParseArgs, "-include-pch");
		coNullTerminate(precompiledHeaderPath);
		coPushBack(sourceParseArgs, precompiledHeaderPath.data);
	}
	return true;
}

coResult coClangSourceParser::InitPrecompiledHeader(const InitConfig& _config)
{
	coLocalAllocator localAllocator(2048);

	// Check out dir
	/*{
	coPathStatus status;
	coTRY(coGetPathStatus(status, _config.outPath), nullptr);
	coTRY(status.Exists(), "The output directory does not exist: "<<_config.outPath);
	}*/

	// Build file path
	coDynamicString filePath(localAllocator);
	{
		filePath = _config.precompiledHeaderSourcePath;
		coTRY(coIsFile(filePath), "Not a file: " << filePath);
		coNullTerminate(filePath);
	}

	// Build precompiled header path
	{
		coConstString baseName;
		coGetBaseName(baseName, _config.precompiledHeaderSourcePath);
		coJoinPaths(precompiledHeaderPath, buildDir, baseName);
		precompiledHeaderPath << ".pch";
		coNullTerminate(precompiledHeaderPath);
	}

	// Parse
	{
		CXTranslationUnit translationUnit = nullptr;
		//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, commonParseArgs.count, commonParseArgs.data, 0, nullptr);
		const CXErrorCode parseError = clang_parseTranslationUnit2(clangIndex, filePath.data, commonParseArgs.data, commonParseArgs.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
		coTRY(parseError == CXError_Success, "Clang failed to parse the file: " << filePath << " (libclang: "<< co_GetClangErrorString(parseError) << ")");
		coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
		coDEFER() { clang_disposeTranslationUnit(translationUnit); };
		const CXSaveError saveError = static_cast<CXSaveError>(clang_saveTranslationUnit(translationUnit, precompiledHeaderPath.data, 0));
		coTRY(saveError == CXSaveError_None, "Clang failed to save the file: " << precompiledHeaderPath.data);
	}

	return true;
}

coResult coClangSourceParser::Parse(ParseResult& _result, const ParseConfig& _config)
{
	coTRY(Super::Parse(_result, _config), nullptr);
	coLocalAllocator localAllocator(2048);

	coDynamicString filePath(localAllocator);
	filePath = _config.filePath;
	coNullTerminate(filePath);
	CXTranslationUnit translationUnit = nullptr;
	//translationUnit = clang_createTranslationUnitFromSourceFile(clangIndex, filePath.data, sourceParseArgs.count, sourceParseArgs.data, 0, nullptr);
	const CXErrorCode error = clang_parseTranslationUnit2(clangIndex, filePath.data, sourceParseArgs.data, sourceParseArgs.count, nullptr, 0, CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_Incomplete, &translationUnit);
	coTRY(error == CXError_Success, "Clang failed to parse the file: " << filePath << " (libclang: " << co_GetClangErrorString(error) << ")");
	coTRY(translationUnit, "Can't create translation unit from source file: " << filePath);
	coDEFER() { clang_disposeTranslationUnit(translationUnit); };
	CXCursor cursor = clang_getTranslationUnitCursor(translationUnit);

	if (_result.parsedTypes)
	{
		coTRY(ParseTypes(_result, cursor), "Failed to parse types");
	}
	return true;
}

CXChildVisitResult coClangSourceParser::ParseTypesVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coClangSourceParser* _this = scope->parser;
	const coBool definition = clang_isCursorDefinition(_child) != 0;
	if (!definition)
		return CXChildVisitResult::CXChildVisit_Continue;

	switch (_child.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		const CXSourceLocation location = clang_getCursorLocation(_child);
		if (clang_Location_isFromMainFile(location))
		{
			const CXCursor reflectedAttr = FindAttribute(_child, "Reflected");
			if (!clang_Cursor_isNull(reflectedAttr))
			{
				coASSERT(scope->result);

				if (!_this->ParseType(*scope->result, _child))
				{
					coERROR("Failed");
					return CXChildVisitResult::CXChildVisit_Break;
				}
			}
		}
		break;
	}
	}
	return CXChildVisitResult::CXChildVisit_Continue;
}

CXChildVisitResult coClangSourceParser::ParseTypeChildrenVisitor(CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
{
	const ScopeInfo* scope = static_cast<const ScopeInfo*>(_clientData);
	coASSERT(scope);
	coClangSourceParser* _this = scope->parser;
	if (!_this->ParseTypeChild(*scope, _child))
	{
		coERROR("Failed to parse type child");
		CXChildVisitResult::CXChildVisit_Break;
	}

	return CXChildVisitResult::CXChildVisit_Continue;
}

coResult coClangSourceParser::ParseTypeChild(const ScopeInfo& scope, const CXCursor& _cursor)
{
	coTRY(scope.curType, nullptr);
	switch (_cursor.kind)
	{
	case CXCursor_StructDecl:
	{
		int x = 0;
		++x;
		break;
	}
	case CXCursor_FieldDecl:
	{
		coParsedField* parsedField = new coParsedField();
		parsedField->field = new coField();
		coDEFER() { delete parsedField; };
		coTRY(ParseField(*parsedField, _cursor), "Failed to parse field: " << parsedField->field->name);
		coPushBack(scope.curType->parsedFields, parsedField);
		parsedField = nullptr;
		break;
	}
	case CXCursor_VarDecl: // Static field
	{
		break;
	}
	case CXCursor_CXXMethod: // Both static and non-static
	{
		const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
		if (staticMethod)
		{

		}
		else
		{

		}
		break;
	}
	}
	return true;
}

coResult coClangSourceParser::ParseTypes(ParseResult& _result, const CXCursor& _cursor)
{
	coASSERT(_result.parsedTypes);
	ScopeInfo scope;
	scope.parser = this;
	scope.result = &_result;
	clang_visitChildren(_cursor, &ParseTypesVisitor, &scope);
	return true;
}

coResult coClangSourceParser::ParseType(ParseResult& _result, const CXCursor& _cursor)
{
	coParsedType* parsedType = new coParsedType();
	coDEFER() { delete parsedType; };
	parsedType->type = new coType();
	coTRY(ParseSymbol(*parsedType->type, _cursor), nullptr);
	ScopeInfo scope;
	scope.parser = this;
	scope.curType = parsedType;
	clang_visitChildren(_cursor, &ParseTypeChildrenVisitor, &scope);
	coPushBack(*_result.parsedTypes, parsedType);
	parsedType = nullptr; // Release from defer
	return true;
}

coResult coClangSourceParser::ParseField(coParsedField& _parsedField, const CXCursor& _cursor)
{
	coTRY(ParseSymbol(*_parsedField.field, _cursor), nullptr);
	const CXType type = clang_getCursorType(_cursor);
	const CXType canonicalType = clang_getCanonicalType(type);
	const CXCursor typeCursor = clang_getTypeDeclaration(canonicalType);
	const CXString typeSpelling = clang_getCursorSpelling(typeCursor);
	coDEFER() { clang_disposeString(typeSpelling); };
	_parsedField.typeName = clang_getCString(typeSpelling);
	return true;
}

coResult coClangSourceParser::ParseSymbol(coSymbol& _symbol, const CXCursor& _cursor)
{
	const CXString name = clang_getCursorSpelling(_cursor);
	coDEFER() { clang_disposeString(name); };
	_symbol.name = clang_getCString(name);

	const CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(_cursor);
	if (access == CX_CXXPublic)
		_symbol.symbolFlags |= coType::public_;
	return true;
}

coResult coClangSourceParser::ParseMethod(coParsedFunction& /*_function*/, const CXCursor& _cursor)
{
	const coBool staticMethod = clang_CXXMethod_isStatic(_cursor) != 0;
	if (staticMethod)
	{

	}
	else
	{

	}
	return true;
}

CXCursor coClangSourceParser::FindAttribute(const CXCursor& _cursor, const coConstString& _attr)
{
	switch (_cursor.kind)
	{
	case CXCursor_ClassDecl:
	case CXCursor_StructDecl:
	{
		struct Result
		{
			Result(const coConstString& _structName) : cursor(clang_getNullCursor()), structName(_structName) {}
			CXCursor cursor;
			const coConstString& structName;
		};
		static const coConstString attributePrefix("_attribute_");
		coDynamicString structName;
		structName << attributePrefix;
		structName << _attr;
		Result result(structName);
		auto AttributeVisitor = [](CXCursor _child, CXCursor /*_parent*/, CXClientData _clientData)
		{
			if (_child.kind == CXCursor_StructDecl)
			{
				CXString cursorStr = clang_getCursorDisplayName(_child);
				coDEFER() { clang_disposeString(cursorStr); };
				const coConstString name = clang_getCString(cursorStr);
				Result* result = static_cast<Result*>(_clientData);
				if (name == result->structName)
				{
					result->cursor = _child;
					return CXChildVisit_Break;
				}
			}
			return CXChildVisit_Continue;
		};
		clang_visitChildren(_cursor, AttributeVisitor, &result);
		return result.cursor;
		break;
	}
	}

	return clang_getNullCursor();
}
<|endoftext|>


<commit_before>/*****************************************************************************
  intersectMain.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licenced under the GNU General Public License 2.0 license.
******************************************************************************/
#include "intersectBed.h"
#include "version.h"

using namespace std;

// define our program name
#define PROGRAM_NAME "bedtools intersect"

// define our parameter checking macro
#define PARAMETER_CHECK(param, paramLen, actualLen) (strncmp(argv[i], param, min(actualLen, paramLen))== 0) && (actualLen == paramLen)

// function declarations
void intersect_help(void);

int intersect_main(int argc, char* argv[]) {

    // our configuration variables
    bool showHelp = false;

    // input files
    string bedAFile;
    string bedBFile;

    // input arguments
    float overlapFraction = 1E-9;

    bool haveBedA           = false;
    bool haveBedB           = false;
    bool noHit              = false;
    bool leftJoin           = false;
    bool anyHit             = false;
    bool writeA             = false;
    bool writeB             = false;
    bool writeCount         = false;
    bool writeOverlap       = false;
    bool writeAllOverlap    = false;
    bool haveFraction       = false;
    bool reciprocalFraction = false;
    bool sameStrand         = false;
    bool diffStrand         = false;
    bool obeySplits         = false;
    bool inputIsBam         = false;
    bool outputIsBam        = true;
    bool uncompressedBam    = false;
    bool sortedInput        = false;
    bool printHeader        = false;

    // check to see if we should print out some help
    if(argc <= 1) showHelp = true;

    for(int i = 1; i < argc; i++) {
        int parameterLength = (int)strlen(argv[i]);

        if((PARAMETER_CHECK("-h", 2, parameterLength)) ||
        (PARAMETER_CHECK("--help", 5, parameterLength))) {
            showHelp = true;
        }
    }

    if(showHelp) intersect_help();

    // do some parsing (all of these parameters require 2 strings)
    for(int i = 1; i < argc; i++) {

        int parameterLength = (int)strlen(argv[i]);

        if(PARAMETER_CHECK("-a", 2, parameterLength)) {
            if ((i+1) < argc) {
                haveBedA = true;
                outputIsBam = false;
                bedAFile = argv[i + 1];
                i++;
            }
        }
        else if(PARAMETER_CHECK("-abam", 5, parameterLength)) {
            if ((i+1) < argc) {
                haveBedA = true;
                inputIsBam = true;
                bedAFile = argv[i + 1];
                i++;
            }
        }
        else if(PARAMETER_CHECK("-b", 2, parameterLength)) {
            if ((i+1) < argc) {
                haveBedB = true;
                bedBFile = argv[i + 1];
                i++;
            }
        }
        else if(PARAMETER_CHECK("-bed", 4, parameterLength)) {
            outputIsBam = false;
        }
        else if(PARAMETER_CHECK("-u", 2, parameterLength)) {
            anyHit = true;
        }
        else if(PARAMETER_CHECK("-f", 2, parameterLength)) {
            if ((i+1) < argc) {
                haveFraction = true;
                overlapFraction = atof(argv[i + 1]);
                i++;
            }
        }
        else if(PARAMETER_CHECK("-wa", 3, parameterLength)) {
            writeA = true;
        }
        else if(PARAMETER_CHECK("-wb", 3, parameterLength)) {
            writeB = true;
        }
        else if(PARAMETER_CHECK("-wo", 3, parameterLength)) {
            writeOverlap = true;
        }
        else if(PARAMETER_CHECK("-wao", 4, parameterLength)) {
            writeAllOverlap = true;
            writeOverlap = true;
        }
        else if(PARAMETER_CHECK("-c", 2, parameterLength)) {
            writeCount = true;
        }
        else if(PARAMETER_CHECK("-r", 2, parameterLength)) {
            reciprocalFraction = true;
        }
        else if (PARAMETER_CHECK("-v", 2, parameterLength)) {
            noHit = true;
        }
        else if (PARAMETER_CHECK("-s", 2, parameterLength)) {
            sameStrand = true;
        }
        else if (PARAMETER_CHECK("-S", 2, parameterLength)) {
            diffStrand = true;
        }
        else if (PARAMETER_CHECK("-split", 6, parameterLength)) {
            obeySplits = true;
        }
        else if (PARAMETER_CHECK("-loj", 4, parameterLength)) {
            leftJoin = true;
        }
        else if(PARAMETER_CHECK("-ubam", 5, parameterLength)) {
            uncompressedBam = true;
        }
        else if(PARAMETER_CHECK("-sorted", 7, parameterLength)) {
            sortedInput = true;
        }
        else if(PARAMETER_CHECK("-header", 7, parameterLength)) {
            printHeader = true;
        }
        else {
            cerr << endl << "*****ERROR: Unrecognized parameter: " << argv[i] << " *****" << endl << endl;
            showHelp = true;
        }
    }

    // make sure we have both input files
    if (!haveBedA || !haveBedB) {
        cerr << endl << "*****" << endl << "*****ERROR: Need -a and -b files. " << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && noHit) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -v, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeB && writeCount) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wb OR -c, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeCount && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wb OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeA && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wa OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeB && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wb OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (reciprocalFraction && !haveFraction) {
        cerr << endl << "*****" << endl << "*****ERROR: If using -r, you need to define -f." << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && writeCount) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -c, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && writeB) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -wb, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (sameStrand && diffStrand) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -s OR -S, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (inputIsBam && writeB && outputIsBam) {
        cerr << endl << "*****" << endl << "*****WARNING: -wb is ignored with -abam" << endl << "*****" << endl;
    }

    if (inputIsBam && leftJoin) {
        cerr << endl << "*****" << endl << "*****WARNING: -loj is ignored with -abam" << endl << "*****" << endl;
    }

    if (outputIsBam && (writeCount || writeOverlap || writeAllOverlap))
    {
        outputIsBam = false;
    }

    if (!showHelp) {

        BedIntersect *bi = new BedIntersect(bedAFile, bedBFile, anyHit, writeA, writeB, writeOverlap,
                                            writeAllOverlap, overlapFraction, noHit, leftJoin, writeCount, sameStrand, diffStrand,
                                            reciprocalFraction, obeySplits, inputIsBam, outputIsBam, uncompressedBam,
                                            sortedInput, printHeader);
        delete bi;
        return 0;
    }
    else {
        intersect_help();
        return 0;
    }
}

void intersect_help(void) {

    cerr << "\nTool:    bedtools intersect (aka intersectBed)" << endl;
    cerr << "Version: " << VERSION << "\n";
    cerr << "Summary: Report overlaps between two feature files." << endl << endl;

    cerr << "Usage:   " << PROGRAM_NAME << " [OPTIONS] -a <bed/gff/vcf> -b <bed/gff/vcf>" << endl << endl;

    cerr << "Options: " << endl;

    cerr << "\t-abam\t"         << "The A input file is in BAM format.  Output will be BAM as well." << endl << endl;

    cerr << "\t-ubam\t"         << "Write uncompressed BAM output. Default writes compressed BAM." << endl << endl;

    cerr << "\t-bed\t"          << "When using BAM input (-abam), write output as BED. The default" << endl;
    cerr                        << "\t\tis to write output in BAM when using -abam." << endl << endl;

    cerr << "\t-wa\t"           << "Write the original entry in A for each overlap." << endl << endl;

    cerr << "\t-wb\t"           << "Write the original entry in B for each overlap." << endl;
    cerr                        << "\t\t- Useful for knowing _what_ A overlaps. Restricted by -f and -r." << endl << endl;

    cerr << "\t-loj\t"          << "Perform a \"left outer join\". That is, for each feature in A" << endl;
    cerr                        << "\t\treport each overlap with B.  If no overlaps are found, " << endl;
    cerr                        << "\t\treport a NULL feature for B." << endl << endl;

    cerr << "\t-wo\t"           << "Write the original A and B entries plus the number of base" << endl;
    cerr                        << "\t\tpairs of overlap between the two features." << endl;
    cerr                        << "\t\t- Overlaps restricted by -f and -r." << endl;
    cerr                        << "\t\t  Only A features with overlap are reported." << endl << endl;

    cerr << "\t-wao\t"          << "Write the original A and B entries plus the number of base" << endl;
    cerr                        << "\t\tpairs of overlap between the two features." << endl;
    cerr                        << "\t\t- Overlapping features restricted by -f and -r." << endl;
    cerr                        << "\t\t  However, A features w/o overlap are also reported" << endl;
    cerr                        << "\t\t  with a NULL B feature and overlap = 0." << endl << endl;

    cerr << "\t-u\t"            << "Write the original A entry _once_ if _any_ overlaps found in B." << endl;
    cerr                        << "\t\t- In other words, just report the fact >=1 hit was found." << endl;
    cerr                        << "\t\t- Overlaps restricted by -f and -r." << endl << endl;

    cerr << "\t-c\t"            << "For each entry in A, report the number of overlaps with B." << endl;
    cerr                        << "\t\t- Reports 0 for A entries that have no overlap with B." << endl;
    cerr                        << "\t\t- Overlaps restricted by -f and -r." << endl << endl;

    cerr << "\t-v\t"            << "Only report those entries in A that have _no overlaps_ with B." << endl;
    cerr                        << "\t\t- Similar to \"grep -v\" (an homage)." << endl << endl;

    cerr << "\t-f\t"            << "Minimum overlap required as a fraction of A." << endl;
    cerr                        << "\t\t- Default is 1E-9 (i.e., 1bp)." << endl;
    cerr                        << "\t\t- FLOAT (e.g. 0.50)" << endl << endl;

    cerr << "\t-r\t"            << "Require that the fraction overlap be reciprocal for A and B." << endl;
    cerr                        << "\t\t- In other words, if -f is 0.90 and -r is used, this requires" << endl;
    cerr                        << "\t\t  that B overlap 90% of A and A _also_ overlaps 90% of B." << endl << endl;

    cerr << "\t-s\t"            << "Require same strandedness.  That is, only report hits in B" << endl;
    cerr                        << "\t\tthat overlap A on the _same_ strand." << endl;
    cerr                        << "\t\t- By default, overlaps are reported without respect to strand." << endl << endl;

    cerr << "\t-S\t"            << "Require different strandedness.  That is, only report hits in B" << endl;
    cerr                        << "\t\tthat overlap A on the _opposite_ strand." << endl;
    cerr                        << "\t\t- By default, overlaps are reported without respect to strand." << endl << endl;

    cerr << "\t-split\t"        << "Treat \"split\" BAM or BED12 entries as distinct BED intervals." << endl << endl;

    cerr << "\t-sorted\t"       << "Use the \"chromsweep\" algorithm for sorted (-k1,1 -k2,2n) input" << endl << endl;

    cerr << "\t-header\t"       << "Print the header from the A file prior to results." << endl << endl;

    cerr << "Notes: " << endl;
    cerr << "\t(1) When a BAM file is used for the A file, the alignment is retained if overlaps exist," << endl;
    cerr << "\tand exlcuded if an overlap cannot be found.  If multiple overlaps exist, they are not" << endl;
    cerr << "\treported, as we are only testing for one or more overlaps." << endl << endl;

    // end the program here
    exit(1);

}
<commit_msg>[ENH] improve desc. of what -wb does.<commit_after>/*****************************************************************************
  intersectMain.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licenced under the GNU General Public License 2.0 license.
******************************************************************************/
#include "intersectBed.h"
#include "version.h"

using namespace std;

// define our program name
#define PROGRAM_NAME "bedtools intersect"

// define our parameter checking macro
#define PARAMETER_CHECK(param, paramLen, actualLen) (strncmp(argv[i], param, min(actualLen, paramLen))== 0) && (actualLen == paramLen)

// function declarations
void intersect_help(void);

int intersect_main(int argc, char* argv[]) {

    // our configuration variables
    bool showHelp = false;

    // input files
    string bedAFile;
    string bedBFile;

    // input arguments
    float overlapFraction = 1E-9;

    bool haveBedA           = false;
    bool haveBedB           = false;
    bool noHit              = false;
    bool leftJoin           = false;
    bool anyHit             = false;
    bool writeA             = false;
    bool writeB             = false;
    bool writeCount         = false;
    bool writeOverlap       = false;
    bool writeAllOverlap    = false;
    bool haveFraction       = false;
    bool reciprocalFraction = false;
    bool sameStrand         = false;
    bool diffStrand         = false;
    bool obeySplits         = false;
    bool inputIsBam         = false;
    bool outputIsBam        = true;
    bool uncompressedBam    = false;
    bool sortedInput        = false;
    bool printHeader        = false;

    // check to see if we should print out some help
    if(argc <= 1) showHelp = true;

    for(int i = 1; i < argc; i++) {
        int parameterLength = (int)strlen(argv[i]);

        if((PARAMETER_CHECK("-h", 2, parameterLength)) ||
        (PARAMETER_CHECK("--help", 5, parameterLength))) {
            showHelp = true;
        }
    }

    if(showHelp) intersect_help();

    // do some parsing (all of these parameters require 2 strings)
    for(int i = 1; i < argc; i++) {

        int parameterLength = (int)strlen(argv[i]);

        if(PARAMETER_CHECK("-a", 2, parameterLength)) {
            if ((i+1) < argc) {
                haveBedA = true;
                outputIsBam = false;
                bedAFile = argv[i + 1];
                i++;
            }
        }
        else if(PARAMETER_CHECK("-abam", 5, parameterLength)) {
            if ((i+1) < argc) {
                haveBedA = true;
                inputIsBam = true;
                bedAFile = argv[i + 1];
                i++;
            }
        }
        else if(PARAMETER_CHECK("-b", 2, parameterLength)) {
            if ((i+1) < argc) {
                haveBedB = true;
                bedBFile = argv[i + 1];
                i++;
            }
        }
        else if(PARAMETER_CHECK("-bed", 4, parameterLength)) {
            outputIsBam = false;
        }
        else if(PARAMETER_CHECK("-u", 2, parameterLength)) {
            anyHit = true;
        }
        else if(PARAMETER_CHECK("-f", 2, parameterLength)) {
            if ((i+1) < argc) {
                haveFraction = true;
                overlapFraction = atof(argv[i + 1]);
                i++;
            }
        }
        else if(PARAMETER_CHECK("-wa", 3, parameterLength)) {
            writeA = true;
        }
        else if(PARAMETER_CHECK("-wb", 3, parameterLength)) {
            writeB = true;
        }
        else if(PARAMETER_CHECK("-wo", 3, parameterLength)) {
            writeOverlap = true;
        }
        else if(PARAMETER_CHECK("-wao", 4, parameterLength)) {
            writeAllOverlap = true;
            writeOverlap = true;
        }
        else if(PARAMETER_CHECK("-c", 2, parameterLength)) {
            writeCount = true;
        }
        else if(PARAMETER_CHECK("-r", 2, parameterLength)) {
            reciprocalFraction = true;
        }
        else if (PARAMETER_CHECK("-v", 2, parameterLength)) {
            noHit = true;
        }
        else if (PARAMETER_CHECK("-s", 2, parameterLength)) {
            sameStrand = true;
        }
        else if (PARAMETER_CHECK("-S", 2, parameterLength)) {
            diffStrand = true;
        }
        else if (PARAMETER_CHECK("-split", 6, parameterLength)) {
            obeySplits = true;
        }
        else if (PARAMETER_CHECK("-loj", 4, parameterLength)) {
            leftJoin = true;
        }
        else if(PARAMETER_CHECK("-ubam", 5, parameterLength)) {
            uncompressedBam = true;
        }
        else if(PARAMETER_CHECK("-sorted", 7, parameterLength)) {
            sortedInput = true;
        }
        else if(PARAMETER_CHECK("-header", 7, parameterLength)) {
            printHeader = true;
        }
        else {
            cerr << endl << "*****ERROR: Unrecognized parameter: " << argv[i] << " *****" << endl << endl;
            showHelp = true;
        }
    }

    // make sure we have both input files
    if (!haveBedA || !haveBedB) {
        cerr << endl << "*****" << endl << "*****ERROR: Need -a and -b files. " << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && noHit) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -v, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeB && writeCount) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wb OR -c, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeCount && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wb OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeA && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wa OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (writeB && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -wb OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (reciprocalFraction && !haveFraction) {
        cerr << endl << "*****" << endl << "*****ERROR: If using -r, you need to define -f." << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && writeCount) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -c, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && writeB) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -wb, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (anyHit && writeOverlap) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -u OR -wo, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (sameStrand && diffStrand) {
        cerr << endl << "*****" << endl << "*****ERROR: Request either -s OR -S, not both." << endl << "*****" << endl;
        showHelp = true;
    }

    if (inputIsBam && writeB && outputIsBam) {
        cerr << endl << "*****" << endl << "*****WARNING: -wb is ignored with -abam" << endl << "*****" << endl;
    }

    if (inputIsBam && leftJoin) {
        cerr << endl << "*****" << endl << "*****WARNING: -loj is ignored with -abam" << endl << "*****" << endl;
    }

    if (outputIsBam && (writeCount || writeOverlap || writeAllOverlap))
    {
        outputIsBam = false;
    }

    if (!showHelp) {

        BedIntersect *bi = new BedIntersect(bedAFile, bedBFile, anyHit, writeA, writeB, writeOverlap,
                                            writeAllOverlap, overlapFraction, noHit, leftJoin, writeCount, sameStrand, diffStrand,
                                            reciprocalFraction, obeySplits, inputIsBam, outputIsBam, uncompressedBam,
                                            sortedInput, printHeader);
        delete bi;
        return 0;
    }
    else {
        intersect_help();
        return 0;
    }
}

void intersect_help(void) {

    cerr << "\nTool:    bedtools intersect (aka intersectBed)" << endl;
    cerr << "Version: " << VERSION << "\n";
    cerr << "Summary: Report overlaps between two feature files." << endl << endl;

    cerr << "Usage:   " << PROGRAM_NAME << " [OPTIONS] -a <bed/gff/vcf> -b <bed/gff/vcf>" << endl << endl;

    cerr << "Options: " << endl;

    cerr << "\t-abam\t"         << "The A input file is in BAM format.  Output will be BAM as well." << endl << endl;

    cerr << "\t-ubam\t"         << "Write uncompressed BAM output. Default writes compressed BAM." << endl << endl;

    cerr << "\t-bed\t"          << "When using BAM input (-abam), write output as BED. The default" << endl;
    cerr                        << "\t\tis to write output in BAM when using -abam." << endl << endl;

    cerr << "\t-wa\t"           << "Write the original entry in A for each overlap." << endl << endl;

    cerr << "\t-wb\t"           << "Follow the A entry with the original "
                                << "entry in B for each overlap." << endl;
    cerr                        << "\t\t- Useful for knowing _what_ A overlaps. Restricted by -f and -r." << endl << endl;

    cerr << "\t-loj\t"          << "Perform a \"left outer join\". That is, for each feature in A" << endl;
    cerr                        << "\t\treport each overlap with B.  If no overlaps are found, " << endl;
    cerr                        << "\t\treport a NULL feature for B." << endl << endl;

    cerr << "\t-wo\t"           << "Write the original A and B entries plus the number of base" << endl;
    cerr                        << "\t\tpairs of overlap between the two features." << endl;
    cerr                        << "\t\t- Overlaps restricted by -f and -r." << endl;
    cerr                        << "\t\t  Only A features with overlap are reported." << endl << endl;

    cerr << "\t-wao\t"          << "Write the original A and B entries plus the number of base" << endl;
    cerr                        << "\t\tpairs of overlap between the two features." << endl;
    cerr                        << "\t\t- Overlapping features restricted by -f and -r." << endl;
    cerr                        << "\t\t  However, A features w/o overlap are also reported" << endl;
    cerr                        << "\t\t  with a NULL B feature and overlap = 0." << endl << endl;

    cerr << "\t-u\t"            << "Write the original A entry _once_ if _any_ overlaps found in B." << endl;
    cerr                        << "\t\t- In other words, just report the fact >=1 hit was found." << endl;
    cerr                        << "\t\t- Overlaps restricted by -f and -r." << endl << endl;

    cerr << "\t-c\t"            << "For each entry in A, report the number of overlaps with B." << endl;
    cerr                        << "\t\t- Reports 0 for A entries that have no overlap with B." << endl;
    cerr                        << "\t\t- Overlaps restricted by -f and -r." << endl << endl;

    cerr << "\t-v\t"            << "Only report those entries in A that have _no overlaps_ with B." << endl;
    cerr                        << "\t\t- Similar to \"grep -v\" (an homage)." << endl << endl;

    cerr << "\t-f\t"            << "Minimum overlap required as a fraction of A." << endl;
    cerr                        << "\t\t- Default is 1E-9 (i.e., 1bp)." << endl;
    cerr                        << "\t\t- FLOAT (e.g. 0.50)" << endl << endl;

    cerr << "\t-r\t"            << "Require that the fraction overlap be reciprocal for A and B." << endl;
    cerr                        << "\t\t- In other words, if -f is 0.90 and -r is used, this requires" << endl;
    cerr                        << "\t\t  that B overlap 90% of A and A _also_ overlaps 90% of B." << endl << endl;

    cerr << "\t-s\t"            << "Require same strandedness.  That is, only report hits in B" << endl;
    cerr                        << "\t\tthat overlap A on the _same_ strand." << endl;
    cerr                        << "\t\t- By default, overlaps are reported without respect to strand." << endl << endl;

    cerr << "\t-S\t"            << "Require different strandedness.  That is, only report hits in B" << endl;
    cerr                        << "\t\tthat overlap A on the _opposite_ strand." << endl;
    cerr                        << "\t\t- By default, overlaps are reported without respect to strand." << endl << endl;

    cerr << "\t-split\t"        << "Treat \"split\" BAM or BED12 entries as distinct BED intervals." << endl << endl;

    cerr << "\t-sorted\t"       << "Use the \"chromsweep\" algorithm for sorted (-k1,1 -k2,2n) input" << endl << endl;

    cerr << "\t-header\t"       << "Print the header from the A file prior to results." << endl << endl;

    cerr << "Notes: " << endl;
    cerr << "\t(1) When a BAM file is used for the A file, the alignment is retained if overlaps exist," << endl;
    cerr << "\tand exlcuded if an overlap cannot be found.  If multiple overlaps exist, they are not" << endl;
    cerr << "\treported, as we are only testing for one or more overlaps." << endl << endl;

    // end the program here
    exit(1);

}
<|endoftext|>


<commit_before>#include <ace-c/Optimizer.hpp>
#include <ace-c/ast/AstModuleDeclaration.hpp>
#include <ace-c/ast/AstBinaryExpression.hpp>
#include <ace-c/ast/AstVariable.hpp>
#include <ace-c/ast/AstConstant.hpp>

#include <common/my_assert.hpp>

void Optimizer::OptimizeExpr(std::shared_ptr<AstExpression> &expr, AstVisitor *visitor, Module *mod)
{
    ASSERT(expr != nullptr);
    expr->Optimize(visitor, mod);

    if (auto *expr_as_var = dynamic_cast<AstVariable*>(expr.get())) {
        // the side is a variable, so we can further optimize by inlining,
        // only if it is const, and a literal.
        if (expr_as_var->GetProperties().GetIdentifier()) {
            if (expr_as_var->GetProperties().GetIdentifier()->GetFlags() & FLAG_CONST) {
                // the variable is a const, now we make sure that the current
                // value is a literal value
                if (auto *constant = dynamic_cast<AstConstant*>(
                    expr_as_var->GetProperties().GetIdentifier()->GetCurrentValue().get())) {
                    // yay! we were able to retrieve the value that
                    // the variable is set to, so now we can use that
                    // at compile-time rather than using a variable.
                    expr.reset(constant);
                }
            }
        }
    } else if (auto *expr_as_binop = dynamic_cast<AstBinaryExpression*>(expr.get())) {
        if (!expr_as_binop->GetRight()) {
            // right side has been optimized away, to just left side
            expr = expr_as_binop->GetLeft();
        }
    }
}

Optimizer::Optimizer(AstIterator *ast_iterator, CompilationUnit *compilation_unit)
    : AstVisitor(ast_iterator, compilation_unit)
{
}

Optimizer::Optimizer(const Optimizer &other)
    : AstVisitor(other.m_ast_iterator, other.m_compilation_unit)
{
}

void Optimizer::Optimize(bool expect_module_decl)
{
    if (expect_module_decl) {
        if (m_ast_iterator->HasNext()) {
            auto first_statement = m_ast_iterator->Next();
            auto module_declaration = std::dynamic_pointer_cast<AstModuleDeclaration>(first_statement);

            if (module_declaration) {
                // all files must begin with a module declaration
                module_declaration->Optimize(this, nullptr);
                OptimizeInner();
            }
        }
    } else {
        OptimizeInner();
    }
}

void Optimizer::OptimizeInner()
{
    Module *mod = m_compilation_unit->GetCurrentModule();
    while (m_ast_iterator->HasNext()) {
        m_ast_iterator->Next()->Optimize(this, mod);
    }
}
<commit_msg>Delete optimizer.cpp<commit_after><|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2019 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include "DTK_BoostGeometryAdapters.hpp"

#include <DTK_DetailsAlgorithms.hpp>

#include <boost/test/unit_test.hpp>

#define BOOST_TEST_MODULE BoostGeometryAdapters

namespace bg = boost::geometry;
namespace dtk = DataTransferKit::Details;
// Conveniently importing Point and Box in DataTransferKit::Details:: namespace
// and declaring type aliases within boost::geometry:: so that we are able to
// just use dtk:: and bg:: to specify what geometry or algorithm we mean.
namespace DataTransferKit
{
namespace Details
{
using DataTransferKit::Box;
using DataTransferKit::Point;
} // namespace Details
} // namespace DataTransferKit
namespace boost
{
namespace geometry
{
using Point = model::point<double, 3, cs::cartesian>;
using Box = model::box<Point>;
} // namespace geometry
} // namespace boost

BOOST_AUTO_TEST_CASE( equals )
{
    dtk::Point point = {{1., 2., 3.}};
    BOOST_TEST( dtk::equals( point, {{1., 2., 3.}} ) );
    BOOST_TEST( !dtk::equals( point, {{0., 0., 0.}} ) );
    BOOST_TEST( bg::equals( point, bg::make<dtk::Point>( 1., 2., 3. ) ) );
    BOOST_TEST( !bg::equals( point, bg::make<dtk::Point>( 4., 5., 6. ) ) );
    BOOST_TEST( bg::equals( point, bg::make<bg::Point>( 1., 2., 3. ) ) );
    BOOST_TEST( !bg::equals( point, bg::make<bg::Point>( 0., 0., 0. ) ) );

    dtk::Box box = {{{1., 2., 3.}}, {{4., 5., 6.}}};
    BOOST_TEST( dtk::equals( box, {{{1., 2., 3.}}, {{4., 5., 6.}}} ) );
    BOOST_TEST( !dtk::equals( box, {{{0., 0., 0.}}, {{1., 1., 1.}}} ) );
    BOOST_TEST( bg::equals( box, dtk::Box{{{1., 2., 3.}}, {{4., 5., 6.}}} ) );
    BOOST_TEST( !bg::equals( box, dtk::Box{{{0., 0., 0.}}, {{1., 1., 1.}}} ) );
    BOOST_TEST(
        bg::equals( box, bg::Box( bg::make<bg::Point>( 1., 2., 3. ),
                                  bg::make<bg::Point>( 4., 5., 6. ) ) ) );
    BOOST_TEST(
        !bg::equals( box, bg::Box( bg::make<bg::Point>( 0., 0., 0. ),
                                   bg::make<bg::Point>( 1., 1., 1. ) ) ) );
    // Now just for fun compare the DTK box to a Boost.Geometry box composed of
    // DTK points.
    BOOST_TEST( bg::equals(
        box, bg::model::box<dtk::Point>( {{1., 2., 3.}}, {{4., 5., 6.}} ) ) );
    BOOST_TEST( !bg::equals(
        box, bg::model::box<dtk::Point>( {{0., 0., 0.}}, {{0., 0., 0.}} ) ) );
}

BOOST_AUTO_TEST_CASE( distance )
{
    // NOTE unsure if should test for floating point equality here
    dtk::Point a = {{0., 0., 0.}};
    dtk::Point b = {{0., 1., 0.}};
    BOOST_TEST( dtk::distance( a, b ) == 1. );
    BOOST_TEST( bg::distance( a, b ) == 1. );

    std::tie( a, b ) = std::make_pair<dtk::Point, dtk::Point>( {{0., 0., 0.}},
                                                               {{1., 1., 1.}} );
    BOOST_TEST( dtk::distance( a, b ) == std::sqrt( 3. ) );
    BOOST_TEST( bg::distance( a, b ) == std::sqrt( 3. ) );

    BOOST_TEST( dtk::distance( a, a ) == 0. );
    BOOST_TEST( bg::distance( a, a ) == 0. );

    dtk::Box unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};
    dtk::Point p = {{.5, .5, .5}};
    // NOTE DTK has no overload distance( Box, Point )
    BOOST_TEST( dtk::distance( p, unit_box ) == 0. );
    // BOOST_TEST( dtk::distance( unit_box, p ) == 0. );
    BOOST_TEST( bg::distance( p, unit_box ) == 0. );
    BOOST_TEST( bg::distance( unit_box, p ) == 0. );

    p = {{-1., -1., -1.}};
    BOOST_TEST( dtk::distance( p, unit_box ) == std::sqrt( 3. ) );
    BOOST_TEST( bg::distance( p, unit_box ) == std::sqrt( 3. ) );

    p = {{-1., .5, -1.}};
    BOOST_TEST( dtk::distance( p, unit_box ) == std::sqrt( 2. ) );
    BOOST_TEST( bg::distance( p, unit_box ) == std::sqrt( 2. ) );

    p = {{-1., .5, .5}};
    BOOST_TEST( dtk::distance( p, unit_box ) == 1. );
    BOOST_TEST( bg::distance( p, unit_box ) == 1. );
}

BOOST_AUTO_TEST_CASE( expand )
{
    using dtk::equals;
    dtk::Box box;
    // NOTE even though not considered valid, default constructed DTK box can be
    // expanded using Boost.Geometry algorithm.
    BOOST_TEST( !bg::is_valid( box ) );
    bg::expand( box, dtk::Point{{0., 0., 0.}} );
    dtk::expand( box, {{1., 1., 1.}} );
    BOOST_TEST( equals( box, {{{0., 0., 0.}}, {{1., 1., 1.}}} ) );
    bg::expand( box, dtk::Box{{{1., 2., 3.}}, {{4., 5., 6.}}} );
    dtk::expand( box, {{{-1., -2., -3.}}, {{0., 0., 0.}}} );
    BOOST_TEST( equals( box, {{{-1., -2., -3.}}, {{4., 5., 6.}}} ) );
}

BOOST_AUTO_TEST_CASE( centroid )
{
    using dtk::equals;
    // For convenience define a function that returns the centroid.
    // Boost.Geometry defines both `void centroid(Geometry const & geometry,
    // Point &c )` and `Point return_centroid(Geometry const& geometry)`
    auto const dtkReturnCentroid = []( dtk::Box b ) {
        dtk::Point c;
        dtk::centroid( b, c );
        return c;
    };

    // Interestingly enough, even though for Boost.Geometry, the DTK default
    // constructed "empty" box is not valid, it will still calculate its
    // centroid.  Admittedly, the result (centroid at origin) is garbage :)
    dtk::Box empty_box = {};
    BOOST_TEST( !bg::is_valid( empty_box ) );
    BOOST_TEST( equals( bg::return_centroid<dtk::Point>( empty_box ),
                        {{0., 0., 0.}} ) );
    BOOST_TEST( equals( dtkReturnCentroid( empty_box ), {{0., 0., 0.}} ) );

    dtk::Box unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};
    BOOST_TEST(
        equals( bg::return_centroid<dtk::Point>( unit_box ), {{.5, .5, .5}} ) );
    BOOST_TEST( equals( dtkReturnCentroid( unit_box ), {{.5, .5, .5}} ) );

    // NOTE DTK does not have an overload of centroid() for Point at the
    // moment.
    dtk::Point a_point = {{1., 2., 3.}};
    BOOST_TEST( equals( bg::return_centroid<dtk::Point>( a_point ), a_point ) );
    // BOOST_TEST( equals( dtk::centroid(
    //     []( dtk::Point p ) {
    //         dtk::Point c;
    //         dtk::centroid( p, c );
    //         return c;
    //     }( a_point ),
    //     a_point ) ) );
}

BOOST_AUTO_TEST_CASE( is_valid )
{
    // NOTE "empty" box is considered as valid in DataTransferKit but it is
    // not according to Boost.Geometry
    dtk::Box empty_box = {};
    BOOST_TEST( dtk::isValid( empty_box ) );
    std::string message;
    BOOST_TEST( !bg::is_valid( empty_box, message ) );
    BOOST_TEST( message == "Box has corners in wrong order" );

    // Same issue with infinitesimal box around a point (here the origin)
    dtk::Box a_box = {{{0., 0., 0.}}, {{0., 0., 0.}}};
    BOOST_TEST( dtk::isValid( a_box ) );
    BOOST_TEST( !bg::is_valid( a_box, message ) );
    BOOST_TEST( message == "Geometry has wrong topological dimension" );

    dtk::Box unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};
    BOOST_TEST( dtk::isValid( unit_box ) );
    BOOST_TEST( bg::is_valid( unit_box ) );

    dtk::Box invalid_box = {{{1., 2., 3.}}, {{4., NAN, 6.}}};
    BOOST_TEST( !dtk::isValid( invalid_box ) );
    BOOST_TEST( !bg::is_valid( invalid_box, message ) );
    BOOST_TEST( message == "Geometry has point(s) with invalid coordinate(s)" );

    dtk::Point a_point = {{1., 2., 3.}};
    BOOST_TEST( dtk::isValid( a_point ) );
    BOOST_TEST( bg::is_valid( a_point ) );

    auto const infty = std::numeric_limits<double>::infinity();
    dtk::Point invalid_point = {{infty, 1.41, 3.14}};
    BOOST_TEST( !dtk::isValid( invalid_point ) );
    BOOST_TEST( !bg::is_valid( invalid_point, message ) );
    BOOST_TEST( message == "Geometry has point(s) with invalid coordinate(s)" );

    // Also Boost.Geometry has a is_empty() algorithm but it has a different
    // meaning, it checks whether a geometry is an empty set and always returns
    // false for a point or a box.
    BOOST_TEST( !bg::is_empty( empty_box ) );
    BOOST_TEST( !bg::is_empty( a_box ) );
    BOOST_TEST( !bg::is_empty( unit_box ) );
}

BOOST_AUTO_TEST_CASE( intersects )
{
    dtk::Box const unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};

    // self-intersection
    BOOST_TEST( dtk::intersects( unit_box, unit_box ) );
    BOOST_TEST( bg::intersects( unit_box, unit_box ) );

    // share a corner
    dtk::Box other_box = {{{1., 1., 1.}}, {{2., 2., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // share an edge
    other_box = {{{1., 0., 1.}}, {{2., 1., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // share a face
    other_box = {{{0., -1., 0.}}, {{1., 0., 1.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // contains the other box
    other_box = {{{.3, .3, .3}}, {{.6, .6, .6}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // within the other box
    other_box = {{{-1., -1., -1.}}, {{2., 2., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // overlapping
    other_box = {{{.5, .5, .5}}, {{2., 2., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // disjoint
    other_box = {{{1., 2., 3.}}, {{4., 5., 6.}}};
    BOOST_TEST( !dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( !bg::intersects( unit_box, other_box ) );
}
<commit_msg>Update test that calculate centroid of geometries<commit_after>/****************************************************************************
 * Copyright (c) 2012-2019 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include "DTK_BoostGeometryAdapters.hpp"

#include <DTK_DetailsAlgorithms.hpp>

#include <boost/test/unit_test.hpp>

#define BOOST_TEST_MODULE BoostGeometryAdapters

namespace bg = boost::geometry;
namespace dtk = DataTransferKit::Details;
// Conveniently importing Point and Box in DataTransferKit::Details:: namespace
// and declaring type aliases within boost::geometry:: so that we are able to
// just use dtk:: and bg:: to specify what geometry or algorithm we mean.
namespace DataTransferKit
{
namespace Details
{
using DataTransferKit::Box;
using DataTransferKit::Point;
} // namespace Details
} // namespace DataTransferKit
namespace boost
{
namespace geometry
{
using Point = model::point<double, 3, cs::cartesian>;
using Box = model::box<Point>;
} // namespace geometry
} // namespace boost

BOOST_AUTO_TEST_CASE( equals )
{
    dtk::Point point = {{1., 2., 3.}};
    BOOST_TEST( dtk::equals( point, {{1., 2., 3.}} ) );
    BOOST_TEST( !dtk::equals( point, {{0., 0., 0.}} ) );
    BOOST_TEST( bg::equals( point, bg::make<dtk::Point>( 1., 2., 3. ) ) );
    BOOST_TEST( !bg::equals( point, bg::make<dtk::Point>( 4., 5., 6. ) ) );
    BOOST_TEST( bg::equals( point, bg::make<bg::Point>( 1., 2., 3. ) ) );
    BOOST_TEST( !bg::equals( point, bg::make<bg::Point>( 0., 0., 0. ) ) );

    dtk::Box box = {{{1., 2., 3.}}, {{4., 5., 6.}}};
    BOOST_TEST( dtk::equals( box, {{{1., 2., 3.}}, {{4., 5., 6.}}} ) );
    BOOST_TEST( !dtk::equals( box, {{{0., 0., 0.}}, {{1., 1., 1.}}} ) );
    BOOST_TEST( bg::equals( box, dtk::Box{{{1., 2., 3.}}, {{4., 5., 6.}}} ) );
    BOOST_TEST( !bg::equals( box, dtk::Box{{{0., 0., 0.}}, {{1., 1., 1.}}} ) );
    BOOST_TEST(
        bg::equals( box, bg::Box( bg::make<bg::Point>( 1., 2., 3. ),
                                  bg::make<bg::Point>( 4., 5., 6. ) ) ) );
    BOOST_TEST(
        !bg::equals( box, bg::Box( bg::make<bg::Point>( 0., 0., 0. ),
                                   bg::make<bg::Point>( 1., 1., 1. ) ) ) );
    // Now just for fun compare the DTK box to a Boost.Geometry box composed of
    // DTK points.
    BOOST_TEST( bg::equals(
        box, bg::model::box<dtk::Point>( {{1., 2., 3.}}, {{4., 5., 6.}} ) ) );
    BOOST_TEST( !bg::equals(
        box, bg::model::box<dtk::Point>( {{0., 0., 0.}}, {{0., 0., 0.}} ) ) );
}

BOOST_AUTO_TEST_CASE( distance )
{
    // NOTE unsure if should test for floating point equality here
    dtk::Point a = {{0., 0., 0.}};
    dtk::Point b = {{0., 1., 0.}};
    BOOST_TEST( dtk::distance( a, b ) == 1. );
    BOOST_TEST( bg::distance( a, b ) == 1. );

    std::tie( a, b ) = std::make_pair<dtk::Point, dtk::Point>( {{0., 0., 0.}},
                                                               {{1., 1., 1.}} );
    BOOST_TEST( dtk::distance( a, b ) == std::sqrt( 3. ) );
    BOOST_TEST( bg::distance( a, b ) == std::sqrt( 3. ) );

    BOOST_TEST( dtk::distance( a, a ) == 0. );
    BOOST_TEST( bg::distance( a, a ) == 0. );

    dtk::Box unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};
    dtk::Point p = {{.5, .5, .5}};
    // NOTE DTK has no overload distance( Box, Point )
    BOOST_TEST( dtk::distance( p, unit_box ) == 0. );
    // BOOST_TEST( dtk::distance( unit_box, p ) == 0. );
    BOOST_TEST( bg::distance( p, unit_box ) == 0. );
    BOOST_TEST( bg::distance( unit_box, p ) == 0. );

    p = {{-1., -1., -1.}};
    BOOST_TEST( dtk::distance( p, unit_box ) == std::sqrt( 3. ) );
    BOOST_TEST( bg::distance( p, unit_box ) == std::sqrt( 3. ) );

    p = {{-1., .5, -1.}};
    BOOST_TEST( dtk::distance( p, unit_box ) == std::sqrt( 2. ) );
    BOOST_TEST( bg::distance( p, unit_box ) == std::sqrt( 2. ) );

    p = {{-1., .5, .5}};
    BOOST_TEST( dtk::distance( p, unit_box ) == 1. );
    BOOST_TEST( bg::distance( p, unit_box ) == 1. );
}

BOOST_AUTO_TEST_CASE( expand )
{
    using dtk::equals;
    dtk::Box box;
    // NOTE even though not considered valid, default constructed DTK box can be
    // expanded using Boost.Geometry algorithm.
    BOOST_TEST( !bg::is_valid( box ) );
    bg::expand( box, dtk::Point{{0., 0., 0.}} );
    dtk::expand( box, {{1., 1., 1.}} );
    BOOST_TEST( equals( box, {{{0., 0., 0.}}, {{1., 1., 1.}}} ) );
    bg::expand( box, dtk::Box{{{1., 2., 3.}}, {{4., 5., 6.}}} );
    dtk::expand( box, {{{-1., -2., -3.}}, {{0., 0., 0.}}} );
    BOOST_TEST( equals( box, {{{-1., -2., -3.}}, {{4., 5., 6.}}} ) );
}

BOOST_AUTO_TEST_CASE( centroid )
{
    using dtk::equals;

    // Interestingly enough, even though for Boost.Geometry, the DTK default
    // constructed "empty" box is not valid, it will still calculate its
    // centroid.  Admittedly, the result (centroid at origin) is garbage :)
    dtk::Box empty_box = {};
    BOOST_TEST( !bg::is_valid( empty_box ) );
    BOOST_TEST( equals( bg::return_centroid<dtk::Point>( empty_box ),
                        {{0., 0., 0.}} ) );
    BOOST_TEST( equals( dtk::returnCentroid( empty_box ), {{0., 0., 0.}} ) );

    dtk::Box unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};
    BOOST_TEST(
        equals( bg::return_centroid<dtk::Point>( unit_box ), {{.5, .5, .5}} ) );
    BOOST_TEST( equals( dtk::returnCentroid( unit_box ), {{.5, .5, .5}} ) );

    dtk::Point a_point = {{1., 2., 3.}};
    BOOST_TEST( equals( bg::return_centroid<dtk::Point>( a_point ), a_point ) );
    BOOST_TEST( equals( dtk::returnCentroid( a_point ), a_point ) );
}

BOOST_AUTO_TEST_CASE( is_valid )
{
    // NOTE "empty" box is considered as valid in DataTransferKit but it is
    // not according to Boost.Geometry
    dtk::Box empty_box = {};
    BOOST_TEST( dtk::isValid( empty_box ) );
    std::string message;
    BOOST_TEST( !bg::is_valid( empty_box, message ) );
    BOOST_TEST( message == "Box has corners in wrong order" );

    // Same issue with infinitesimal box around a point (here the origin)
    dtk::Box a_box = {{{0., 0., 0.}}, {{0., 0., 0.}}};
    BOOST_TEST( dtk::isValid( a_box ) );
    BOOST_TEST( !bg::is_valid( a_box, message ) );
    BOOST_TEST( message == "Geometry has wrong topological dimension" );

    dtk::Box unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};
    BOOST_TEST( dtk::isValid( unit_box ) );
    BOOST_TEST( bg::is_valid( unit_box ) );

    dtk::Box invalid_box = {{{1., 2., 3.}}, {{4., NAN, 6.}}};
    BOOST_TEST( !dtk::isValid( invalid_box ) );
    BOOST_TEST( !bg::is_valid( invalid_box, message ) );
    BOOST_TEST( message == "Geometry has point(s) with invalid coordinate(s)" );

    dtk::Point a_point = {{1., 2., 3.}};
    BOOST_TEST( dtk::isValid( a_point ) );
    BOOST_TEST( bg::is_valid( a_point ) );

    auto const infty = std::numeric_limits<double>::infinity();
    dtk::Point invalid_point = {{infty, 1.41, 3.14}};
    BOOST_TEST( !dtk::isValid( invalid_point ) );
    BOOST_TEST( !bg::is_valid( invalid_point, message ) );
    BOOST_TEST( message == "Geometry has point(s) with invalid coordinate(s)" );

    // Also Boost.Geometry has a is_empty() algorithm but it has a different
    // meaning, it checks whether a geometry is an empty set and always returns
    // false for a point or a box.
    BOOST_TEST( !bg::is_empty( empty_box ) );
    BOOST_TEST( !bg::is_empty( a_box ) );
    BOOST_TEST( !bg::is_empty( unit_box ) );
}

BOOST_AUTO_TEST_CASE( intersects )
{
    dtk::Box const unit_box = {{{0., 0., 0.}}, {{1., 1., 1.}}};

    // self-intersection
    BOOST_TEST( dtk::intersects( unit_box, unit_box ) );
    BOOST_TEST( bg::intersects( unit_box, unit_box ) );

    // share a corner
    dtk::Box other_box = {{{1., 1., 1.}}, {{2., 2., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // share an edge
    other_box = {{{1., 0., 1.}}, {{2., 1., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // share a face
    other_box = {{{0., -1., 0.}}, {{1., 0., 1.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // contains the other box
    other_box = {{{.3, .3, .3}}, {{.6, .6, .6}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // within the other box
    other_box = {{{-1., -1., -1.}}, {{2., 2., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // overlapping
    other_box = {{{.5, .5, .5}}, {{2., 2., 2.}}};
    BOOST_TEST( dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( bg::intersects( unit_box, other_box ) );

    // disjoint
    other_box = {{{1., 2., 3.}}, {{4., 5., 6.}}};
    BOOST_TEST( !dtk::intersects( unit_box, other_box ) );
    BOOST_TEST( !bg::intersects( unit_box, other_box ) );
}
<|endoftext|>