diff --git a/CMakeLists.txt b/CMakeLists.txt index e226e64..7b1044e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,18 +37,6 @@ CPMAddPackage( ) execute_process(COMMAND ln -sf ${Arbutils_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/include/Arbutils) - -CPMAddPackage( - NAME CreatureLib - GIT_REPOSITORY https://git.p-epsilon.com/Deukhoofd/CreatureLib.git - GIT_TAG master - OPTIONS - "SHARED=${SHARED}" - "WINDOWS=${WINDOWS}" - "STATICC=${STATICC}" -) -execute_process(COMMAND ln -sf ${CreatureLib_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/include/CreatureLib) - CPMAddPackage( NAME CreatureLib GIT_REPOSITORY https://git.p-epsilon.com/Deukhoofd/CreatureLib.git @@ -80,6 +68,7 @@ if (SCRIPT_PROVIDER STREQUAL "angelscript") include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) include_directories(${Angelscript_SOURCE_DIR}/angelscript/include) + include_directories(${Angelscript_SOURCE_DIR}/add_on) link_directories(${Angelscript_BINARY_DIR}) endif() @@ -144,13 +133,24 @@ if (SCRIPT_PROVIDER STREQUAL "angelscript") SET(FILE_SOURCE ${FILE_SOURCE} "src/ScriptResolving/AngelScript/*.cpp" "src/ScriptResolving/AngelScript/*.hpp" - "extern/angelscript_addons/*.cpp" - "extern/angelscript_addons/*.h" + "${Angelscript_SOURCE_DIR}/add_on/scriptbuilder/scriptbuilder.cpp" + "${Angelscript_SOURCE_DIR}/add_on/scripthelper/scripthelper.cpp" + "${Angelscript_SOURCE_DIR}/add_on/scripthandle/scripthandle.cpp" + "${Angelscript_SOURCE_DIR}/add_on/scriptstdstring/scriptstdstring.cpp" + "${Angelscript_SOURCE_DIR}/add_on/scriptdictionary/scriptdictionary.cpp" + "${Angelscript_SOURCE_DIR}/add_on/scriptarray/scriptarray.cpp" "CInterface/AngelScript/*.cpp" "CInterface/AngelScript/*.hpp" ) if (ANGELSCRIPT_DEBUGGER) - SET(FILE_SOURCE ${FILE_SOURCE} "extern/AngelscriptDebuggerServer/src/*.cpp") + CPMAddPackage( + NAME AngelscriptDebugger + GIT_REPOSITORY https://git.p-epsilon.com/Deukhoofd/AngelscriptDebuggerServer.git + GIT_TAG master + ) + execute_process(COMMAND ln -sf ${AngelscriptDebugger_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/include/AngelscriptDebuggerServer) + set(_LINKS ${_LINKS} AngelscriptDebugger) + set(_TESTLINKS ${_TESTLINKS} AngelscriptDebugger) endif() ADD_DEFINITIONS(-D AS_USE_ACCESSORS=1) endif () @@ -168,8 +168,8 @@ if (IPO_SUPPORTED) set_property(TARGET pkmnLib PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) endif () -SET(_LINKS CreatureLib Arbutils) -SET(_TESTLINKS pkmnLib CreatureLib Arbutils) +SET(_LINKS ${_LINKS} CreatureLib Arbutils) +SET(_TESTLINKS ${_TESTLINKS} pkmnLib CreatureLib Arbutils) if (SCRIPT_PROVIDER STREQUAL "angelscript") message(STATUS "Using Angelscript as script provider.") @@ -210,14 +210,23 @@ endif () target_link_libraries(pkmnLib PRIVATE ${_LINKS}) if (PKMNLIB_TESTS) + CPMAddPackage( + NAME doctest + GITHUB_REPOSITORY doctest/doctest + GIT_TAG 2.4.0 + DOWNLOAD_ONLY YES + ) + # Create Test executable file(GLOB_RECURSE TEST_FILES "tests/*.cpp" "tests/*.hpp") - add_executable(pkmnLibTests ${TEST_FILES} extern/doctest.hpp) + add_executable(pkmnLibTests ${TEST_FILES}) # Enable all warnings, and make them error when occurring. target_compile_options(pkmnLibTests PRIVATE -Wall -Wextra -Werror) message(STATUS "${_TESTLINKS}") target_link_libraries(pkmnLibTests PUBLIC ${_TESTLINKS}) + target_include_directories(pkmnLibTests PUBLIC ${doctest_SOURCE_DIR}/doctest) + # Add a definition for the test library target_compile_definitions(pkmnLibTests PRIVATE TESTS_BUILD) diff --git a/extern/AngelscriptDebuggerServer b/extern/AngelscriptDebuggerServer deleted file mode 160000 index 2fe2286..0000000 --- a/extern/AngelscriptDebuggerServer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2fe2286df8f790ef75702a517c1751972da364c5 diff --git a/extern/angelscript_addons/scriptarray/scriptarray.cpp b/extern/angelscript_addons/scriptarray/scriptarray.cpp deleted file mode 100644 index 58512f3..0000000 --- a/extern/angelscript_addons/scriptarray/scriptarray.cpp +++ /dev/null @@ -1,2186 +0,0 @@ -#include -#include -#include -#include -#include // sprintf -#include -#include // std::sort - -#include "scriptarray.h" - -using namespace std; - -BEGIN_AS_NAMESPACE - -// This macro is used to avoid warnings about unused variables. -// Usually where the variables are only used in debug mode. -#define UNUSED_VAR(x) (void)(x) - -// Set the default memory routines -// Use the angelscript engine's memory routines by default -static asALLOCFUNC_t userAlloc = asAllocMem; -static asFREEFUNC_t userFree = asFreeMem; - -// Allows the application to set which memory routines should be used by the array object -void CScriptArray::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) -{ - userAlloc = allocFunc; - userFree = freeFunc; -} - -static void RegisterScriptArray_Native(asIScriptEngine *engine); -static void RegisterScriptArray_Generic(asIScriptEngine *engine); - -struct SArrayBuffer -{ - asDWORD maxElements; - asDWORD numElements; - asBYTE data[1]; -}; - -struct SArrayCache -{ - asIScriptFunction *cmpFunc; - asIScriptFunction *eqFunc; - int cmpFuncReturnCode; // To allow better error message in case of multiple matches - int eqFuncReturnCode; -}; - -// We just define a number here that we assume nobody else is using for -// object type user data. The add-ons have reserved the numbers 1000 -// through 1999 for this purpose, so we should be fine. -const asPWORD ARRAY_CACHE = 1000; - -static void CleanupTypeInfoArrayCache(asITypeInfo *type) -{ - SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); - if( cache ) - { - cache->~SArrayCache(); - userFree(cache); - } -} - -CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length) -{ - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptArray)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - - return 0; - } - - // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, ti); - - return a; -} - -CScriptArray* CScriptArray::Create(asITypeInfo *ti, void *initList) -{ - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptArray)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - - return 0; - } - - // Initialize the object - CScriptArray *a = new(mem) CScriptArray(ti, initList); - - return a; -} - -CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length, void *defVal) -{ - // Allocate the memory - void *mem = userAlloc(sizeof(CScriptArray)); - if( mem == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - - return 0; - } - - // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); - - return a; -} - -CScriptArray* CScriptArray::Create(asITypeInfo *ti) -{ - return CScriptArray::Create(ti, asUINT(0)); -} - -// This optional callback is called when the template type is first used by the compiler. -// It allows the application to validate if the template can be instantiated for the requested -// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect -// allow the callback to tell the engine if the template instance type shouldn't be garbage collected, -// i.e. no asOBJ_GC flag. -static bool ScriptArrayTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) -{ - // Make sure the subtype can be instantiated with a default factory/constructor, - // otherwise we won't be able to instantiate the elements. - int typeId = ti->GetSubTypeId(); - if( typeId == asTYPEID_VOID ) - return false; - if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) - { - asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); - asDWORD flags = subtype->GetFlags(); - if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) - { - // Verify that there is a default constructor - bool found = false; - for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ ) - { - asEBehaviours beh; - asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh); - if( beh != asBEHAVE_CONSTRUCT ) continue; - - if( func->GetParamCount() == 0 ) - { - // Found the default constructor - found = true; - break; - } - } - - if( !found ) - { - // There is no default constructor - // TODO: Should format the message to give the name of the subtype for better understanding - ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); - return false; - } - } - else if( (flags & asOBJ_REF) ) - { - bool found = false; - - // If value assignment for ref type has been disabled then the array - // can be created if the type has a default factory function - if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) - { - // Verify that there is a default factory - for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) - { - asIScriptFunction *func = subtype->GetFactoryByIndex(n); - if( func->GetParamCount() == 0 ) - { - // Found the default factory - found = true; - break; - } - } - } - - if( !found ) - { - // No default factory - // TODO: Should format the message to give the name of the subtype for better understanding - ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); - return false; - } - } - - // If the object type is not garbage collected then the array also doesn't need to be - if( !(flags & asOBJ_GC) ) - dontGarbageCollect = true; - } - else if( !(typeId & asTYPEID_OBJHANDLE) ) - { - // Arrays with primitives cannot form circular references, - // thus there is no need to garbage collect them - dontGarbageCollect = true; - } - else - { - assert( typeId & asTYPEID_OBJHANDLE ); - - // It is not necessary to set the array as garbage collected for all handle types. - // If it is possible to determine that the handle cannot refer to an object type - // that can potentially form a circular reference with the array then it is not - // necessary to make the array garbage collected. - asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); - asDWORD flags = subtype->GetFlags(); - if( !(flags & asOBJ_GC) ) - { - if( (flags & asOBJ_SCRIPT_OBJECT) ) - { - // Even if a script class is by itself not garbage collected, it is possible - // that classes that derive from it may be, so it is not possible to know - // that no circular reference can occur. - if( (flags & asOBJ_NOINHERIT) ) - { - // A script class declared as final cannot be inherited from, thus - // we can be certain that the object cannot be garbage collected. - dontGarbageCollect = true; - } - } - else - { - // For application registered classes we assume the application knows - // what it is doing and don't mark the array as garbage collected unless - // the type is also garbage collected. - dontGarbageCollect = true; - } - } - } - - // The type is ok - return true; -} - -// Registers the template array type -void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray) -{ - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0 ) - RegisterScriptArray_Native(engine); - else - RegisterScriptArray_Generic(engine); - - if( defaultArray ) - { - int r = engine->RegisterDefaultArrayType("array"); assert( r >= 0 ); - UNUSED_VAR(r); - } -} - -static void RegisterScriptArray_Native(asIScriptEngine *engine) -{ - int r = 0; - UNUSED_VAR(r); - - // Register the object type user data clean up - engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); - - // Register the array type as a template - r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); - - // Register a callback for validating the subtype before it is used - r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 ); - - // Templates receive the object type as the first parameter. To the script writer this is hidden - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - - // Register the factory that will be used for initialization lists - r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - - // The memory management methods - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL); assert( r >= 0 ); - - // The index operator returns the template subtype - r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); - - // The assignment operator - r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 ); - - // Other methods - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asMETHOD(CScriptArray, RemoveRange), asCALL_THISCALL); assert(r >= 0); - // TODO: Should length() and resize() be deprecated as the property accessors do the same thing? - // TODO: Register as size() for consistency with other types -#if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint length)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL); assert( r >= 0 ); - // The token 'if_handle_then_const' tells the engine that if the type T is a handle, then it should refer to a read-only object - r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - // TODO: It should be "int find(const T&in value, uint startAt = 0) const" - r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - // TODO: It should be "int findByRef(const T&in value, uint startAt = 0) const" - r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - - // Sort with callback for comparison - r = engine->RegisterFuncdef("bool array::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)"); - r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asMETHODPR(CScriptArray, Sort, (asIScriptFunction*, asUINT, asUINT), void), asCALL_THISCALL); assert(r >= 0); - -#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - // Register virtual properties - r = engine->RegisterObjectMethod("array", "uint get_length() const property", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); -#endif - - // Register GC behaviours in case the array needs to be garbage collected - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptArray, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptArray, SetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptArray, GetFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptArray, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptArray, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); - -#if AS_USE_STLNAMES == 1 - // Same as length - r = engine->RegisterObjectMethod("array", "uint size() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); - // Same as isEmpty - r = engine->RegisterObjectMethod("array", "bool empty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - // Same as insertLast - r = engine->RegisterObjectMethod("array", "void push_back(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); - // Same as removeLast - r = engine->RegisterObjectMethod("array", "void pop_back()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); - // Same as insertAt - r = engine->RegisterObjectMethod("array", "void insert(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void insert(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); - // Same as removeAt - r = engine->RegisterObjectMethod("array", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); -#endif -} - -CScriptArray &CScriptArray::operator=(const CScriptArray &other) -{ - // Only perform the copy if the array types are the same - if( &other != this && - other.GetArrayObjectType() == GetArrayObjectType() ) - { - // Make sure the arrays are of the same size - Resize(other.buffer->numElements); - - // Copy the value of each element - CopyBuffer(buffer, other.buffer); - } - - return *this; -} - -CScriptArray::CScriptArray(asITypeInfo *ti, void *buf) -{ - // The object type should be the template instance of the array - assert( ti && string(ti->GetName()) == "array" ); - - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - - Precache(); - - asIScriptEngine *engine = ti->GetEngine(); - - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = engine->GetSizeOfPrimitiveType(subTypeId); - - // Determine the initial size from the buffer - asUINT length = *(asUINT*)buf; - - // Make sure the array size isn't too large for us to handle - if( !CheckMaxSize(length) ) - { - // Don't continue with the initialization - return; - } - - // Copy the values of the array elements from the buffer - if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) - { - CreateBuffer(&buffer, length); - - // Copy the values of the primitive type into the internal buffer - if( length > 0 ) - memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); - } - else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) - { - CreateBuffer(&buffer, length); - - // Copy the handles into the internal buffer - if( length > 0 ) - memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); - - // With object handles it is safe to clear the memory in the received buffer - // instead of increasing the ref count. It will save time both by avoiding the - // call the increase ref, and also relieve the engine from having to release - // its references too - memset((((asUINT*)buf)+1), 0, length * elementSize); - } - else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) - { - // Only allocate the buffer, but not the objects - subTypeId |= asTYPEID_OBJHANDLE; - CreateBuffer(&buffer, length); - subTypeId &= ~asTYPEID_OBJHANDLE; - - // Copy the handles into the internal buffer - if( length > 0 ) - memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize); - - // For ref types we can do the same as for handles, as they are - // implicitly stored as handles. - memset((((asUINT*)buf)+1), 0, length * elementSize); - } - else - { - // TODO: Optimize by calling the copy constructor of the object instead of - // constructing with the default constructor and then assigning the value - // TODO: With C++11 ideally we should be calling the move constructor, instead - // of the copy constructor as the engine will just discard the objects in the - // buffer afterwards. - CreateBuffer(&buffer, length); - - // For value types we need to call the opAssign for each individual object - for( asUINT n = 0; n < length; n++ ) - { - void *obj = At(n); - asBYTE *srcObj = (asBYTE*)buf; - srcObj += 4 + n*ti->GetSubType()->GetSize(); - engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); - } - } - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); -} - -CScriptArray::CScriptArray(asUINT length, asITypeInfo *ti) -{ - // The object type should be the template instance of the array - assert( ti && string(ti->GetName()) == "array" ); - - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - - Precache(); - - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); - - // Make sure the array size isn't too large for us to handle - if( !CheckMaxSize(length) ) - { - // Don't continue with the initialization - return; - } - - CreateBuffer(&buffer, length); - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); -} - -CScriptArray::CScriptArray(const CScriptArray &other) -{ - refCount = 1; - gcFlag = false; - objType = other.objType; - objType->AddRef(); - buffer = 0; - - Precache(); - - elementSize = other.elementSize; - - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); - - CreateBuffer(&buffer, 0); - - // Copy the content - *this = other; -} - -CScriptArray::CScriptArray(asUINT length, void *defVal, asITypeInfo *ti) -{ - // The object type should be the template instance of the array - assert( ti && string(ti->GetName()) == "array" ); - - refCount = 1; - gcFlag = false; - objType = ti; - objType->AddRef(); - buffer = 0; - - Precache(); - - // Determine element size - if( subTypeId & asTYPEID_MASK_OBJECT ) - elementSize = sizeof(asPWORD); - else - elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); - - // Make sure the array size isn't too large for us to handle - if( !CheckMaxSize(length) ) - { - // Don't continue with the initialization - return; - } - - CreateBuffer(&buffer, length); - - // Notify the GC of the successful creation - if( objType->GetFlags() & asOBJ_GC ) - objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); - - // Initialize the elements with the default value - for( asUINT n = 0; n < GetSize(); n++ ) - SetValue(n, defVal); -} - -void CScriptArray::SetValue(asUINT index, void *value) -{ - // At() will take care of the out-of-bounds checking, though - // if called from the application then nothing will be done - void *ptr = At(index); - if( ptr == 0 ) return; - - if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) ) - objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType()); - else if( subTypeId & asTYPEID_OBJHANDLE ) - { - void *tmp = *(void**)ptr; - *(void**)ptr = *(void**)value; - objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType()); - if( tmp ) - objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType()); - } - else if( subTypeId == asTYPEID_BOOL || - subTypeId == asTYPEID_INT8 || - subTypeId == asTYPEID_UINT8 ) - *(char*)ptr = *(char*)value; - else if( subTypeId == asTYPEID_INT16 || - subTypeId == asTYPEID_UINT16 ) - *(short*)ptr = *(short*)value; - else if( subTypeId == asTYPEID_INT32 || - subTypeId == asTYPEID_UINT32 || - subTypeId == asTYPEID_FLOAT || - subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles - *(int*)ptr = *(int*)value; - else if( subTypeId == asTYPEID_INT64 || - subTypeId == asTYPEID_UINT64 || - subTypeId == asTYPEID_DOUBLE ) - *(double*)ptr = *(double*)value; -} - -CScriptArray::~CScriptArray() -{ - if( buffer ) - { - DeleteBuffer(buffer); - buffer = 0; - } - if( objType ) objType->Release(); -} - -asUINT CScriptArray::GetSize() const -{ - return buffer->numElements; -} - -bool CScriptArray::IsEmpty() const -{ - return buffer->numElements == 0; -} - -void CScriptArray::Reserve(asUINT maxElements) -{ - if( maxElements <= buffer->maxElements ) - return; - - if( !CheckMaxSize(maxElements) ) - return; - - // Allocate memory for the buffer - SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*maxElements)); - if( newBuffer ) - { - newBuffer->numElements = buffer->numElements; - newBuffer->maxElements = maxElements; - } - else - { - // Out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - return; - } - - // As objects in arrays of objects are not stored inline, it is safe to use memcpy here - // since we're just copying the pointers to objects and not the actual objects. - memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize); - - // Release the old buffer - userFree(buffer); - - buffer = newBuffer; -} - -void CScriptArray::Resize(asUINT numElements) -{ - if( !CheckMaxSize(numElements) ) - return; - - Resize((int)numElements - (int)buffer->numElements, (asUINT)-1); -} - -void CScriptArray::RemoveRange(asUINT start, asUINT count) -{ - if (count == 0) - return; - - if( buffer == 0 || start > buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Index out of bounds"); - return; - } - - // Cap count to the end of the array - if (start + count > buffer->numElements) - count = buffer->numElements - start; - - // Destroy the elements that are being removed - Destruct(buffer, start, start + count); - - // Compact the elements - // As objects in arrays of objects are not stored inline, it is safe to use memmove here - // since we're just copying the pointers to objects and not the actual objects. - memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - start - count)*elementSize); - buffer->numElements -= count; -} - -// Internal -void CScriptArray::Resize(int delta, asUINT at) -{ - if( delta < 0 ) - { - if( -delta > (int)buffer->numElements ) - delta = -(int)buffer->numElements; - if( at > buffer->numElements + delta ) - at = buffer->numElements + delta; - } - else if( delta > 0 ) - { - // Make sure the array size isn't too large for us to handle - if( delta > 0 && !CheckMaxSize(buffer->numElements + delta) ) - return; - - if( at > buffer->numElements ) - at = buffer->numElements; - } - - if( delta == 0 ) return; - - if( buffer->maxElements < buffer->numElements + delta ) - { - // Allocate memory for the buffer - SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta))); - if( newBuffer ) - { - newBuffer->numElements = buffer->numElements + delta; - newBuffer->maxElements = newBuffer->numElements; - } - else - { - // Out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - return; - } - - // As objects in arrays of objects are not stored inline, it is safe to use memcpy here - // since we're just copying the pointers to objects and not the actual objects. - memcpy(newBuffer->data, buffer->data, at*elementSize); - if( at < buffer->numElements ) - memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize); - - // Initialize the new elements with default values - Construct(newBuffer, at, at+delta); - - // Release the old buffer - userFree(buffer); - - buffer = newBuffer; - } - else if( delta < 0 ) - { - Destruct(buffer, at, at-delta); - // As objects in arrays of objects are not stored inline, it is safe to use memmove here - // since we're just copying the pointers to objects and not the actual objects. - memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize); - buffer->numElements += delta; - } - else - { - // As objects in arrays of objects are not stored inline, it is safe to use memmove here - // since we're just copying the pointers to objects and not the actual objects. - memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize); - Construct(buffer, at, at+delta); - buffer->numElements += delta; - } -} - -// internal -bool CScriptArray::CheckMaxSize(asUINT numElements) -{ - // This code makes sure the size of the buffer that is allocated - // for the array doesn't overflow and becomes smaller than requested - - asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1; - if( elementSize > 0 ) - maxSize /= elementSize; - - if( numElements > maxSize ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Too large array size"); - - return false; - } - - // OK - return true; -} - -asITypeInfo *CScriptArray::GetArrayObjectType() const -{ - return objType; -} - -int CScriptArray::GetArrayTypeId() const -{ - return objType->GetTypeId(); -} - -int CScriptArray::GetElementTypeId() const -{ - return subTypeId; -} - -void CScriptArray::InsertAt(asUINT index, void *value) -{ - if( index > buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return; - } - - // Make room for the new element - Resize(1, index); - - // Set the value of the new element - SetValue(index, value); -} - -void CScriptArray::InsertAt(asUINT index, const CScriptArray &arr) -{ - if (index > buffer->numElements) - { - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Index out of bounds"); - return; - } - - if (objType != arr.objType) - { - // This shouldn't really be possible to happen when - // called from a script, but let's check for it anyway - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException("Mismatching array types"); - return; - } - - asUINT elements = arr.GetSize(); - Resize(elements, index); - if (&arr != this) - { - for (asUINT n = 0; n < arr.GetSize(); n++) - { - // This const cast is allowed, since we know the - // value will only be used to make a copy of it - void *value = const_cast(arr.At(n)); - SetValue(index + n, value); - } - } - else - { - // The array that is being inserted is the same as this one. - // So we should iterate over the elements before the index, - // and then the elements after - for (asUINT n = 0; n < index; n++) - { - // This const cast is allowed, since we know the - // value will only be used to make a copy of it - void *value = const_cast(arr.At(n)); - SetValue(index + n, value); - } - - for (asUINT n = index + elements, m = 0; n < arr.GetSize(); n++, m++) - { - // This const cast is allowed, since we know the - // value will only be used to make a copy of it - void *value = const_cast(arr.At(n)); - SetValue(index + index + m, value); - } - } -} - -void CScriptArray::InsertLast(void *value) -{ - InsertAt(buffer->numElements, value); -} - -void CScriptArray::RemoveAt(asUINT index) -{ - if( index >= buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return; - } - - // Remove the element - Resize(-1, index); -} - -void CScriptArray::RemoveLast() -{ - RemoveAt(buffer->numElements-1); -} - -// Return a pointer to the array element. Returns 0 if the index is out of bounds -const void *CScriptArray::At(asUINT index) const -{ - if( buffer == 0 || index >= buffer->numElements ) - { - // If this is called from a script we raise a script exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Index out of bounds"); - return 0; - } - - if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - return *(void**)(buffer->data + elementSize*index); - else - return buffer->data + elementSize*index; -} -void *CScriptArray::At(asUINT index) -{ - return const_cast(const_cast(this)->At(index)); -} - -void *CScriptArray::GetBuffer() -{ - return buffer->data; -} - - -// internal -void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements) -{ - *buf = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1+elementSize*numElements)); - - if( *buf ) - { - (*buf)->numElements = numElements; - (*buf)->maxElements = numElements; - Construct(*buf, 0, numElements); - } - else - { - // Oops, out of memory - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - } -} - -// internal -void CScriptArray::DeleteBuffer(SArrayBuffer *buf) -{ - Destruct(buf, 0, buf->numElements); - - // Free the buffer - userFree(buf); -} - -// internal -void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end) -{ - if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - { - // Create an object using the default constructor/factory for each element - void **max = (void**)(buf->data + end * sizeof(void*)); - void **d = (void**)(buf->data + start * sizeof(void*)); - - asIScriptEngine *engine = objType->GetEngine(); - asITypeInfo *subType = objType->GetSubType(); - - for( ; d < max; d++ ) - { - *d = (void*)engine->CreateScriptObject(subType); - if( *d == 0 ) - { - // Set the remaining entries to null so the destructor - // won't attempt to destroy invalid objects later - memset(d, 0, sizeof(void*)*(max-d)); - - // There is no need to set an exception on the context, - // as CreateScriptObject has already done that - return; - } - } - } - else - { - // Set all elements to zero whether they are handles or primitives - void *d = (void*)(buf->data + start * elementSize); - memset(d, 0, (end-start)*elementSize); - } -} - -// internal -void CScriptArray::Destruct(SArrayBuffer *buf, asUINT start, asUINT end) -{ - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - asIScriptEngine *engine = objType->GetEngine(); - - void **max = (void**)(buf->data + end * sizeof(void*)); - void **d = (void**)(buf->data + start * sizeof(void*)); - - for( ; d < max; d++ ) - { - if( *d ) - engine->ReleaseScriptObject(*d, objType->GetSubType()); - } - } -} - - -// internal -bool CScriptArray::Less(const void *a, const void *b, bool asc) -{ - if( !asc ) - { - // Swap items - const void *TEMP = a; - a = b; - b = TEMP; - } - - if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) - { - // Simple compare of values - switch( subTypeId ) - { - #define COMPARE(T) *((T*)a) < *((T*)b) - case asTYPEID_BOOL: return COMPARE(bool); - case asTYPEID_INT8: return COMPARE(signed char); - case asTYPEID_UINT8: return COMPARE(unsigned char); - case asTYPEID_INT16: return COMPARE(signed short); - case asTYPEID_UINT16: return COMPARE(unsigned short); - case asTYPEID_INT32: return COMPARE(signed int); - case asTYPEID_UINT32: return COMPARE(unsigned int); - case asTYPEID_FLOAT: return COMPARE(float); - case asTYPEID_DOUBLE: return COMPARE(double); - default: return COMPARE(signed int); // All enums fall in this case - #undef COMPARE - } - } - - return false; -} - -void CScriptArray::Reverse() -{ - asUINT size = GetSize(); - - if( size >= 2 ) - { - asBYTE TEMP[16]; - - for( asUINT i = 0; i < size / 2; i++ ) - { - Copy(TEMP, GetArrayItemPointer(i)); - Copy(GetArrayItemPointer(i), GetArrayItemPointer(size - i - 1)); - Copy(GetArrayItemPointer(size - i - 1), TEMP); - } - } -} - -bool CScriptArray::operator==(const CScriptArray &other) const -{ - if( objType != other.objType ) - return false; - - if( GetSize() != other.GetSize() ) - return false; - - asIScriptContext *cmpContext = 0; - bool isNested = false; - - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if( cmpContext ) - { - if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) - isNested = true; - else - cmpContext = 0; - } - if( cmpContext == 0 ) - { - // TODO: Ideally this context would be retrieved from a pool, so we don't have to - // create a new one everytime. We could keep a context with the array object - // but that would consume a lot of resources as each context is quite heavy. - cmpContext = objType->GetEngine()->CreateContext(); - } - } - - // Check if all elements are equal - bool isEqual = true; - SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - for( asUINT n = 0; n < GetSize(); n++ ) - if( !Equals(At(n), other.At(n), cmpContext, cache) ) - { - isEqual = false; - break; - } - - if( cmpContext ) - { - if( isNested ) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if( state == asEXECUTION_ABORTED ) - cmpContext->Abort(); - } - else - cmpContext->Release(); - } - - return isEqual; -} - -// internal -bool CScriptArray::Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const -{ - if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) - { - // Simple compare of values - switch( subTypeId ) - { - #define COMPARE(T) *((T*)a) == *((T*)b) - case asTYPEID_BOOL: return COMPARE(bool); - case asTYPEID_INT8: return COMPARE(signed char); - case asTYPEID_UINT8: return COMPARE(unsigned char); - case asTYPEID_INT16: return COMPARE(signed short); - case asTYPEID_UINT16: return COMPARE(unsigned short); - case asTYPEID_INT32: return COMPARE(signed int); - case asTYPEID_UINT32: return COMPARE(unsigned int); - case asTYPEID_FLOAT: return COMPARE(float); - case asTYPEID_DOUBLE: return COMPARE(double); - default: return COMPARE(signed int); // All enums fall here - #undef COMPARE - } - } - else - { - int r = 0; - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Allow the find to work even if the array contains null handles - if( *(void**)a == *(void**)b ) return true; - } - - // Execute object opEquals if available - if( cache && cache->eqFunc ) - { - // TODO: Add proper error handling - r = ctx->Prepare(cache->eqFunc); assert(r >= 0); - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - r = ctx->SetObject(*((void**)a)); assert(r >= 0); - r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); - } - else - { - r = ctx->SetObject((void*)a); assert(r >= 0); - r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); - } - - r = ctx->Execute(); - - if( r == asEXECUTION_FINISHED ) - return ctx->GetReturnByte() != 0; - - return false; - } - - // Execute object opCmp if available - if( cache && cache->cmpFunc ) - { - // TODO: Add proper error handling - r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); - - if( subTypeId & asTYPEID_OBJHANDLE ) - { - r = ctx->SetObject(*((void**)a)); assert(r >= 0); - r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); - } - else - { - r = ctx->SetObject((void*)a); assert(r >= 0); - r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); - } - - r = ctx->Execute(); - - if( r == asEXECUTION_FINISHED ) - return (int)ctx->GetReturnDWord() == 0; - - return false; - } - } - - return false; -} - -int CScriptArray::FindByRef(void *ref) const -{ - return FindByRef(0, ref); -} - -int CScriptArray::FindByRef(asUINT startAt, void *ref) const -{ - // Find the matching element by its reference - asUINT size = GetSize(); - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Dereference the pointer - ref = *(void**)ref; - for( asUINT i = startAt; i < size; i++ ) - { - if( *(void**)At(i) == ref ) - return i; - } - } - else - { - // Compare the reference directly - for( asUINT i = startAt; i < size; i++ ) - { - if( At(i) == ref ) - return i; - } - } - - return -1; -} - -int CScriptArray::Find(void *value) const -{ - return Find(0, value); -} - -int CScriptArray::Find(asUINT startAt, void *value) const -{ - // Check if the subtype really supports find() - // TODO: Can't this be done at compile time too by the template callback - SArrayCache *cache = 0; - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) - { - asIScriptContext *ctx = asGetActiveContext(); - asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); - - // Throw an exception - if( ctx ) - { - char tmp[512]; - - if( cache && cache->eqFuncReturnCode == asMULTIPLE_FUNCTIONS ) -#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); -#else - sprintf(tmp, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); -#endif - else -#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); -#else - sprintf(tmp, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); -#endif - ctx->SetException(tmp); - } - - return -1; - } - } - - asIScriptContext *cmpContext = 0; - bool isNested = false; - - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if( cmpContext ) - { - if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) - isNested = true; - else - cmpContext = 0; - } - if( cmpContext == 0 ) - { - // TODO: Ideally this context would be retrieved from a pool, so we don't have to - // create a new one everytime. We could keep a context with the array object - // but that would consume a lot of resources as each context is quite heavy. - cmpContext = objType->GetEngine()->CreateContext(); - } - } - - // Find the matching element - int ret = -1; - asUINT size = GetSize(); - - for( asUINT i = startAt; i < size; i++ ) - { - // value passed by reference - if( Equals(At(i), value, cmpContext, cache) ) - { - ret = (int)i; - break; - } - } - - if( cmpContext ) - { - if( isNested ) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if( state == asEXECUTION_ABORTED ) - cmpContext->Abort(); - } - else - cmpContext->Release(); - } - - return ret; -} - - - -// internal -// Copy object handle or primitive value -// Even in arrays of objects the objects are allocated on -// the heap and the array stores the pointers to the objects -void CScriptArray::Copy(void *dst, void *src) -{ - memcpy(dst, src, elementSize); -} - - -// internal -// Return pointer to array item (object handle or primitive value) -void *CScriptArray::GetArrayItemPointer(int index) -{ - return buffer->data + index * elementSize; -} - -// internal -// Return pointer to data in buffer (object or primitive) -void *CScriptArray::GetDataPointer(void *buf) -{ - if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) - { - // Real address of object - return reinterpret_cast(*(size_t*)buf); - } - else - { - // Primitive is just a raw data - return buf; - } -} - - -// Sort ascending -void CScriptArray::SortAsc() -{ - Sort(0, GetSize(), true); -} - -// Sort ascending -void CScriptArray::SortAsc(asUINT startAt, asUINT count) -{ - Sort(startAt, count, true); -} - -// Sort descending -void CScriptArray::SortDesc() -{ - Sort(0, GetSize(), false); -} - -// Sort descending -void CScriptArray::SortDesc(asUINT startAt, asUINT count) -{ - Sort(startAt, count, false); -} - - -// internal -void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) -{ - // Subtype isn't primitive and doesn't have opCmp - SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - if( !cache || cache->cmpFunc == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); - - // Throw an exception - if( ctx ) - { - char tmp[512]; - - if( cache && cache->cmpFuncReturnCode == asMULTIPLE_FUNCTIONS ) -#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' has multiple matching opCmp methods", subType->GetName()); -#else - sprintf(tmp, "Type '%s' has multiple matching opCmp methods", subType->GetName()); -#endif - else -#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) - sprintf_s(tmp, 512, "Type '%s' does not have a matching opCmp method", subType->GetName()); -#else - sprintf(tmp, "Type '%s' does not have a matching opCmp method", subType->GetName()); -#endif - - ctx->SetException(tmp); - } - - return; - } - } - - // No need to sort - if( count < 2 ) - { - return; - } - - int start = startAt; - int end = startAt + count; - - // Check if we could access invalid item while sorting - if( start >= (int)buffer->numElements || end > (int)buffer->numElements ) - { - asIScriptContext *ctx = asGetActiveContext(); - - // Throw an exception - if( ctx ) - { - ctx->SetException("Index out of bounds"); - } - - return; - } - - if( subTypeId & ~asTYPEID_MASK_SEQNBR ) - { - asIScriptContext *cmpContext = 0; - bool isNested = false; - - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if( cmpContext ) - { - if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) - isNested = true; - else - cmpContext = 0; - } - if( cmpContext == 0 ) - cmpContext = objType->GetEngine()->RequestContext(); - - // Do the sorting - struct { - bool asc; - asIScriptContext *cmpContext; - asIScriptFunction *cmpFunc; - bool operator()(void *a, void *b) const - { - if( !asc ) - { - // Swap items - void *TEMP = a; - a = b; - b = TEMP; - } - - int r = 0; - - // Allow sort to work even if the array contains null handles - if( a == 0 ) return true; - if( b == 0 ) return false; - - // Execute object opCmp - if( cmpFunc ) - { - // TODO: Add proper error handling - r = cmpContext->Prepare(cmpFunc); assert(r >= 0); - r = cmpContext->SetObject(a); assert(r >= 0); - r = cmpContext->SetArgObject(0, b); assert(r >= 0); - r = cmpContext->Execute(); - - if( r == asEXECUTION_FINISHED ) - { - return (int)cmpContext->GetReturnDWord() < 0; - } - } - - return false; - } - } customLess = {asc, cmpContext, cache ? cache->cmpFunc : 0}; - std::sort((void**)GetArrayItemPointer(start), (void**)GetArrayItemPointer(end), customLess); - - // Clean up - if( cmpContext ) - { - if( isNested ) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if( state == asEXECUTION_ABORTED ) - cmpContext->Abort(); - } - else - objType->GetEngine()->ReturnContext(cmpContext); - } - } - else - { - // TODO: Use std::sort for primitive types too - - // Insertion sort - asBYTE tmp[16]; - for( int i = start + 1; i < end; i++ ) - { - Copy(tmp, GetArrayItemPointer(i)); - - int j = i - 1; - - while( j >= start && Less(GetDataPointer(tmp), At(j), asc) ) - { - Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); - j--; - } - - Copy(GetArrayItemPointer(j + 1), tmp); - } - } -} - -// Sort with script callback for comparing elements -void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count) -{ - // No need to sort - if (count < 2) - return; - - // Check if we could access invalid item while sorting - asUINT start = startAt; - asUINT end = asQWORD(startAt) + asQWORD(count) >= (asQWORD(1)<<32) ? 0xFFFFFFFF : startAt + count; - if (end > buffer->numElements) - end = buffer->numElements; - - if (start >= buffer->numElements) - { - asIScriptContext *ctx = asGetActiveContext(); - - // Throw an exception - if (ctx) - ctx->SetException("Index out of bounds"); - - return; - } - - asIScriptContext *cmpContext = 0; - bool isNested = false; - - // Try to reuse the active context - cmpContext = asGetActiveContext(); - if (cmpContext) - { - if (cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0) - isNested = true; - else - cmpContext = 0; - } - if (cmpContext == 0) - cmpContext = objType->GetEngine()->RequestContext(); - - // Insertion sort - asBYTE tmp[16]; - for (asUINT i = start + 1; i < end; i++) - { - Copy(tmp, GetArrayItemPointer(i)); - - asUINT j = i - 1; - - while (j != 0xFFFFFFFF && j >= start ) - { - cmpContext->Prepare(func); - cmpContext->SetArgAddress(0, GetDataPointer(tmp)); - cmpContext->SetArgAddress(1, At(j)); - int r = cmpContext->Execute(); - if (r != asEXECUTION_FINISHED) - break; - if (*(bool*)(cmpContext->GetAddressOfReturnValue())) - { - Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); - j--; - } - else - break; - } - - Copy(GetArrayItemPointer(j + 1), tmp); - } - - if (cmpContext) - { - if (isNested) - { - asEContextState state = cmpContext->GetState(); - cmpContext->PopState(); - if (state == asEXECUTION_ABORTED) - cmpContext->Abort(); - } - else - objType->GetEngine()->ReturnContext(cmpContext); - } -} - -// internal -void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src) -{ - asIScriptEngine *engine = objType->GetEngine(); - if( subTypeId & asTYPEID_OBJHANDLE ) - { - // Copy the references and increase the reference counters - if( dst->numElements > 0 && src->numElements > 0 ) - { - int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; - - void **max = (void**)(dst->data + count * sizeof(void*)); - void **d = (void**)dst->data; - void **s = (void**)src->data; - - for( ; d < max; d++, s++ ) - { - void *tmp = *d; - *d = *s; - if( *d ) - engine->AddRefScriptObject(*d, objType->GetSubType()); - // Release the old ref after incrementing the new to avoid problem incase it is the same ref - if( tmp ) - engine->ReleaseScriptObject(tmp, objType->GetSubType()); - } - } - } - else - { - if( dst->numElements > 0 && src->numElements > 0 ) - { - int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - // Call the assignment operator on all of the objects - void **max = (void**)(dst->data + count * sizeof(void*)); - void **d = (void**)dst->data; - void **s = (void**)src->data; - - asITypeInfo *subType = objType->GetSubType(); - for( ; d < max; d++, s++ ) - engine->AssignScriptObject(*d, *s, subType); - } - else - { - // Primitives are copied byte for byte - memcpy(dst->data, src->data, count*elementSize); - } - } - } -} - -// internal -// Precache some info -void CScriptArray::Precache() -{ - subTypeId = objType->GetSubTypeId(); - - // Check if it is an array of objects. Only for these do we need to cache anything - // Type ids for primitives and enums only has the sequence number part - if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) - return; - - // The opCmp and opEquals methods are cached because the searching for the - // methods is quite time consuming if a lot of array objects are created. - - // First check if a cache already exists for this array type - SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( cache ) return; - - // We need to make sure the cache is created only once, even - // if multiple threads reach the same point at the same time - asAcquireExclusiveLock(); - - // Now that we got the lock, we need to check again to make sure the - // cache wasn't created while we were waiting for the lock - cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); - if( cache ) - { - asReleaseExclusiveLock(); - return; - } - - // Create the cache - cache = reinterpret_cast(userAlloc(sizeof(SArrayCache))); - if( !cache ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Out of memory"); - asReleaseExclusiveLock(); - return; - } - memset(cache, 0, sizeof(SArrayCache)); - - // If the sub type is a handle to const, then the methods must be const too - bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; - - asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); - if( subType ) - { - for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) - { - asIScriptFunction *func = subType->GetMethodByIndex(i); - - if( func->GetParamCount() == 1 && (!mustBeConst || func->IsReadOnly()) ) - { - asDWORD flags = 0; - int returnTypeId = func->GetReturnTypeId(&flags); - - // The method must not return a reference - if( flags != asTM_NONE ) - continue; - - // opCmp returns an int and opEquals returns a bool - bool isCmp = false, isEq = false; - if( returnTypeId == asTYPEID_INT32 && strcmp(func->GetName(), "opCmp") == 0 ) - isCmp = true; - if( returnTypeId == asTYPEID_BOOL && strcmp(func->GetName(), "opEquals") == 0 ) - isEq = true; - - if( !isCmp && !isEq ) - continue; - - // The parameter must either be a reference to the subtype or a handle to the subtype - int paramTypeId; - func->GetParam(0, ¶mTypeId, &flags); - - if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) ) - continue; - - if( (flags & asTM_INREF) ) - { - if( (paramTypeId & asTYPEID_OBJHANDLE) || (mustBeConst && !(flags & asTM_CONST)) ) - continue; - } - else if( paramTypeId & asTYPEID_OBJHANDLE ) - { - if( mustBeConst && !(paramTypeId & asTYPEID_HANDLETOCONST) ) - continue; - } - else - continue; - - if( isCmp ) - { - if( cache->cmpFunc || cache->cmpFuncReturnCode ) - { - cache->cmpFunc = 0; - cache->cmpFuncReturnCode = asMULTIPLE_FUNCTIONS; - } - else - cache->cmpFunc = func; - } - else if( isEq ) - { - if( cache->eqFunc || cache->eqFuncReturnCode ) - { - cache->eqFunc = 0; - cache->eqFuncReturnCode = asMULTIPLE_FUNCTIONS; - } - else - cache->eqFunc = func; - } - } - } - } - - if( cache->eqFunc == 0 && cache->eqFuncReturnCode == 0 ) - cache->eqFuncReturnCode = asNO_FUNCTION; - if( cache->cmpFunc == 0 && cache->cmpFuncReturnCode == 0 ) - cache->cmpFuncReturnCode = asNO_FUNCTION; - - // Set the user data only at the end so others that retrieve it will know it is complete - objType->SetUserData(cache, ARRAY_CACHE); - - asReleaseExclusiveLock(); -} - -// GC behaviour -void CScriptArray::EnumReferences(asIScriptEngine *engine) -{ - // TODO: If garbage collection can be done from a separate thread, then this method must be - // protected so that it doesn't get lost during the iteration if the array is modified - - // If the array is holding handles, then we need to notify the GC of them - if( subTypeId & asTYPEID_MASK_OBJECT ) - { - void **d = (void**)buffer->data; - - asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); - if ((subType->GetFlags() & asOBJ_REF)) - { - // For reference types we need to notify the GC of each instance - for (asUINT n = 0; n < buffer->numElements; n++) - { - if (d[n]) - engine->GCEnumCallback(d[n]); - } - } - else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) - { - // For value types we need to forward the enum callback - // to the object so it can decide what to do - for (asUINT n = 0; n < buffer->numElements; n++) - { - if (d[n]) - engine->ForwardGCEnumReferences(d[n], subType); - } - } - } -} - -// GC behaviour -void CScriptArray::ReleaseAllHandles(asIScriptEngine *) -{ - // Resizing to zero will release everything - Resize(0); -} - -void CScriptArray::AddRef() const -{ - // Clear the GC flag then increase the counter - gcFlag = false; - asAtomicInc(refCount); -} - -void CScriptArray::Release() const -{ - // Clearing the GC flag then descrease the counter - gcFlag = false; - if( asAtomicDec(refCount) == 0 ) - { - // When reaching 0 no more references to this instance - // exists and the object should be destroyed - this->~CScriptArray(); - userFree(const_cast(this)); - } -} - -// GC behaviour -int CScriptArray::GetRefCount() -{ - return refCount; -} - -// GC behaviour -void CScriptArray::SetFlag() -{ - gcFlag = true; -} - -// GC behaviour -bool CScriptArray::GetFlag() -{ - return gcFlag; -} - -//-------------------------------------------- -// Generic calling conventions - -static void ScriptArrayFactory_Generic(asIScriptGeneric *gen) -{ - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); -} - -static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen) -{ - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - asUINT length = gen->GetArgDWord(1); - - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); -} - -static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen) -{ - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - void *buf = gen->GetArgAddress(1); - - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); -} - -static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen) -{ - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - asUINT length = gen->GetArgDWord(1); - void *defVal = gen->GetArgAddress(2); - - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); -} - -static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen) -{ - asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); -} - -static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen) -{ - CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *self = *other; - gen->SetReturnObject(self); -} - -static void ScriptArrayEquals_Generic(asIScriptGeneric *gen) -{ - CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnByte(self->operator==(*other)); -} - -static void ScriptArrayFind_Generic(asIScriptGeneric *gen) -{ - void *value = gen->GetArgAddress(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->Find(value)); -} - -static void ScriptArrayFind2_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - void *value = gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->Find(index, value)); -} - -static void ScriptArrayFindByRef_Generic(asIScriptGeneric *gen) -{ - void *value = gen->GetArgAddress(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->FindByRef(value)); -} - -static void ScriptArrayFindByRef2_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - void *value = gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - gen->SetReturnDWord(self->FindByRef(index, value)); -} - -static void ScriptArrayAt_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - - gen->SetReturnAddress(self->At(index)); -} - -static void ScriptArrayInsertAt_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - void *value = gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->InsertAt(index, value); -} - -static void ScriptArrayInsertAtArray_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - CScriptArray *array = (CScriptArray*)gen->GetArgAddress(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->InsertAt(index, *array); -} - -static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->RemoveAt(index); -} - -static void ScriptArrayRemoveRange_Generic(asIScriptGeneric *gen) -{ - asUINT start = gen->GetArgDWord(0); - asUINT count = gen->GetArgDWord(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->RemoveRange(start, count); -} - -static void ScriptArrayInsertLast_Generic(asIScriptGeneric *gen) -{ - void *value = gen->GetArgAddress(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->InsertLast(value); -} - -static void ScriptArrayRemoveLast_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->RemoveLast(); -} - -static void ScriptArrayLength_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - - gen->SetReturnDWord(self->GetSize()); -} - -static void ScriptArrayResize_Generic(asIScriptGeneric *gen) -{ - asUINT size = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - - self->Resize(size); -} - -static void ScriptArrayReserve_Generic(asIScriptGeneric *gen) -{ - asUINT size = gen->GetArgDWord(0); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Reserve(size); -} - -static void ScriptArraySortAsc_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortAsc(); -} - -static void ScriptArrayReverse_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Reverse(); -} - -static void ScriptArrayIsEmpty_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->IsEmpty(); -} - -static void ScriptArraySortAsc2_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - asUINT count = gen->GetArgDWord(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortAsc(index, count); -} - -static void ScriptArraySortDesc_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortDesc(); -} - -static void ScriptArraySortDesc2_Generic(asIScriptGeneric *gen) -{ - asUINT index = gen->GetArgDWord(0); - asUINT count = gen->GetArgDWord(1); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SortDesc(index, count); -} - -static void ScriptArraySortCallback_Generic(asIScriptGeneric *gen) -{ - asIScriptFunction *callback = (asIScriptFunction*)gen->GetArgAddress(0); - asUINT startAt = gen->GetArgDWord(1); - asUINT count = gen->GetArgDWord(2); - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Sort(callback, startAt, count); -} - -static void ScriptArrayAddRef_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->AddRef(); -} - -static void ScriptArrayRelease_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->Release(); -} - -static void ScriptArrayGetRefCount_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetRefCount(); -} - -static void ScriptArraySetFlag_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - self->SetFlag(); -} - -static void ScriptArrayGetFlag_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetFlag(); -} - -static void ScriptArrayEnumReferences_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); -} - -static void ScriptArrayReleaseAllHandles_Generic(asIScriptGeneric *gen) -{ - CScriptArray *self = (CScriptArray*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllHandles(engine); -} - -static void RegisterScriptArray_Generic(asIScriptEngine *engine) -{ - int r = 0; - UNUSED_VAR(r); - - engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); - - r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTION(ScriptArrayFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in, int&in) {repeat T}", asFUNCTION(ScriptArrayListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptArrayAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeLast()", asFUNCTION(ScriptArrayRemoveLast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asFUNCTION(ScriptArrayRemoveRange_Generic), asCALL_GENERIC); assert(r >= 0); -#if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint length)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc()", asFUNCTION(ScriptArraySortAsc_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc()", asFUNCTION(ScriptArraySortDesc_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reverse()", asFUNCTION(ScriptArrayReverse_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); - r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); -#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - r = engine->RegisterObjectMethod("array", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); -#endif - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptArraySetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptArrayGetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptArrayEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptArrayReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); -} - -END_AS_NAMESPACE diff --git a/extern/angelscript_addons/scriptarray/scriptarray.h b/extern/angelscript_addons/scriptarray/scriptarray.h deleted file mode 100644 index 4903a97..0000000 --- a/extern/angelscript_addons/scriptarray/scriptarray.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef SCRIPTARRAY_H -#define SCRIPTARRAY_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -// Sometimes it may be desired to use the same method names as used by C++ STL. -// This may for example reduce time when converting code from script to C++ or -// back. -// -// 0 = off -// 1 = on -#ifndef AS_USE_STLNAMES -#define AS_USE_STLNAMES 0 -#endif - -// Some prefer to use property accessors to get/set the length of the array -// This option registers the accessors instead of the method length() -#ifndef AS_USE_ACCESSORS -#define AS_USE_ACCESSORS 0 -#endif - -BEGIN_AS_NAMESPACE - -struct SArrayBuffer; -struct SArrayCache; - -class CScriptArray -{ -public: - // Set the memory functions that should be used by all CScriptArrays - static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); - - // Factory functions - static CScriptArray *Create(asITypeInfo *ot); - static CScriptArray *Create(asITypeInfo *ot, asUINT length); - static CScriptArray *Create(asITypeInfo *ot, asUINT length, void *defaultValue); - static CScriptArray *Create(asITypeInfo *ot, void *listBuffer); - - // Memory management - void AddRef() const; - void Release() const; - - // Type information - asITypeInfo *GetArrayObjectType() const; - int GetArrayTypeId() const; - int GetElementTypeId() const; - - // Get the current size - asUINT GetSize() const; - - // Returns true if the array is empty - bool IsEmpty() const; - - // Pre-allocates memory for elements - void Reserve(asUINT maxElements); - - // Resize the array - void Resize(asUINT numElements); - - // Get a pointer to an element. Returns 0 if out of bounds - void *At(asUINT index); - const void *At(asUINT index) const; - - // Set value of an element. - // The value arg should be a pointer to the value that will be copied to the element. - // Remember, if the array holds handles the value parameter should be the - // address of the handle. The refCount of the object will also be incremented - void SetValue(asUINT index, void *value); - - // Copy the contents of one array to another (only if the types are the same) - CScriptArray &operator=(const CScriptArray&); - - // Compare two arrays - bool operator==(const CScriptArray &) const; - - // Array manipulation - void InsertAt(asUINT index, void *value); - void InsertAt(asUINT index, const CScriptArray &arr); - void InsertLast(void *value); - void RemoveAt(asUINT index); - void RemoveLast(); - void RemoveRange(asUINT start, asUINT count); - void SortAsc(); - void SortDesc(); - void SortAsc(asUINT startAt, asUINT count); - void SortDesc(asUINT startAt, asUINT count); - void Sort(asUINT startAt, asUINT count, bool asc); - void Sort(asIScriptFunction *less, asUINT startAt, asUINT count); - void Reverse(); - int Find(void *value) const; - int Find(asUINT startAt, void *value) const; - int FindByRef(void *ref) const; - int FindByRef(asUINT startAt, void *ref) const; - - // Return the address of internal buffer for direct manipulation of elements - void *GetBuffer(); - - // GC methods - int GetRefCount(); - void SetFlag(); - bool GetFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllHandles(asIScriptEngine *engine); - -protected: - mutable int refCount; - mutable bool gcFlag; - asITypeInfo *objType; - SArrayBuffer *buffer; - int elementSize; - int subTypeId; - - // Constructors - CScriptArray(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list - CScriptArray(asUINT length, asITypeInfo *ot); - CScriptArray(asUINT length, void *defVal, asITypeInfo *ot); - CScriptArray(const CScriptArray &other); - virtual ~CScriptArray(); - - bool Less(const void *a, const void *b, bool asc); - void *GetArrayItemPointer(int index); - void *GetDataPointer(void *buffer); - void Copy(void *dst, void *src); - void Precache(); - bool CheckMaxSize(asUINT numElements); - void Resize(int delta, asUINT at); - void CreateBuffer(SArrayBuffer **buf, asUINT numElements); - void DeleteBuffer(SArrayBuffer *buf); - void CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src); - void Construct(SArrayBuffer *buf, asUINT start, asUINT end); - void Destruct(SArrayBuffer *buf, asUINT start, asUINT end); - bool Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const; -}; - -void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray); - -END_AS_NAMESPACE - -#endif diff --git a/extern/angelscript_addons/scriptbuilder/scriptbuilder.cpp b/extern/angelscript_addons/scriptbuilder/scriptbuilder.cpp deleted file mode 100644 index 97b2833..0000000 --- a/extern/angelscript_addons/scriptbuilder/scriptbuilder.cpp +++ /dev/null @@ -1,1167 +0,0 @@ -#include "scriptbuilder.h" -#include -#include -using namespace std; - -#include -#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(__S3E__) -#include -#endif -#ifdef _WIN32_WCE -#include // For GetModuleFileName() -#endif - -#if defined(__S3E__) || defined(__APPLE__) || defined(__GNUC__) -#include // For getcwd() -#endif - -BEGIN_AS_NAMESPACE - -// Helper functions -static string GetCurrentDir(); -static string GetAbsolutePath(const string &path); - - -CScriptBuilder::CScriptBuilder() -{ - engine = 0; - module = 0; - - includeCallback = 0; - includeParam = 0; - - pragmaCallback = 0; - pragmaParam = 0; -} - -void CScriptBuilder::SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam) -{ - includeCallback = callback; - includeParam = userParam; -} - -void CScriptBuilder::SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam) -{ - pragmaCallback = callback; - pragmaParam = userParam; -} - -int CScriptBuilder::StartNewModule(asIScriptEngine *inEngine, const char *moduleName) -{ - if(inEngine == 0 ) return -1; - - engine = inEngine; - module = inEngine->GetModule(moduleName, asGM_ALWAYS_CREATE); - if( module == 0 ) - return -1; - - ClearAll(); - - return 0; -} - -asIScriptEngine *CScriptBuilder::GetEngine() -{ - return engine; -} - -asIScriptModule *CScriptBuilder::GetModule() -{ - return module; -} - -unsigned int CScriptBuilder::GetSectionCount() const -{ - return (unsigned int)(includedScripts.size()); -} - -string CScriptBuilder::GetSectionName(unsigned int idx) const -{ - if( idx >= includedScripts.size() ) return ""; - -#ifdef _WIN32 - set::const_iterator it = includedScripts.begin(); -#else - set::const_iterator it = includedScripts.begin(); -#endif - while( idx-- > 0 ) it++; - return *it; -} - -// Returns 1 if the section was included -// Returns 0 if the section was not included because it had already been included before -// Returns <0 if there was an error -int CScriptBuilder::AddSectionFromFile(const char *filename) -{ - // The file name stored in the set should be the fully resolved name because - // it is possible to name the same file in multiple ways using relative paths. - string fullpath = GetAbsolutePath(filename); - - if( IncludeIfNotAlreadyIncluded(fullpath.c_str()) ) - { - int r = LoadScriptSection(fullpath.c_str()); - if( r < 0 ) - return r; - else - return 1; - } - - return 0; -} - -// Returns 1 if the section was included -// Returns 0 if the section was not included because it had already been included before -// Returns <0 if there was an error -int CScriptBuilder::AddSectionFromMemory(const char *sectionName, const char *scriptCode, unsigned int scriptLength, int lineOffset) -{ - if( IncludeIfNotAlreadyIncluded(sectionName) ) - { - int r = ProcessScriptSection(scriptCode, scriptLength, sectionName, lineOffset); - if( r < 0 ) - return r; - else - return 1; - } - - return 0; -} - -int CScriptBuilder::BuildModule() -{ - return Build(); -} - -void CScriptBuilder::DefineWord(const char *word) -{ - string sword = word; - if( definedWords.find(sword) == definedWords.end() ) - { - definedWords.insert(sword); - } -} - -void CScriptBuilder::ClearAll() -{ - includedScripts.clear(); - -#if AS_PROCESS_METADATA == 1 - currentClass = ""; - currentNamespace = ""; - - foundDeclarations.clear(); - typeMetadataMap.clear(); - funcMetadataMap.clear(); - varMetadataMap.clear(); -#endif -} - -bool CScriptBuilder::IncludeIfNotAlreadyIncluded(const char *filename) -{ - string scriptFile = filename; - if( includedScripts.find(scriptFile) != includedScripts.end() ) - { - // Already included - return false; - } - - // Add the file to the set of included sections - includedScripts.insert(scriptFile); - - return true; -} - -int CScriptBuilder::LoadScriptSection(const char *filename) -{ - // Open the script file - string scriptFile = filename; -#if _MSC_VER >= 1500 && !defined(__S3E__) - FILE *f = 0; - fopen_s(&f, scriptFile.c_str(), "rb"); -#else - FILE *f = fopen(scriptFile.c_str(), "rb"); -#endif - if( f == 0 ) - { - // Write a message to the engine's message callback - string msg = "Failed to open script file '" + GetAbsolutePath(scriptFile) + "'"; - engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); - - // TODO: Write the file where this one was included from - - return -1; - } - - // Determine size of the file - fseek(f, 0, SEEK_END); - int len = ftell(f); - fseek(f, 0, SEEK_SET); - - // On Win32 it is possible to do the following instead - // int len = _filelength(_fileno(f)); - - // Read the entire file - string code; - size_t c = 0; - if( len > 0 ) - { - code.resize(len); - c = fread(&code[0], len, 1, f); - } - - fclose(f); - - if( c == 0 && len > 0 ) - { - // Write a message to the engine's message callback - string msg = "Failed to load script file '" + GetAbsolutePath(scriptFile) + "'"; - engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); - return -1; - } - - // Process the script section even if it is zero length so that the name is registered - return ProcessScriptSection(code.c_str(), (unsigned int)(code.length()), filename, 0); -} - -int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset) -{ - vector includes; - - // Perform a superficial parsing of the script first to store the metadata - if( length ) - modifiedScript.assign(script, length); - else - modifiedScript = script; - - // First perform the checks for #if directives to exclude code that shouldn't be compiled - unsigned int pos = 0; - int nested = 0; - while( pos < modifiedScript.size() ) - { - asUINT len = 0; - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_UNKNOWN && modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) - { - int start = pos++; - - // Is this an #if directive? - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - - string token; - token.assign(&modifiedScript[pos], len); - - pos += len; - - if( token == "if" ) - { - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_WHITESPACE ) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } - - if( t == asTC_IDENTIFIER ) - { - string word; - word.assign(&modifiedScript[pos], len); - - // Overwrite the #if directive with space characters to avoid compiler error - pos += len; - OverwriteCode(start, pos-start); - - // Has this identifier been defined by the application or not? - if( definedWords.find(word) == definedWords.end() ) - { - // Exclude all the code until and including the #endif - pos = ExcludeCode(pos); - } - else - { - nested++; - } - } - } - else if( token == "endif" ) - { - // Only remove the #endif if there was a matching #if - if( nested > 0 ) - { - OverwriteCode(start, pos-start); - nested--; - } - } - } - else - pos += len; - } - -#if AS_PROCESS_METADATA == 1 - // Preallocate memory - string name, declaration; - vector metadata; - declaration.reserve(100); -#endif - - // Then check for meta data and #include directives - pos = 0; - while( pos < modifiedScript.size() ) - { - asUINT len = 0; - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_COMMENT || t == asTC_WHITESPACE ) - { - pos += len; - continue; - } - -#if AS_PROCESS_METADATA == 1 - // Check if class - if( currentClass == "" && modifiedScript.substr(pos,len) == "class" ) - { - // Get the identifier after "class" - do - { - pos += len; - if( pos >= modifiedScript.size() ) - { - t = asTC_UNKNOWN; - break; - } - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } while(t == asTC_COMMENT || t == asTC_WHITESPACE); - - if( t == asTC_IDENTIFIER ) - { - currentClass = modifiedScript.substr(pos,len); - - // Search until first { or ; is encountered - while( pos < modifiedScript.length() ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - - // If start of class section encountered stop - if( modifiedScript[pos] == '{' ) - { - pos += len; - break; - } - else if (modifiedScript[pos] == ';') - { - // The class declaration has ended and there are no children - currentClass = ""; - pos += len; - break; - } - - // Check next symbol - pos += len; - } - } - - continue; - } - - // Check if end of class - if( currentClass != "" && modifiedScript[pos] == '}' ) - { - currentClass = ""; - pos += len; - continue; - } - - // Check if namespace - if( modifiedScript.substr(pos,len) == "namespace" ) - { - // Get the identifier after "namespace" - do - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } while(t == asTC_COMMENT || t == asTC_WHITESPACE); - - if( currentNamespace != "" ) - currentNamespace += "::"; - currentNamespace += modifiedScript.substr(pos,len); - - // Search until first { is encountered - while( pos < modifiedScript.length() ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - - // If start of namespace section encountered stop - if( modifiedScript[pos] == '{' ) - { - pos += len; - break; - } - - // Check next symbol - pos += len; - } - - continue; - } - - // Check if end of namespace - if( currentNamespace != "" && modifiedScript[pos] == '}' ) - { - size_t found = currentNamespace.rfind( "::" ); - if( found != string::npos ) - { - currentNamespace.erase( found ); - } - else - { - currentNamespace = ""; - } - pos += len; - continue; - } - - // Is this the start of metadata? - if( modifiedScript[pos] == '[' ) - { - // Get the metadata string - pos = ExtractMetadata(pos, metadata); - - // Determine what this metadata is for - int type; - ExtractDeclaration(pos, name, declaration, type); - - // Store away the declaration in a map for lookup after the build has completed - if( type > 0 ) - { - SMetadataDecl decl(metadata, name, declaration, type, currentClass, currentNamespace); - foundDeclarations.push_back(decl); - } - } - else -#endif - // Is this a preprocessor directive? - if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) - { - int start = pos++; - - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_IDENTIFIER ) - { - string token; - token.assign(&modifiedScript[pos], len); - if( token == "include" ) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_WHITESPACE ) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } - - if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') ) - { - // Get the include file - string includefile; - includefile.assign(&modifiedScript[pos+1], len-2); - pos += len; - - // Store it for later processing - includes.push_back(includefile); - - // Overwrite the include directive with space characters to avoid compiler error - OverwriteCode(start, pos-start); - } - } - else if (token == "pragma") - { - // Read until the end of the line - pos += len; - for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++); - - // Call the pragma callback - string pragmaText(&modifiedScript[start + 7], pos - start - 7); - int r = pragmaCallback ? pragmaCallback(pragmaText, *this, pragmaParam) : -1; - if (r < 0) - { - // TODO: Report the correct line number - engine->WriteMessage(sectionname, 0, 0, asMSGTYPE_ERROR, "Invalid #pragma directive"); - return r; - } - - // Overwrite the pragma directive with space characters to avoid compiler error - OverwriteCode(start, pos - start); - } - } - } - // Don't search for metadata/includes within statement blocks or between tokens in statements - else - { - pos = SkipStatement(pos); - } - } - - // Build the actual script - engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true); - module->AddScriptSection(sectionname, modifiedScript.c_str(), modifiedScript.size(), lineOffset); - - if( includes.size() > 0 ) - { - // If the callback has been set, then call it for each included file - if( includeCallback ) - { - for( int n = 0; n < (int)includes.size(); n++ ) - { - int r = includeCallback(includes[n].c_str(), sectionname, this, includeParam); - if( r < 0 ) - return r; - } - } - else - { - // By default we try to load the included file from the relative directory of the current file - - // Determine the path of the current script so that we can resolve relative paths for includes - string path = sectionname; - size_t posOfSlash = path.find_last_of("/\\"); - if( posOfSlash != string::npos ) - path.resize(posOfSlash+1); - else - path = ""; - - // Load the included scripts - for( int n = 0; n < (int)includes.size(); n++ ) - { - // If the include is a relative path, then prepend the path of the originating script - if( includes[n].find_first_of("/\\") != 0 && - includes[n].find_first_of(":") == string::npos ) - { - includes[n] = path + includes[n]; - } - - // Include the script section - int r = AddSectionFromFile(includes[n].c_str()); - if( r < 0 ) - return r; - } - } - } - - return 0; -} - -int CScriptBuilder::Build() -{ - int r = module->Build(); - if( r < 0 ) - return r; - -#if AS_PROCESS_METADATA == 1 - // After the script has been built, the metadata strings should be - // stored for later lookup by function id, type id, and variable index - for( int n = 0; n < (int)foundDeclarations.size(); n++ ) - { - SMetadataDecl *decl = &foundDeclarations[n]; - module->SetDefaultNamespace(decl->nameSpace.c_str()); - if( decl->type == MDT_TYPE ) - { - // Find the type id - int typeId = module->GetTypeIdByDecl(decl->declaration.c_str()); - assert( typeId >= 0 ); - if( typeId >= 0 ) - typeMetadataMap.insert(map >::value_type(typeId, decl->metadata)); - } - else if( decl->type == MDT_FUNC ) - { - if( decl->parentClass == "" ) - { - // Find the function id - asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); - assert( func ); - if( func ) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - else - { - // Find the method id - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert( typeId > 0 ); - map::iterator it = classMetadataMap.find(typeId); - if( it == classMetadataMap.end() ) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - asITypeInfo *type = engine->GetTypeInfoById(typeId); - asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); - assert( func ); - if( func ) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - else if( decl->type == MDT_VIRTPROP ) - { - if( decl->parentClass == "" ) - { - // Find the global virtual property accessors - asIScriptFunction *func = module->GetFunctionByName(("get_" + decl->declaration).c_str()); - if( func ) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - func = module->GetFunctionByName(("set_" + decl->declaration).c_str()); - if( func ) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - else - { - // Find the method virtual property accessors - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert( typeId > 0 ); - map::iterator it = classMetadataMap.find(typeId); - if( it == classMetadataMap.end() ) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - asITypeInfo *type = engine->GetTypeInfoById(typeId); - asIScriptFunction *func = type->GetMethodByName(("get_" + decl->declaration).c_str()); - if( func ) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - func = type->GetMethodByName(("set_" + decl->declaration).c_str()); - if( func ) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - else if( decl->type == MDT_VAR ) - { - if( decl->parentClass == "" ) - { - // Find the global variable index - int varIdx = module->GetGlobalVarIndexByName(decl->declaration.c_str()); - assert( varIdx >= 0 ); - if( varIdx >= 0 ) - varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); - } - else - { - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert( typeId > 0 ); - - // Add the classes if needed - map::iterator it = classMetadataMap.find(typeId); - if( it == classMetadataMap.end() ) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - // Add the variable to class - asITypeInfo *objectType = engine->GetTypeInfoById(typeId); - int idx = -1; - - // Search through all properties to get proper declaration - for( asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i ) - { - const char *name; - objectType->GetProperty(i, &name); - if( decl->declaration == name ) - { - idx = i; - break; - } - } - - // If found, add it - assert( idx >= 0 ); - if( idx >= 0 ) it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); - } - } - else if (decl->type == MDT_FUNC_OR_VAR) - { - if (decl->parentClass == "") - { - // Find the global variable index - int varIdx = module->GetGlobalVarIndexByName(decl->name.c_str()); - if (varIdx >= 0) - varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); - else - { - asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); - assert(func); - if (func) - funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - else - { - int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); - assert(typeId > 0); - - // Add the classes if needed - map::iterator it = classMetadataMap.find(typeId); - if (it == classMetadataMap.end()) - { - classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); - it = classMetadataMap.find(typeId); - } - - // Add the variable to class - asITypeInfo *objectType = engine->GetTypeInfoById(typeId); - int idx = -1; - - // Search through all properties to get proper declaration - for (asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i) - { - const char *name; - objectType->GetProperty(i, &name); - if (decl->name == name) - { - idx = i; - break; - } - } - - // If found, add it - if (idx >= 0) - it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); - else - { - // Look for the matching method instead - asITypeInfo *type = engine->GetTypeInfoById(typeId); - asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); - assert(func); - if (func) - it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); - } - } - } - } - module->SetDefaultNamespace(""); -#endif - - return 0; -} - -int CScriptBuilder::SkipStatement(int pos) -{ - asUINT len = 0; - - // Skip until ; or { whichever comes first - while( pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' && modifiedScript[pos] != '{' ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - pos += len; - } - - // Skip entire statement block - if( pos < (int)modifiedScript.length() && modifiedScript[pos] == '{' ) - { - pos += 1; - - // Find the end of the statement block - int level = 1; - while( level > 0 && pos < (int)modifiedScript.size() ) - { - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( t == asTC_KEYWORD ) - { - if( modifiedScript[pos] == '{' ) - level++; - else if( modifiedScript[pos] == '}' ) - level--; - } - - pos += len; - } - } - else - pos += 1; - - return pos; -} - -// Overwrite all code with blanks until the matching #endif -int CScriptBuilder::ExcludeCode(int pos) -{ - asUINT len = 0; - int nested = 0; - while( pos < (int)modifiedScript.size() ) - { - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if( modifiedScript[pos] == '#' ) - { - modifiedScript[pos] = ' '; - pos++; - - // Is it an #if or #endif directive? - engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - string token; - token.assign(&modifiedScript[pos], len); - OverwriteCode(pos, len); - - if( token == "if" ) - { - nested++; - } - else if( token == "endif" ) - { - if( nested-- == 0 ) - { - pos += len; - break; - } - } - } - else if( modifiedScript[pos] != '\n' ) - { - OverwriteCode(pos, len); - } - pos += len; - } - - return pos; -} - -// Overwrite all characters except line breaks with blanks -void CScriptBuilder::OverwriteCode(int start, int len) -{ - char *code = &modifiedScript[start]; - for( int n = 0; n < len; n++ ) - { - if( *code != '\n' ) - *code = ' '; - code++; - } -} - -#if AS_PROCESS_METADATA == 1 -int CScriptBuilder::ExtractMetadata(int pos, vector &metadata) -{ - metadata.clear(); - - // Extract all metadata. They can be separated by whitespace and comments - for (;;) - { - string metadataString = ""; - - // Overwrite the metadata with space characters to allow compilation - modifiedScript[pos] = ' '; - - // Skip opening brackets - pos += 1; - - int level = 1; - asUINT len = 0; - while (level > 0 && pos < (int)modifiedScript.size()) - { - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - if (t == asTC_KEYWORD) - { - if (modifiedScript[pos] == '[') - level++; - else if (modifiedScript[pos] == ']') - level--; - } - - // Copy the metadata to our buffer - if (level > 0) - metadataString.append(&modifiedScript[pos], len); - - // Overwrite the metadata with space characters to allow compilation - if (t != asTC_WHITESPACE) - OverwriteCode(pos, len); - - pos += len; - } - - metadata.push_back(metadataString); - - // Check for more metadata. Possibly separated by comments - asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - while (t == asTC_COMMENT || t == asTC_WHITESPACE) - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } - - if (modifiedScript[pos] != '[') - break; - } - - return pos; -} - -int CScriptBuilder::ExtractDeclaration(int pos, string &name, string &declaration, int &type) -{ - declaration = ""; - type = 0; - - int start = pos; - - std::string token; - asUINT len = 0; - asETokenClass t = asTC_WHITESPACE; - - // Skip white spaces, comments, and leading decorators - do - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - token.assign(&modifiedScript[pos], len); - } while ( t == asTC_WHITESPACE || t == asTC_COMMENT || - token == "private" || token == "protected" || - token == "shared" || token == "external" || - token == "final" || token == "abstract" ); - - // We're expecting, either a class, interface, function, or variable declaration - if( t == asTC_KEYWORD || t == asTC_IDENTIFIER ) - { - token.assign(&modifiedScript[pos], len); - if( token == "interface" || token == "class" || token == "enum" ) - { - // Skip white spaces and comments - do - { - pos += len; - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - } while ( t == asTC_WHITESPACE || t == asTC_COMMENT ); - - if( t == asTC_IDENTIFIER ) - { - type = MDT_TYPE; - declaration.assign(&modifiedScript[pos], len); - pos += len; - return pos; - } - } - else - { - // For function declarations, store everything up to the start of the - // statement block, except for succeeding decorators (final, override, etc) - - // For variable declaration store just the name as there can only be one - - // We'll only know if the declaration is a variable or function declaration - // when we see the statement block, or absense of a statement block. - bool hasParenthesis = false; - int nestedParenthesis = 0; - declaration.append(&modifiedScript[pos], len); - pos += len; - for(; pos < (int)modifiedScript.size();) - { - t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); - token.assign(&modifiedScript[pos], len); - if (t == asTC_KEYWORD) - { - if (token == "{" && nestedParenthesis == 0) - { - if (hasParenthesis) - { - // We've found the end of a function signature - type = MDT_FUNC; - } - else - { - // We've found a virtual property. Just keep the name - declaration = name; - type = MDT_VIRTPROP; - } - return pos; - } - if ((token == "=" && !hasParenthesis) || token == ";") - { - if (hasParenthesis) - { - // The declaration is ambigous. It can be a variable with initialization, or a function prototype - type = MDT_FUNC_OR_VAR; - } - else - { - // Substitute the declaration with just the name - declaration = name; - type = MDT_VAR; - } - return pos; - } - else if (token == "(") - { - nestedParenthesis++; - - // This is the first parenthesis we encounter. If the parenthesis isn't followed - // by a statement block, then this is a variable declaration, in which case we - // should only store the type and name of the variable, not the initialization parameters. - hasParenthesis = true; - } - else if (token == ")") - { - nestedParenthesis--; - } - } - else if( t == asTC_IDENTIFIER ) - { - name = token; - } - - // Skip trailing decorators - if( !hasParenthesis || nestedParenthesis > 0 || t != asTC_IDENTIFIER || (token != "final" && token != "override") ) - declaration += token; - - pos += len; - } - } - } - - return start; -} - -vector CScriptBuilder::GetMetadataForType(int typeId) -{ - map >::iterator it = typeMetadataMap.find(typeId); - if( it != typeMetadataMap.end() ) - return it->second; - - return vector(); -} - -vector CScriptBuilder::GetMetadataForFunc(asIScriptFunction *func) -{ - if( func ) - { - map >::iterator it = funcMetadataMap.find(func->GetId()); - if( it != funcMetadataMap.end() ) - return it->second; - } - - return vector(); -} - -vector CScriptBuilder::GetMetadataForVar(int varIdx) -{ - map >::iterator it = varMetadataMap.find(varIdx); - if( it != varMetadataMap.end() ) - return it->second; - - return vector(); -} - -vector CScriptBuilder::GetMetadataForTypeProperty(int typeId, int varIdx) -{ - map::iterator typeIt = classMetadataMap.find(typeId); - if(typeIt == classMetadataMap.end()) return vector(); - - map >::iterator propIt = typeIt->second.varMetadataMap.find(varIdx); - if(propIt == typeIt->second.varMetadataMap.end()) return vector(); - - return propIt->second; -} - -vector CScriptBuilder::GetMetadataForTypeMethod(int typeId, asIScriptFunction *method) -{ - if( method ) - { - map::iterator typeIt = classMetadataMap.find(typeId); - if (typeIt == classMetadataMap.end()) return vector(); - - map >::iterator methodIt = typeIt->second.funcMetadataMap.find(method->GetId()); - if(methodIt == typeIt->second.funcMetadataMap.end()) return vector(); - - return methodIt->second; - } - - return vector(); -} -#endif - -string GetAbsolutePath(const string &file) -{ - string str = file; - - // If this is a relative path, complement it with the current path - if( !((str.length() > 0 && (str[0] == '/' || str[0] == '\\')) || - str.find(":") != string::npos) ) - { - str = GetCurrentDir() + "/" + str; - } - - // Replace backslashes for forward slashes - size_t pos = 0; - while( (pos = str.find("\\", pos)) != string::npos ) - str[pos] = '/'; - - // Replace /./ with / - pos = 0; - while( (pos = str.find("/./", pos)) != string::npos ) - str.erase(pos+1, 2); - - // For each /../ remove the parent dir and the /../ - pos = 0; - while( (pos = str.find("/../")) != string::npos ) - { - size_t pos2 = str.rfind("/", pos-1); - if( pos2 != string::npos ) - str.erase(pos2, pos+3-pos2); - else - { - // The path is invalid - break; - } - } - - return str; -} - -string GetCurrentDir() -{ - char buffer[1024]; -#if defined(_MSC_VER) || defined(_WIN32) - #ifdef _WIN32_WCE - static TCHAR apppath[MAX_PATH] = TEXT(""); - if (!apppath[0]) - { - GetModuleFileName(NULL, apppath, MAX_PATH); - - int appLen = _tcslen(apppath); - - // Look for the last backslash in the path, which would be the end - // of the path itself and the start of the filename. We only want - // the path part of the exe's full-path filename - // Safety is that we make sure not to walk off the front of the - // array (in case the path is nothing more than a filename) - while (appLen > 1) - { - if (apppath[appLen-1] == TEXT('\\')) - break; - appLen--; - } - - // Terminate the string after the trailing backslash - apppath[appLen] = TEXT('\0'); - } - #ifdef _UNICODE - wcstombs(buffer, apppath, min(1024, wcslen(apppath)*sizeof(wchar_t))); - #else - memcpy(buffer, apppath, min(1024, strlen(apppath))); - #endif - - return buffer; - #elif defined(__S3E__) - // Marmalade uses its own portable C library - return getcwd(buffer, (int)1024); - #elif _XBOX_VER >= 200 - // XBox 360 doesn't support the getcwd function, just use the root folder - return "game:/"; - #elif defined(_M_ARM) - // TODO: How to determine current working dir on Windows Phone? - return ""; - #else - return _getcwd(buffer, (int)1024); - #endif // _MSC_VER -#elif defined(__APPLE__) || defined(__linux__) - return getcwd(buffer, 1024); -#else - return ""; -#endif -} - -END_AS_NAMESPACE - - diff --git a/extern/angelscript_addons/scriptbuilder/scriptbuilder.h b/extern/angelscript_addons/scriptbuilder/scriptbuilder.h deleted file mode 100644 index c11f1b9..0000000 --- a/extern/angelscript_addons/scriptbuilder/scriptbuilder.h +++ /dev/null @@ -1,216 +0,0 @@ -#ifndef SCRIPTBUILDER_H -#define SCRIPTBUILDER_H - -//--------------------------- -// Compilation settings -// - -// Set this flag to turn on/off metadata processing -// 0 = off -// 1 = on -#ifndef AS_PROCESS_METADATA -#define AS_PROCESS_METADATA 1 -#endif - -// TODO: Implement flags for turning on/off include directives and conditional programming - - - -//--------------------------- -// Declaration -// - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - - -#if defined(_MSC_VER) && _MSC_VER <= 1200 -// disable the annoying warnings on MSVC 6 -#pragma warning (disable:4786) -#endif - -#include -#include -#include -#include -#include // _strcmpi - -BEGIN_AS_NAMESPACE - -class CScriptBuilder; - -// This callback will be called for each #include directive encountered by the -// builder. The callback should call the AddSectionFromFile or AddSectionFromMemory -// to add the included section to the script. If the include cannot be resolved -// then the function should return a negative value to abort the compilation. -typedef int (*INCLUDECALLBACK_t)(const char *include, const char *from, CScriptBuilder *builder, void *userParam); - -// This callback will be called for each #pragma directive encountered by the builder. -// The application can interpret the pragmaText and decide what do to based on that. -// If the callback returns a negative value the builder will report an error and abort the compilation. -typedef int(*PRAGMACALLBACK_t)(const std::string &pragmaText, CScriptBuilder &builder, void *userParam); - -// Helper class for loading and pre-processing script files to -// support include directives and metadata declarations -class CScriptBuilder -{ -public: - CScriptBuilder(); - - // Start a new module - int StartNewModule(asIScriptEngine *engine, const char *moduleName); - - // Load a script section from a file on disk - // Returns 1 if the file was included - // 0 if the file had already been included before - // <0 on error - int AddSectionFromFile(const char *filename); - - // Load a script section from memory - // Returns 1 if the section was included - // 0 if a section with the same name had already been included before - // <0 on error - int AddSectionFromMemory(const char *sectionName, - const char *scriptCode, - unsigned int scriptLength = 0, - int lineOffset = 0); - - // Build the added script sections - int BuildModule(); - - // Returns the engine - asIScriptEngine *GetEngine(); - - // Returns the current module - asIScriptModule *GetModule(); - - // Register the callback for resolving include directive - void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); - - // Register the callback for resolving pragma directive - void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); - - // Add a pre-processor define for conditional compilation - void DefineWord(const char *word); - - // Enumerate included script sections - unsigned int GetSectionCount() const; - std::string GetSectionName(unsigned int idx) const; - -#if AS_PROCESS_METADATA == 1 - // Get metadata declared for classes, interfaces, and enums - std::vector GetMetadataForType(int typeId); - - // Get metadata declared for functions - std::vector GetMetadataForFunc(asIScriptFunction *func); - - // Get metadata declared for global variables - std::vector GetMetadataForVar(int varIdx); - - // Get metadata declared for class variables - std::vector GetMetadataForTypeProperty(int typeId, int varIdx); - - // Get metadata declared for class methods - std::vector GetMetadataForTypeMethod(int typeId, asIScriptFunction *method); -#endif - -protected: - void ClearAll(); - int Build(); - int ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset); - int LoadScriptSection(const char *filename); - bool IncludeIfNotAlreadyIncluded(const char *filename); - - int SkipStatement(int pos); - - int ExcludeCode(int start); - void OverwriteCode(int start, int len); - - asIScriptEngine *engine; - asIScriptModule *module; - std::string modifiedScript; - - INCLUDECALLBACK_t includeCallback; - void *includeParam; - - PRAGMACALLBACK_t pragmaCallback; - void *pragmaParam; - -#if AS_PROCESS_METADATA == 1 - int ExtractMetadata(int pos, std::vector &outMetadata); - int ExtractDeclaration(int pos, std::string &outName, std::string &outDeclaration, int &outType); - - enum METADATATYPE - { - MDT_TYPE = 1, - MDT_FUNC = 2, - MDT_VAR = 3, - MDT_VIRTPROP = 4, - MDT_FUNC_OR_VAR = 5 - }; - - // Temporary structure for storing metadata and declaration - struct SMetadataDecl - { - SMetadataDecl(std::vector m, std::string n, std::string d, int t, std::string c, std::string ns) : metadata(m), name(n), declaration(d), type(t), parentClass(c), nameSpace(ns) {} - std::vector metadata; - std::string name; - std::string declaration; - int type; - std::string parentClass; - std::string nameSpace; - }; - std::vector foundDeclarations; - std::string currentClass; - std::string currentNamespace; - - // Storage of metadata for global declarations - std::map > typeMetadataMap; - std::map > funcMetadataMap; - std::map > varMetadataMap; - - // Storage of metadata for class member declarations - struct SClassMetadata - { - SClassMetadata(const std::string& aName) : className(aName) {} - std::string className; - std::map > funcMetadataMap; - std::map > varMetadataMap; - }; - std::map classMetadataMap; - -#endif - -#ifdef _WIN32 - // On Windows the filenames are case insensitive so the comparisons to - // avoid duplicate includes must also be case insensitive. True case insensitive - // is not easy as it must be language aware, but a simple implementation such - // as strcmpi should suffice in almost all cases. - // - // ref: http://www.gotw.ca/gotw/029.htm - // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317761(v=vs.85).aspx - // ref: http://site.icu-project.org/ - - // TODO: Strings by default are treated as UTF8 encoded. If the application choses to - // use a different encoding, the comparison algorithm should be adjusted as well - - struct ci_less - { - bool operator()(const std::string &a, const std::string &b) const - { - return _stricmp(a.c_str(), b.c_str()) < 0; - } - }; - std::set includedScripts; -#else - std::set includedScripts; -#endif - - std::set definedWords; -}; - -END_AS_NAMESPACE - -#endif diff --git a/extern/angelscript_addons/scriptdictionary/scriptdictionary.cpp b/extern/angelscript_addons/scriptdictionary/scriptdictionary.cpp deleted file mode 100644 index 23a49eb..0000000 --- a/extern/angelscript_addons/scriptdictionary/scriptdictionary.cpp +++ /dev/null @@ -1,1299 +0,0 @@ -#include -#include -#include "scriptdictionary.h" -#include "../scriptarray/scriptarray.h" - -BEGIN_AS_NAMESPACE - -using namespace std; - -//------------------------------------------------------------------------ -// Object types are cached as user data to avoid costly runtime lookups - -// We just define a number here that we assume nobody else is using for -// object type user data. The add-ons have reserved the numbers 1000 -// through 1999 for this purpose, so we should be fine. -const asPWORD DICTIONARY_CACHE = 1003; - -// This cache holds the object type of the dictionary type and array type -// so it isn't necessary to look this up each time the dictionary or array -// is created. -struct SDictionaryCache -{ - asITypeInfo *dictType; - asITypeInfo *arrayType; - asITypeInfo *keyType; - - // This is called from RegisterScriptDictionary - static void Setup(asIScriptEngine *engine) - { - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - if( cache == 0 ) - { - cache = new SDictionaryCache; - engine->SetUserData(cache, DICTIONARY_CACHE); - engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); - - cache->dictType = engine->GetTypeInfoByName("dictionary"); - cache->arrayType = engine->GetTypeInfoByDecl("array"); - cache->keyType = engine->GetTypeInfoByDecl("string"); - } - } - - // This is called from the engine when shutting down - static void Cleanup(asIScriptEngine *engine) - { - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - if( cache ) - delete cache; - } -}; - -//-------------------------------------------------------------------------- -// CScriptDictionary implementation - -CScriptDictionary *CScriptDictionary::Create(asIScriptEngine *engine) -{ - // Use the custom memory routine from AngelScript to allow application to better control how much memory is used - CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); - new(obj) CScriptDictionary(engine); - return obj; -} - -CScriptDictionary *CScriptDictionary::Create(asBYTE *buffer) -{ - // Use the custom memory routine from AngelScript to allow application to better control how much memory is used - CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); - new(obj) CScriptDictionary(buffer); - return obj; -} - -CScriptDictionary::CScriptDictionary(asIScriptEngine *engine) -{ - Init(engine); -} - -void CScriptDictionary::Init(asIScriptEngine *e) -{ - // We start with one reference - refCount = 1; - gcFlag = false; - - // Keep a reference to the engine for as long as we live - // We don't increment the reference counter, because the - // engine will hold a pointer to the object in the GC. - engine = e; - - // The dictionary object type is cached to avoid dynamically parsing it each time - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - - // Notify the garbage collector of this object - engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType); -} - -CScriptDictionary::CScriptDictionary(asBYTE *buffer) -{ - // This constructor will always be called from a script - // so we can get the engine from the active context - asIScriptContext *ctx = asGetActiveContext(); - Init(ctx->GetEngine()); - - // Determine if the dictionary key type is registered as reference type or value type - SDictionaryCache& cache = *reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - bool keyAsRef = cache.keyType->GetFlags() & asOBJ_REF ? true : false; - - // Initialize the dictionary from the buffer - asUINT length = *(asUINT*)buffer; - buffer += 4; - - while( length-- ) - { - // Align the buffer pointer on a 4 byte boundary in - // case previous value was smaller than 4 bytes - if( asPWORD(buffer) & 0x3 ) - buffer += 4 - (asPWORD(buffer) & 0x3); - - // Get the name value pair from the buffer and insert it in the dictionary - dictKey_t name; - if (keyAsRef) - { - name = **(dictKey_t**)buffer; - buffer += sizeof(dictKey_t*); - } - else - { - name = *(dictKey_t*)buffer; - buffer += sizeof(dictKey_t); - } - - // Get the type id of the value - int typeId = *(int*)buffer; - buffer += sizeof(int); - - // Depending on the type id, the value will inline in the buffer or a pointer - void *ref = (void*)buffer; - - if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE ) - { - // Convert primitive values to either int64 or double, so we can use the overloaded Set methods - asINT64 i64; - double d; - switch( typeId ) - { - case asTYPEID_INT8: i64 = *(char*) ref; break; - case asTYPEID_INT16: i64 = *(short*) ref; break; - case asTYPEID_INT32: i64 = *(int*) ref; break; - case asTYPEID_INT64: i64 = *(asINT64*) ref; break; - case asTYPEID_UINT8: i64 = *(unsigned char*) ref; break; - case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break; - case asTYPEID_UINT32: i64 = *(unsigned int*) ref; break; - case asTYPEID_UINT64: i64 = *(asINT64*) ref; break; - case asTYPEID_FLOAT: d = *(float*) ref; break; - case asTYPEID_DOUBLE: d = *(double*) ref; break; - } - - if( typeId >= asTYPEID_FLOAT ) - Set(name, d); - else - Set(name, i64); - } - else - { - if( (typeId & asTYPEID_MASK_OBJECT) && - !(typeId & asTYPEID_OBJHANDLE) && - (engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) ) - { - // Dereference the pointer to get the reference to the actual object - ref = *(void**)ref; - } - - Set(name, ref, typeId); - } - - // Advance the buffer pointer with the size of the value - if( typeId & asTYPEID_MASK_OBJECT ) - { - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if( ti->GetFlags() & asOBJ_VALUE ) - buffer += ti->GetSize(); - else - buffer += sizeof(void*); - } - else if( typeId == 0 ) - { - // null pointer - buffer += sizeof(void*); - } - else - { - buffer += engine->GetSizeOfPrimitiveType(typeId); - } - } -} - -CScriptDictionary::~CScriptDictionary() -{ - // Delete all keys and values - DeleteAll(); -} - -void CScriptDictionary::AddRef() const -{ - // We need to clear the GC flag - gcFlag = false; - asAtomicInc(refCount); -} - -void CScriptDictionary::Release() const -{ - // We need to clear the GC flag - gcFlag = false; - if( asAtomicDec(refCount) == 0 ) - { - this->~CScriptDictionary(); - asFreeMem(const_cast(this)); - } -} - -int CScriptDictionary::GetRefCount() -{ - return refCount; -} - -void CScriptDictionary::SetGCFlag() -{ - gcFlag = true; -} - -bool CScriptDictionary::GetGCFlag() -{ - return gcFlag; -} - -void CScriptDictionary::EnumReferences(asIScriptEngine *inEngine) -{ - // TODO: If garbage collection can be done from a separate thread, then this method must be - // protected so that it doesn't get lost during the iteration if the dictionary is modified - - // Call the gc enum callback for each of the objects - dictMap_t::iterator it; - for( it = dict.begin(); it != dict.end(); it++ ) - { - if (it->second.m_typeId & asTYPEID_MASK_OBJECT) - { - asITypeInfo *subType = engine->GetTypeInfoById(it->second.m_typeId); - if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) - { - // For value types we need to forward the enum callback - // to the object so it can decide what to do - engine->ForwardGCEnumReferences(it->second.m_valueObj, subType); - } - else - { - // For others, simply notify the GC about the reference - inEngine->GCEnumCallback(it->second.m_valueObj); - } - } - } -} - -void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/) -{ - // We're being told to release all references in - // order to break circular references for dead objects - DeleteAll(); -} - -CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other) -{ - // Clear everything we had before - DeleteAll(); - - // Do a shallow copy of the dictionary - dictMap_t::const_iterator it; - for( it = other.dict.begin(); it != other.dict.end(); it++ ) - { - if( it->second.m_typeId & asTYPEID_OBJHANDLE ) - Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId); - else if( it->second.m_typeId & asTYPEID_MASK_OBJECT ) - Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId); - else - Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId); - } - - return *this; -} - -CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) -{ - // Return the existing value if it exists, else insert an empty value - return &dict[key]; -} - -const CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) const -{ - // Return the existing value if it exists - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return &it->second; - - // Else raise an exception - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Invalid access to non-existing value"); - - return 0; -} - -void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId) -{ - dictMap_t::iterator it; - it = dict.find(key); - if( it == dict.end() ) - it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first; - - it->second.Set(engine, value, typeId); -} - -// This overloaded method is implemented so that all integer and -// unsigned integers types will be stored in the dictionary as int64 -// through implicit conversions. This simplifies the management of the -// numeric types when the script retrieves the stored value using a -// different type. -void CScriptDictionary::Set(const dictKey_t &key, const asINT64 &value) -{ - Set(key, const_cast(&value), asTYPEID_INT64); -} - -// This overloaded method is implemented so that all floating point types -// will be stored in the dictionary as double through implicit conversions. -// This simplifies the management of the numeric types when the script -// retrieves the stored value using a different type. -void CScriptDictionary::Set(const dictKey_t &key, const double &value) -{ - Set(key, const_cast(&value), asTYPEID_DOUBLE); -} - -// Returns true if the value was successfully retrieved -bool CScriptDictionary::Get(const dictKey_t &key, void *value, int typeId) const -{ - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return it->second.Get(engine, value, typeId); - - // AngelScript has already initialized the value with a default value, - // so we don't have to do anything if we don't find the element, or if - // the element is incompatible with the requested type. - - return false; -} - -// Returns the type id of the stored value -int CScriptDictionary::GetTypeId(const dictKey_t &key) const -{ - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return it->second.m_typeId; - - return -1; -} - -bool CScriptDictionary::Get(const dictKey_t &key, asINT64 &value) const -{ - return Get(key, &value, asTYPEID_INT64); -} - -bool CScriptDictionary::Get(const dictKey_t &key, double &value) const -{ - return Get(key, &value, asTYPEID_DOUBLE); -} - -bool CScriptDictionary::Exists(const dictKey_t &key) const -{ - dictMap_t::const_iterator it; - it = dict.find(key); - if( it != dict.end() ) - return true; - - return false; -} - -bool CScriptDictionary::IsEmpty() const -{ - if( dict.size() == 0 ) - return true; - - return false; -} - -asUINT CScriptDictionary::GetSize() const -{ - return asUINT(dict.size()); -} - -bool CScriptDictionary::Delete(const dictKey_t &key) -{ - dictMap_t::iterator it; - it = dict.find(key); - if( it != dict.end() ) - { - it->second.FreeValue(engine); - dict.erase(it); - return true; - } - - return false; -} - -void CScriptDictionary::DeleteAll() -{ - dictMap_t::iterator it; - for( it = dict.begin(); it != dict.end(); it++ ) - it->second.FreeValue(engine); - - dict.clear(); -} - -CScriptArray* CScriptDictionary::GetKeys() const -{ - // Retrieve the object type for the array from the cache - SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); - asITypeInfo *ti = cache->arrayType; - - // Create the array object - CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size())); - long current = -1; - dictMap_t::const_iterator it; - for( it = dict.begin(); it != dict.end(); it++ ) - { - current++; - *(dictKey_t*)array->At(current) = it->first; - } - - return array; -} - -//-------------------------------------------------------------------------- -// Generic wrappers - -void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen) -{ - *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine()); -} - -void ScriptDictionaryListFactory_Generic(asIScriptGeneric *gen) -{ - asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0); - *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer); -} - -void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dict->AddRef(); -} - -void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dict->Release(); -} - -void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0); - *dict = *other; - *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict; -} - -void ScriptDictionarySet_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - int typeId = gen->GetArgTypeId(1); - dict->Set(*key, ref, typeId); -} - -void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - dict->Set(*key, *(asINT64*)ref); -} - -void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - dict->Set(*key, *(double*)ref); -} - -void ScriptDictionaryGet_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - int typeId = gen->GetArgTypeId(1); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId); -} - -void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref); -} - -void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - void *ref = *(void**)gen->GetAddressOfArg(1); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref); -} - -void ScriptDictionaryExists_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - bool ret = dict->Exists(*key); - *(bool*)gen->GetAddressOfReturnLocation() = ret; -} - -void ScriptDictionaryIsEmpty_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - bool ret = dict->IsEmpty(); - *(bool*)gen->GetAddressOfReturnLocation() = ret; -} - -void ScriptDictionaryGetSize_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - asUINT ret = dict->GetSize(); - *(asUINT*)gen->GetAddressOfReturnLocation() = ret; -} - -void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - *(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key); -} - -void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); - dict->DeleteAll(); -} - -static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); -} - -static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - self->SetGCFlag(); -} - -static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); -} - -static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->EnumReferences(engine); -} - -static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); - self->ReleaseAllReferences(engine); -} - -static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - *(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys(); -} - -static void CScriptDictionary_opIndex_Generic(asIScriptGeneric *gen) -{ - CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); -} - -static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen) -{ - const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject(); - dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); - *(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); -} - - -//------------------------------------------------------------------------- -// CScriptDictValue - -CScriptDictValue::CScriptDictValue() -{ - m_valueObj = 0; - m_typeId = 0; -} - -CScriptDictValue::CScriptDictValue(asIScriptEngine *engine, void *value, int typeId) -{ - m_valueObj = 0; - m_typeId = 0; - Set(engine, value, typeId); -} - -CScriptDictValue::~CScriptDictValue() -{ - if (m_valueObj && m_typeId) - { - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - FreeValue(ctx->GetEngine()); - else - { - // Must not hold an object when destroyed, as then the object will never be freed - assert((m_typeId & asTYPEID_MASK_OBJECT) == 0); - } - } -} - -void CScriptDictValue::FreeValue(asIScriptEngine *engine) -{ - // If it is a handle or a ref counted object, call release - if( m_typeId & asTYPEID_MASK_OBJECT ) - { - // Let the engine release the object - engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId)); - m_valueObj = 0; - m_typeId = 0; - } - - // For primitives, there's nothing to do -} - -void CScriptDictValue::EnumReferences(asIScriptEngine *inEngine) -{ - // If we're holding a reference, we'll notify the garbage collector of it - if (m_valueObj) - inEngine->GCEnumCallback(m_valueObj); - - // The object type itself is also garbage collected - if (m_typeId) - inEngine->GCEnumCallback(inEngine->GetTypeInfoById(m_typeId)); -} - -void CScriptDictValue::Set(asIScriptEngine *engine, void *value, int typeId) -{ - FreeValue(engine); - - m_typeId = typeId; - if( typeId & asTYPEID_OBJHANDLE ) - { - // We're receiving a reference to the handle, so we need to dereference it - m_valueObj = *(void**)value; - engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId)); - } - else if( typeId & asTYPEID_MASK_OBJECT ) - { - // Create a copy of the object - m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId)); - if( m_valueObj == 0 ) - { - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - ctx->SetException("Cannot create copy of object"); - } - } - else - { - // Copy the primitive value - // We receive a pointer to the value. - int size = engine->GetSizeOfPrimitiveType(typeId); - memcpy(&m_valueInt, value, size); - } -} - -void CScriptDictValue::Set(asIScriptEngine *engine, CScriptDictValue &value) -{ - if( value.m_typeId & asTYPEID_OBJHANDLE ) - Set(engine, (void*)&value.m_valueObj, value.m_typeId); - else if( value.m_typeId & asTYPEID_MASK_OBJECT ) - Set(engine, (void*)value.m_valueObj, value.m_typeId); - else - Set(engine, (void*)&value.m_valueInt, value.m_typeId); -} - -// This overloaded method is implemented so that all integer and -// unsigned integers types will be stored in the dictionary as int64 -// through implicit conversions. This simplifies the management of the -// numeric types when the script retrieves the stored value using a -// different type. -void CScriptDictValue::Set(asIScriptEngine *engine, const asINT64 &value) -{ - Set(engine, const_cast(&value), asTYPEID_INT64); -} - -// This overloaded method is implemented so that all floating point types -// will be stored in the dictionary as double through implicit conversions. -// This simplifies the management of the numeric types when the script -// retrieves the stored value using a different type. -void CScriptDictValue::Set(asIScriptEngine *engine, const double &value) -{ - Set(engine, const_cast(&value), asTYPEID_DOUBLE); -} - -bool CScriptDictValue::Get(asIScriptEngine *engine, void *value, int typeId) const -{ - // Return the value - if( typeId & asTYPEID_OBJHANDLE ) - { - // A handle can be retrieved if the stored type is a handle of same or compatible type - // or if the stored type is an object that implements the interface that the handle refer to. - if( (m_typeId & asTYPEID_MASK_OBJECT) ) - { - // Don't allow the get if the stored handle is to a const, but the desired handle is not - if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) ) - return false; - - // RefCastObject will increment the refcount if successful - engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast(value)); - - return true; - } - } - else if( typeId & asTYPEID_MASK_OBJECT ) - { - // Verify that the copy can be made - bool isCompatible = false; - - // Allow a handle to be value assigned if the wanted type is not a handle - if( (m_typeId & ~(asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST) ) == typeId && m_valueObj != 0 ) - isCompatible = true; - - // Copy the object into the given reference - if( isCompatible ) - { - engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId)); - - return true; - } - } - else - { - if( m_typeId == typeId ) - { - int size = engine->GetSizeOfPrimitiveType(typeId); - memcpy(value, &m_valueInt, size); - return true; - } - - // We know all numbers are stored as either int64 or double, since we register overloaded functions for those - // Only bool and enums needs to be treated separately - if( typeId == asTYPEID_DOUBLE ) - { - if( m_typeId == asTYPEID_INT64 ) - *(double*)value = double(m_valueInt); - else if (m_typeId == asTYPEID_BOOL) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - char localValue; - memcpy(&localValue, &m_valueInt, sizeof(char)); - *(double*)value = localValue ? 1.0 : 0.0; - } - else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - int localValue; - memcpy(&localValue, &m_valueInt, sizeof(int)); - *(double*)value = double(localValue); // enums are 32bit - } - else - { - // The stored type is an object - // TODO: Check if the object has a conversion operator to a primitive value - *(double*)value = 0; - return false; - } - return true; - } - else if( typeId == asTYPEID_INT64 ) - { - if( m_typeId == asTYPEID_DOUBLE ) - *(asINT64*)value = asINT64(m_valueFlt); - else if (m_typeId == asTYPEID_BOOL) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - char localValue; - memcpy(&localValue, &m_valueInt, sizeof(char)); - *(asINT64*)value = localValue ? 1 : 0; - } - else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - int localValue; - memcpy(&localValue, &m_valueInt, sizeof(int)); - *(asINT64*)value = localValue; // enums are 32bit - } - else - { - // The stored type is an object - // TODO: Check if the object has a conversion operator to a primitive value - *(asINT64*)value = 0; - return false; - } - return true; - } - else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 ) - { - // The desired type is an enum. These are always 32bit integers - if( m_typeId == asTYPEID_DOUBLE ) - *(int*)value = int(m_valueFlt); - else if( m_typeId == asTYPEID_INT64 ) - *(int*)value = int(m_valueInt); - else if (m_typeId == asTYPEID_BOOL) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - char localValue; - memcpy(&localValue, &m_valueInt, sizeof(char)); - *(int*)value = localValue ? 1 : 0; - } - else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) - { - // Use memcpy instead of type cast to make sure the code is endianess agnostic - int localValue; - memcpy(&localValue, &m_valueInt, sizeof(int)); - *(int*)value = localValue; // enums are 32bit - } - else - { - // The stored type is an object - // TODO: Check if the object has a conversion operator to a primitive value - *(int*)value = 0; - return false; - } - return true; - } - else if( typeId == asTYPEID_BOOL ) - { - if (m_typeId & asTYPEID_OBJHANDLE) - { - // TODO: Check if the object has a conversion operator to a primitive value - *(bool*)value = m_valueObj ? true : false; - } - else if( m_typeId & asTYPEID_MASK_OBJECT ) - { - // TODO: Check if the object has a conversion operator to a primitive value - *(bool*)value = true; - } - else - { - // Compare only the bytes that were actually set - asQWORD zero = 0; - int size = engine->GetSizeOfPrimitiveType(m_typeId); - *(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true; - } - return true; - } - } - - // It was not possible to retrieve the value using the desired typeId - return false; -} - -const void * CScriptDictValue::GetAddressOfValue() const -{ - if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) ) - { - // Return the address to the object directly - return m_valueObj; - } - - // Return the address of the primitive or the pointer to the object - return reinterpret_cast(&m_valueObj); -} - -bool CScriptDictValue::Get(asIScriptEngine *engine, asINT64 &value) const -{ - return Get(engine, &value, asTYPEID_INT64); -} - -bool CScriptDictValue::Get(asIScriptEngine *engine, double &value) const -{ - return Get(engine, &value, asTYPEID_DOUBLE); -} - -int CScriptDictValue::GetTypeId() const -{ - return m_typeId; -} - -static void CScriptDictValue_Construct(void *mem) -{ - new(mem) CScriptDictValue(); -} - -static void CScriptDictValue_Destruct(CScriptDictValue *obj) -{ - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->FreeValue(engine); - } - obj->~CScriptDictValue(); -} - -static CScriptDictValue &CScriptDictValue_opAssign(void *ref, int typeId, CScriptDictValue *obj) -{ - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->Set(engine, ref, typeId); - } - return *obj; -} - -static CScriptDictValue &CScriptDictValue_opAssign(const CScriptDictValue &other, CScriptDictValue *obj) -{ - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->Set(engine, const_cast(other)); - } - - return *obj; -} - -static CScriptDictValue &CScriptDictValue_opAssign(double val, CScriptDictValue *obj) -{ - return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj); -} - -static CScriptDictValue &CScriptDictValue_opAssign(asINT64 val, CScriptDictValue *obj) -{ - return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj); -} - -static void CScriptDictValue_opCast(void *ref, int typeId, CScriptDictValue *obj) -{ - asIScriptContext *ctx = asGetActiveContext(); - if( ctx ) - { - asIScriptEngine *engine = ctx->GetEngine(); - obj->Get(engine, ref, typeId); - } -} - -static asINT64 CScriptDictValue_opConvInt(CScriptDictValue *obj) -{ - asINT64 value; - CScriptDictValue_opCast(&value, asTYPEID_INT64, obj); - return value; -} - -static double CScriptDictValue_opConvDouble(CScriptDictValue *obj) -{ - double value; - CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj); - return value; -} - -//------------------------------------------------------------------- -// generic wrapper for CScriptDictValue - -static void CScriptDictValue_opConvDouble_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - double value; - self->Get(gen->GetEngine(), value); - *(double*)gen->GetAddressOfReturnLocation() = value; -} - -static void CScriptDictValue_opConvInt_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - asINT64 value; - self->Get(gen->GetEngine(), value); - *(asINT64*)gen->GetAddressOfReturnLocation() = value; -} - -static void CScriptDictValue_opCast_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0)); -} - -static void CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self); -} - -static void CScriptDictValue_opAssign_double_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self); -} - -static void CScriptDictValue_opAssign_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self); -} - -static void CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast(gen->GetArgAddress(0)), self); -} - -static void CScriptDictValue_Construct_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - CScriptDictValue_Construct(self); -} - -static void CScriptDictValue_Destruct_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - CScriptDictValue_Destruct(self); -} - -static void CScriptDictValue_EnumReferences_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - self->EnumReferences(gen->GetEngine()); -} - -static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen) -{ - CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); - self->FreeValue(gen->GetEngine()); -} - -//-------------------------------------------------------------------------- -// Register the type - -void RegisterScriptDictionary(asIScriptEngine *engine) -{ - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptDictionary_Generic(engine); - else - RegisterScriptDictionary_Native(engine); -} - -void RegisterScriptDictionary_Native(asIScriptEngine *engine) -{ - [[maybe_unused]] int r; - - // The array type must be available - assert( engine->GetTypeInfoByDecl("array") ); - -#if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); -#else - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); -#endif - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); - - // Register GC behaviours - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); - -#if AS_USE_STLNAMES == 1 - // Same as isEmpty - r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); - // Same as getSize - r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); - // Same as delete - r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); - // Same as deleteAll - r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); -#endif - - // Cache some things the dictionary will need at runtime - SDictionaryCache::Setup(engine); -} - -void RegisterScriptDictionary_Generic(asIScriptEngine *engine) -{ - [[maybe_unused]] int r; - - // Register the cleanup callback for the object type cache - engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); - -#if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); -#else - r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); -#endif - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); - - // Register GC behaviours - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); - - // Cache some things the dictionary will need at runtime - SDictionaryCache::Setup(engine); -} - -//------------------------------------------------------------------ -// Iterator implementation - -CScriptDictionary::CIterator CScriptDictionary::begin() const -{ - return CIterator(*this, dict.begin()); -} - -CScriptDictionary::CIterator CScriptDictionary::end() const -{ - return CIterator(*this, dict.end()); -} - -CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const -{ - return CIterator(*this, dict.find(key)); -} - -CScriptDictionary::CIterator::CIterator( - const CScriptDictionary &dict, - dictMap_t::const_iterator it) - : m_it(it), m_dict(dict) -{} - -void CScriptDictionary::CIterator::operator++() -{ - ++m_it; -} - -void CScriptDictionary::CIterator::operator++(int) -{ - ++m_it; - - // Normally the post increment would return a copy of the object with the original state, - // but it is rarely used so we skip this extra copy to avoid unnecessary overhead -} - -CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*() -{ - return *this; -} - -bool CScriptDictionary::CIterator::operator==(const CIterator &other) const -{ - return m_it == other.m_it; -} - -bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const -{ - return m_it != other.m_it; -} - -const dictKey_t &CScriptDictionary::CIterator::GetKey() const -{ - return m_it->first; -} - -int CScriptDictionary::CIterator::GetTypeId() const -{ - return m_it->second.m_typeId; -} - -bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const -{ - return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64); -} - -bool CScriptDictionary::CIterator::GetValue(double &value) const -{ - return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE); -} - -bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const -{ - return m_it->second.Get(m_dict.engine, value, typeId); -} - -const void *CScriptDictionary::CIterator::GetAddressOfValue() const -{ - return m_it->second.GetAddressOfValue(); -} - -END_AS_NAMESPACE - - diff --git a/extern/angelscript_addons/scriptdictionary/scriptdictionary.h b/extern/angelscript_addons/scriptdictionary/scriptdictionary.h deleted file mode 100644 index 062bb15..0000000 --- a/extern/angelscript_addons/scriptdictionary/scriptdictionary.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef SCRIPTDICTIONARY_H -#define SCRIPTDICTIONARY_H - -// The dictionary class relies on the script string object, thus the script -// string type must be registered with the engine before registering the -// dictionary type - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -// By default the CScriptDictionary use the std::string for the keys. -// If the application uses a custom string type, then this typedef -// can be changed accordingly. -#include -typedef std::string dictKey_t; - -// Forward declare CScriptDictValue so we can typedef the internal map type -BEGIN_AS_NAMESPACE -class CScriptDictValue; -END_AS_NAMESPACE - -// C++11 introduced the std::unordered_map which is a hash map which is -// is generally more performatic for lookups than the std::map which is a -// binary tree. -// TODO: memory: The map allocator should use the asAllocMem and asFreeMem -#if AS_CAN_USE_CPP11 -#include -typedef std::unordered_map dictMap_t; -#else -#include -typedef std::map dictMap_t; -#endif - - -#ifdef _MSC_VER -// Turn off annoying warnings about truncated symbol names -#pragma warning (disable:4786) -#endif - - - - -// Sometimes it may be desired to use the same method names as used by C++ STL. -// This may for example reduce time when converting code from script to C++ or -// back. -// -// 0 = off -// 1 = on - -#ifndef AS_USE_STLNAMES -#define AS_USE_STLNAMES 0 -#endif - - -BEGIN_AS_NAMESPACE - -class CScriptArray; -class CScriptDictionary; - -class CScriptDictValue -{ -public: - // This class must not be declared as local variable in C++, because it needs - // to receive the script engine pointer in all operations. The engine pointer - // is not kept as member in order to keep the size down - CScriptDictValue(); - CScriptDictValue(asIScriptEngine *engine, void *value, int typeId); - - // Destructor must not be called without first calling FreeValue, otherwise a memory leak will occur - ~CScriptDictValue(); - - // Replace the stored value - void Set(asIScriptEngine *engine, void *value, int typeId); - void Set(asIScriptEngine *engine, const asINT64 &value); - void Set(asIScriptEngine *engine, const double &value); - void Set(asIScriptEngine *engine, CScriptDictValue &value); - - // Gets the stored value. Returns false if the value isn't compatible with the informed typeId - bool Get(asIScriptEngine *engine, void *value, int typeId) const; - bool Get(asIScriptEngine *engine, asINT64 &value) const; - bool Get(asIScriptEngine *engine, double &value) const; - - // Returns the address of the stored value for inspection - const void *GetAddressOfValue() const; - - // Returns the type id of the stored value - int GetTypeId() const; - - // Free the stored value - void FreeValue(asIScriptEngine *engine); - - // GC callback - void EnumReferences(asIScriptEngine *engine); - -protected: - friend class CScriptDictionary; - - union - { - asINT64 m_valueInt; - double m_valueFlt; - void *m_valueObj; - }; - int m_typeId; -}; - -class CScriptDictionary -{ -public: - // Factory functions - static CScriptDictionary *Create(asIScriptEngine *engine); - - // Called from the script to instantiate a dictionary from an initialization list - static CScriptDictionary *Create(asBYTE *buffer); - - // Reference counting - void AddRef() const; - void Release() const; - - // Reassign the dictionary - CScriptDictionary &operator =(const CScriptDictionary &other); - - // Sets a key/value pair - void Set(const dictKey_t &key, void *value, int typeId); - void Set(const dictKey_t &key, const asINT64 &value); - void Set(const dictKey_t &key, const double &value); - - // Gets the stored value. Returns false if the value isn't compatible with the informed typeId - bool Get(const dictKey_t &key, void *value, int typeId) const; - bool Get(const dictKey_t &key, asINT64 &value) const; - bool Get(const dictKey_t &key, double &value) const; - - // Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist - // If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned - CScriptDictValue *operator[](const dictKey_t &key); - const CScriptDictValue *operator[](const dictKey_t &key) const; - - // Returns the type id of the stored value, or negative if it doesn't exist - int GetTypeId(const dictKey_t &key) const; - - // Returns true if the key is set - bool Exists(const dictKey_t &key) const; - - // Returns true if there are no key/value pairs in the dictionary - bool IsEmpty() const; - - // Returns the number of key/value pairs in the dictionary - asUINT GetSize() const; - - // Deletes the key - bool Delete(const dictKey_t &key); - - // Deletes all keys - void DeleteAll(); - - // Get an array of all keys - CScriptArray *GetKeys() const; - - // STL style iterator - class CIterator - { - public: - void operator++(); // Pre-increment - void operator++(int); // Post-increment - - // This is needed to support C++11 range-for - CIterator &operator*(); - - bool operator==(const CIterator &other) const; - bool operator!=(const CIterator &other) const; - - // Accessors - const dictKey_t &GetKey() const; - int GetTypeId() const; - bool GetValue(asINT64 &value) const; - bool GetValue(double &value) const; - bool GetValue(void *value, int typeId) const; - const void * GetAddressOfValue() const; - - protected: - friend class CScriptDictionary; - - CIterator(); - CIterator(const CScriptDictionary &dict, - dictMap_t::const_iterator it); - - CIterator &operator=(const CIterator &) {return *this;} // Not used - - dictMap_t::const_iterator m_it; - const CScriptDictionary &m_dict; - }; - - CIterator begin() const; - CIterator end() const; - CIterator find(const dictKey_t &key) const; - - // Garbage collections behaviours - int GetRefCount(); - void SetGCFlag(); - bool GetGCFlag(); - void EnumReferences(asIScriptEngine *engine); - void ReleaseAllReferences(asIScriptEngine *engine); - -protected: - // Since the dictionary uses the asAllocMem and asFreeMem functions to allocate memory - // the constructors are made protected so that the application cannot allocate it - // manually in a different way - CScriptDictionary(asIScriptEngine *engine); - CScriptDictionary(asBYTE *buffer); - - // We don't want anyone to call the destructor directly, it should be called through the Release method - virtual ~CScriptDictionary(); - - // Cache the object types needed - void Init(asIScriptEngine *engine); - - // Our properties - asIScriptEngine *engine; - mutable int refCount; - mutable bool gcFlag; - dictMap_t dict; -}; - -// This function will determine the configuration of the engine -// and use one of the two functions below to register the dictionary object -void RegisterScriptDictionary(asIScriptEngine *engine); - -// Call this function to register the math functions -// using native calling conventions -void RegisterScriptDictionary_Native(asIScriptEngine *engine); - -// Use this one instead if native calling conventions -// are not supported on the target platform -void RegisterScriptDictionary_Generic(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/extern/angelscript_addons/scripthandle/scripthandle.cpp b/extern/angelscript_addons/scripthandle/scripthandle.cpp deleted file mode 100644 index e47b1fe..0000000 --- a/extern/angelscript_addons/scripthandle/scripthandle.cpp +++ /dev/null @@ -1,360 +0,0 @@ -#include "scripthandle.h" -#include -#include -#include - -BEGIN_AS_NAMESPACE - -static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); } -static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); } -// This one is not static because it needs to be friend with the CScriptHandle class -void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); } -static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); } - -CScriptHandle::CScriptHandle() -{ - m_ref = 0; - m_type = 0; -} - -CScriptHandle::CScriptHandle(const CScriptHandle &other) -{ - m_ref = other.m_ref; - m_type = other.m_type; - - AddRefHandle(); -} - -CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type) -{ - m_ref = ref; - m_type = type; - - AddRefHandle(); -} - -// This constructor shouldn't be called from the application -// directly as it requires an active script context -CScriptHandle::CScriptHandle(void *ref, int typeId) -{ - m_ref = 0; - m_type = 0; - - Assign(ref, typeId); -} - -CScriptHandle::~CScriptHandle() -{ - ReleaseHandle(); -} - -void CScriptHandle::ReleaseHandle() -{ - if( m_ref && m_type ) - { - asIScriptEngine *engine = m_type->GetEngine(); - engine->ReleaseScriptObject(m_ref, m_type); - - engine->Release(); - - m_ref = 0; - m_type = 0; - } -} - -void CScriptHandle::AddRefHandle() -{ - if( m_ref && m_type ) - { - asIScriptEngine *engine = m_type->GetEngine(); - engine->AddRefScriptObject(m_ref, m_type); - - // Hold on to the engine so it isn't destroyed while - // a reference to a script object is still held - engine->AddRef(); - } -} - -CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other) -{ - Set(other.m_ref, other.m_type); - - return *this; -} - -void CScriptHandle::Set(void *ref, asITypeInfo *type) -{ - if( m_ref == ref ) return; - - ReleaseHandle(); - - m_ref = ref; - m_type = type; - - AddRefHandle(); -} - -void *CScriptHandle::GetRef() -{ - return m_ref; -} - -asITypeInfo *CScriptHandle::GetType() const -{ - return m_type; -} - -int CScriptHandle::GetTypeId() const -{ - if( m_type == 0 ) return 0; - - return m_type->GetTypeId() | asTYPEID_OBJHANDLE; -} - -// This method shouldn't be called from the application -// directly as it requires an active script context -CScriptHandle &CScriptHandle::Assign(void *ref, int typeId) -{ - // When receiving a null handle we just clear our memory - if( typeId == 0 ) - { - Set(0, 0); - return *this; - } - - // Dereference received handles to get the object - if( typeId & asTYPEID_OBJHANDLE ) - { - // Store the actual reference - ref = *(void**)ref; - typeId &= ~asTYPEID_OBJHANDLE; - } - - // Get the object type - asIScriptContext *ctx = asGetActiveContext(); - asIScriptEngine *engine = ctx->GetEngine(); - asITypeInfo *type = engine->GetTypeInfoById(typeId); - - // If the argument is another CScriptHandle, we should copy the content instead - if( type && strcmp(type->GetName(), "ref") == 0 ) - { - CScriptHandle *r = (CScriptHandle*)ref; - ref = r->m_ref; - type = r->m_type; - } - - Set(ref, type); - - return *this; -} - -bool CScriptHandle::operator==(const CScriptHandle &o) const -{ - if( m_ref == o.m_ref && - m_type == o.m_type ) - return true; - - // TODO: If type is not the same, we should attempt to do a dynamic cast, - // which may change the pointer for application registered classes - - return false; -} - -bool CScriptHandle::operator!=(const CScriptHandle &o) const -{ - return !(*this == o); -} - -bool CScriptHandle::Equals(void *ref, int typeId) const -{ - // Null handles are received as reference to a null handle - if( typeId == 0 ) - ref = 0; - - // Dereference handles to get the object - if( typeId & asTYPEID_OBJHANDLE ) - { - // Compare the actual reference - ref = *(void**)ref; - typeId &= ~asTYPEID_OBJHANDLE; - } - - // TODO: If typeId is not the same, we should attempt to do a dynamic cast, - // which may change the pointer for application registered classes - - if( ref == m_ref ) return true; - - return false; -} - -// AngelScript: used as '@obj = cast(ref);' -void CScriptHandle::Cast(void **outRef, int typeId) -{ - // If we hold a null handle, then just return null - if( m_type == 0 ) - { - *outRef = 0; - return; - } - - // It is expected that the outRef is always a handle - assert( typeId & asTYPEID_OBJHANDLE ); - - // Compare the type id of the actual object - typeId &= ~asTYPEID_OBJHANDLE; - asIScriptEngine *engine = m_type->GetEngine(); - asITypeInfo *type = engine->GetTypeInfoById(typeId); - - *outRef = 0; - - // RefCastObject will increment the refCount of the returned object if successful - engine->RefCastObject(m_ref, m_type, type, outRef); -} - -void CScriptHandle::EnumReferences(asIScriptEngine *inEngine) -{ - // If we're holding a reference, we'll notify the garbage collector of it - if (m_ref) - inEngine->GCEnumCallback(m_ref); - - // The object type itself is also garbage collected - if( m_type) - inEngine->GCEnumCallback(m_type); -} - -void CScriptHandle::ReleaseReferences(asIScriptEngine *) -{ - // Simply clear the content to release the references - Set(0, 0); -} - -void RegisterScriptHandle_Native(asIScriptEngine *engine) -{ - [[maybe_unused]] int r; - -#if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); -#else - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); -#endif - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0); - r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 ); -} - -void CScriptHandle_Construct_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - new(self) CScriptHandle(); -} - -void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - new(self) CScriptHandle(*other); -} - -void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen) -{ - void *ref = gen->GetArgAddress(0); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - Construct(self, ref, typeId); -} - -void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->~CScriptHandle(); -} - -void CScriptHandle_Cast_Generic(asIScriptGeneric *gen) -{ - void **ref = reinterpret_cast(gen->GetArgAddress(0)); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->Cast(ref, typeId); -} - -void CScriptHandle_Assign_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - *self = *other; - gen->SetReturnAddress(self); -} - -void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen) -{ - void *ref = gen->GetArgAddress(0); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->Assign(ref, typeId); - gen->SetReturnAddress(self); -} - -void CScriptHandle_Equals_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnByte(*self == *other); -} - -void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen) -{ - void *ref = gen->GetArgAddress(0); - int typeId = gen->GetArgTypeId(0); - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - gen->SetReturnByte(self->Equals(ref, typeId)); -} - -void CScriptHandle_EnumReferences_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->EnumReferences(gen->GetEngine()); -} - -void CScriptHandle_ReleaseReferences_Generic(asIScriptGeneric *gen) -{ - CScriptHandle *self = reinterpret_cast(gen->GetObject()); - self->ReleaseReferences(gen->GetEngine()); -} - -void RegisterScriptHandle_Generic(asIScriptEngine *engine) -{ - [[maybe_unused]] int r; - - r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 ); -} - -void RegisterScriptHandle(asIScriptEngine *engine) -{ - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - RegisterScriptHandle_Generic(engine); - else - RegisterScriptHandle_Native(engine); -} - - -END_AS_NAMESPACE diff --git a/extern/angelscript_addons/scripthandle/scripthandle.h b/extern/angelscript_addons/scripthandle/scripthandle.h deleted file mode 100644 index 7adf1b7..0000000 --- a/extern/angelscript_addons/scripthandle/scripthandle.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SCRIPTHANDLE_H -#define SCRIPTHANDLE_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - - -BEGIN_AS_NAMESPACE - -class CScriptHandle -{ -public: - // Constructors - CScriptHandle(); - CScriptHandle(const CScriptHandle &other); - CScriptHandle(void *ref, asITypeInfo *type); - ~CScriptHandle(); - - // Copy the stored value from another any object - CScriptHandle &operator=(const CScriptHandle &other); - - // Set the reference - void Set(void *ref, asITypeInfo *type); - - // Compare equalness - bool operator==(const CScriptHandle &o) const; - bool operator!=(const CScriptHandle &o) const; - bool Equals(void *ref, int typeId) const; - - // Dynamic cast to desired handle type - void Cast(void **outRef, int typeId); - - // Returns the type of the reference held - asITypeInfo *GetType() const; - int GetTypeId() const; - - // Get the reference - void *GetRef(); - - // GC callback - void EnumReferences(asIScriptEngine *engine); - void ReleaseReferences(asIScriptEngine *engine); - -protected: - // These functions need to have access to protected - // members in order to call them from the script engine - friend void Construct(CScriptHandle *self, void *ref, int typeId); - friend void RegisterScriptHandle_Native(asIScriptEngine *engine); - friend void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen); - - void ReleaseHandle(); - void AddRefHandle(); - - // These shouldn't be called directly by the - // application as they requires an active context - CScriptHandle(void *ref, int typeId); - CScriptHandle &Assign(void *ref, int typeId); - - void *m_ref; - asITypeInfo *m_type; -}; - -void RegisterScriptHandle(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/extern/angelscript_addons/scripthelper/scripthelper.cpp b/extern/angelscript_addons/scripthelper/scripthelper.cpp deleted file mode 100644 index bb85b65..0000000 --- a/extern/angelscript_addons/scripthelper/scripthelper.cpp +++ /dev/null @@ -1,987 +0,0 @@ -#include -#include "scripthelper.h" -#include -#include -#include -#include -#include - -using namespace std; - -BEGIN_AS_NAMESPACE - -int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result) -{ - // TODO: If a lot of script objects are going to be compared, e.g. when sorting an array, - // then the method id and context should be cached between calls. - - int retval = -1; - asIScriptFunction *func = 0; - - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if( ti ) - { - // Check if the object type has a compatible opCmp method - for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) - { - asIScriptFunction *f = ti->GetMethodByIndex(n); - asDWORD flags; - if( strcmp(f->GetName(), "opCmp") == 0 && - f->GetReturnTypeId(&flags) == asTYPEID_INT32 && - flags == asTM_NONE && - f->GetParamCount() == 1 ) - { - int paramTypeId; - f->GetParam(0, ¶mTypeId, &flags); - - // The parameter must be an input reference of the same type - // If the reference is a inout reference, then it must also be read-only - if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) - break; - - // Found the method - func = f; - break; - } - } - } - - if( func ) - { - // Call the method - asIScriptContext *ctx = engine->CreateContext(); - ctx->Prepare(func); - ctx->SetObject(lobj); - ctx->SetArgAddress(0, robj); - int r = ctx->Execute(); - if( r == asEXECUTION_FINISHED ) - { - result = (int)ctx->GetReturnDWord(); - - // The comparison was successful - retval = 0; - } - ctx->Release(); - } - - return retval; -} - -int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result) -{ - // TODO: If a lot of script objects are going to be compared, e.g. when searching for an - // entry in a set, then the method and context should be cached between calls. - - int retval = -1; - asIScriptFunction *func = 0; - - asITypeInfo *ti = engine->GetTypeInfoById(typeId); - if( ti ) - { - // Check if the object type has a compatible opEquals method - for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) - { - asIScriptFunction *f = ti->GetMethodByIndex(n); - asDWORD flags; - if( strcmp(f->GetName(), "opEquals") == 0 && - f->GetReturnTypeId(&flags) == asTYPEID_BOOL && - flags == asTM_NONE && - f->GetParamCount() == 1 ) - { - int paramTypeId; - f->GetParam(0, ¶mTypeId, &flags); - - // The parameter must be an input reference of the same type - // If the reference is a inout reference, then it must also be read-only - if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) - break; - - // Found the method - func = f; - break; - } - } - } - - if( func ) - { - // Call the method - asIScriptContext *ctx = engine->CreateContext(); - ctx->Prepare(func); - ctx->SetObject(lobj); - ctx->SetArgAddress(0, robj); - int r = ctx->Execute(); - if( r == asEXECUTION_FINISHED ) - { - result = ctx->GetReturnByte() ? true : false; - - // The comparison was successful - retval = 0; - } - ctx->Release(); - } - else - { - // If the opEquals method doesn't exist, then we try with opCmp instead - int relation; - retval = CompareRelation(engine, lobj, robj, typeId, relation); - if( retval >= 0 ) - result = relation == 0 ? true : false; - } - - return retval; -} - -int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod, asIScriptContext *ctx) -{ - return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx); -} - -int ExecuteString(asIScriptEngine *engine, const char *code, void *ref, int refTypeId, asIScriptModule *mod, asIScriptContext *ctx) -{ - // Wrap the code in a function so that it can be compiled and executed - string funcCode = " ExecuteString() {\n"; - funcCode += code; - funcCode += "\n;}"; - - // Determine the return type based on the type of the ref arg - funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode; - - // GetModule will free unused types, so to be on the safe side we'll hold on to a reference to the type - asITypeInfo *type = 0; - if( refTypeId & asTYPEID_MASK_OBJECT ) - { - type = engine->GetTypeInfoById(refTypeId); - if( type ) - type->AddRef(); - } - - // If no module was provided, get a dummy from the engine - asIScriptModule *execMod = mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE); - - // Now it's ok to release the type - if( type ) - type->Release(); - - // Compile the function that can be executed - asIScriptFunction *func = 0; - int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0, &func); - if( r < 0 ) - return r; - - // If no context was provided, request a new one from the engine - asIScriptContext *execCtx = ctx ? ctx : engine->RequestContext(); - r = execCtx->Prepare(func); - if (r >= 0) - { - // Execute the function - r = execCtx->Execute(); - - // Unless the provided type was void retrieve it's value - if (ref != 0 && refTypeId != asTYPEID_VOID) - { - if (refTypeId & asTYPEID_OBJHANDLE) - { - // Expect the pointer to be null to start with - assert(*reinterpret_cast(ref) == 0); - *reinterpret_cast(ref) = *reinterpret_cast(execCtx->GetAddressOfReturnValue()); - engine->AddRefScriptObject(*reinterpret_cast(ref), engine->GetTypeInfoById(refTypeId)); - } - else if (refTypeId & asTYPEID_MASK_OBJECT) - { - // Use the registered assignment operator to do a value assign. - // This assumes that the ref is pointing to a valid object instance. - engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetTypeInfoById(refTypeId)); - } - else - { - // Copy the primitive value - memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId)); - } - } - } - - // Clean up - func->Release(); - if( !ctx ) engine->ReturnContext(execCtx); - - return r; -} - -int WriteConfigToFile(asIScriptEngine *engine, const char *filename) -{ - ofstream strm; - strm.open(filename); - - return WriteConfigToStream(engine, strm); -} - -int WriteConfigToStream(asIScriptEngine *engine, ostream &strm) -{ - // A helper function for escaping quotes in default arguments - struct Escape - { - static string Quotes(const char *decl) - { - string str = decl; - size_t pos = 0; - for(;;) - { - // Find " characters - pos = str.find("\"",pos); - if( pos == string::npos ) - break; - - // Add a \ to escape them - str.insert(pos, "\\"); - pos += 2; - } - - return str; - } - }; - - int c, n; - - asDWORD currAccessMask = 0; - string currNamespace = ""; - engine->SetDefaultNamespace(""); - - // Export the engine version, just for info - strm << "// AngelScript " << asGetLibraryVersion() << "\n"; - strm << "// Lib options " << asGetLibraryOptions() << "\n"; - - // Export the relevant engine properties - strm << "// Engine properties\n"; - for( n = 0; n < asEP_LAST_PROPERTY; n++ ) - strm << "ep " << n << " " << engine->GetEngineProperty(asEEngineProp(n)) << "\n"; - - // Make sure the default array type is expanded to the template form - bool expandDefArrayToTempl = engine->GetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL) ? true : false; - engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true); - - // Write enum types and their values - strm << "\n// Enums\n"; - c = engine->GetEnumCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *ti = engine->GetEnumByIndex(n); - asDWORD accessMask = ti->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - const char *nameSpace = ti->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - const char *enumName = ti->GetName(); - strm << "enum " << enumName << "\n"; - for( asUINT m = 0; m < ti->GetEnumValueCount(); m++ ) - { - const char *valName; - int val; - valName = ti->GetEnumValueByIndex(m, &val); - strm << "enumval " << enumName << " " << valName << " " << val << "\n"; - } - } - - // Enumerate all types - strm << "\n// Types\n"; - - // Keep a list of the template types, as the methods for these need to be exported first - set templateTypes; - - c = engine->GetObjectTypeCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *type = engine->GetObjectTypeByIndex(n); - asDWORD accessMask = type->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - const char *nameSpace = type->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) - { - // This should only be interfaces - assert( type->GetSize() == 0 ); - - strm << "intf " << type->GetName() << "\n"; - } - else - { - // Only the type flags are necessary. The application flags are application - // specific and doesn't matter to the offline compiler. The object size is also - // unnecessary for the offline compiler - strm << "objtype \"" << engine->GetTypeDeclaration(type->GetTypeId()) << "\" " << (unsigned int)(type->GetFlags() & asOBJ_MASK_VALID_FLAGS) << "\n"; - - // Store the template types (but not template instances) - if( (type->GetFlags() & asOBJ_TEMPLATE) && type->GetSubType() && (type->GetSubType()->GetFlags() & asOBJ_TEMPLATE_SUBTYPE) ) - templateTypes.insert(type); - } - } - - c = engine->GetTypedefCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *ti = engine->GetTypedefByIndex(n); - const char *nameSpace = ti->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - asDWORD accessMask = ti->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "typedef " << ti->GetName() << " \"" << engine->GetTypeDeclaration(ti->GetTypedefTypeId()) << "\"\n"; - } - - c = engine->GetFuncdefCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *funcDef = engine->GetFuncdefByIndex(n); - asDWORD accessMask = funcDef->GetAccessMask(); - const char *nameSpace = funcDef->GetNamespace(); - // Child funcdefs do not have any namespace, as they belong to the parent object - if( nameSpace && nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "funcdef \"" << funcDef->GetFuncdefSignature()->GetDeclaration() << "\"\n"; - } - - // A helper for writing object type members - struct TypeWriter - { - static void Write(asIScriptEngine *engine, ostream &strm, asITypeInfo *type, string &currNamespace, asDWORD &currAccessMask) - { - const char *nameSpace = type->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - string typeDecl = engine->GetTypeDeclaration(type->GetTypeId()); - if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) - { - for( asUINT m = 0; m < type->GetMethodCount(); m++ ) - { - asIScriptFunction *func = type->GetMethodByIndex(m); - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "intfmthd " << typeDecl.c_str() << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; - } - } - else - { - asUINT m; - for( m = 0; m < type->GetFactoryCount(); m++ ) - { - asIScriptFunction *func = type->GetFactoryByIndex(m); - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "objbeh \"" << typeDecl.c_str() << "\" " << asBEHAVE_FACTORY << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - } - for( m = 0; m < type->GetBehaviourCount(); m++ ) - { - asEBehaviours beh; - asIScriptFunction *func = type->GetBehaviourByIndex(m, &beh); - - if( beh == asBEHAVE_CONSTRUCT ) - // Prefix 'void' - strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - else if( beh == asBEHAVE_DESTRUCT ) - // Prefix 'void' and remove ~ - strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str()+1 << "\"\n"; - else - strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; - } - for( m = 0; m < type->GetMethodCount(); m++ ) - { - asIScriptFunction *func = type->GetMethodByIndex(m); - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "objmthd \"" << typeDecl.c_str() << "\" \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; - } - for( m = 0; m < type->GetPropertyCount(); m++ ) - { - asDWORD accessMask; - type->GetProperty(m, 0, 0, 0, 0, 0, 0, &accessMask); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "objprop \"" << typeDecl.c_str() << "\" \"" << type->GetPropertyDeclaration(m) << "\""; - - // Save information about composite properties - int compositeOffset; - bool isCompositeIndirect; - type->GetProperty(m, 0, 0, 0, 0, 0, 0, 0, &compositeOffset, &isCompositeIndirect); - strm << " " << compositeOffset << " " << (isCompositeIndirect ? "1" : "0") << "\n"; - } - } - } - }; - - // Write the members of the template types, so they can be fully registered before any other type uses them - // TODO: Order the template types based on dependency to avoid failure if one type uses instances of another - strm << "\n// Template type members\n"; - for( set::iterator it = templateTypes.begin(); it != templateTypes.end(); ++it ) - { - asITypeInfo *type = *it; - TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); - } - - // Write the object types members - strm << "\n// Type members\n"; - - c = engine->GetObjectTypeCount(); - for( n = 0; n < c; n++ ) - { - asITypeInfo *type = engine->GetObjectTypeByIndex(n); - if( templateTypes.find(type) == templateTypes.end() ) - TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); - } - - // Write functions - strm << "\n// Functions\n"; - - c = engine->GetGlobalFunctionCount(); - for( n = 0; n < c; n++ ) - { - asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n); - const char *nameSpace = func->GetNamespace(); - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - asDWORD accessMask = func->GetAccessMask(); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - strm << "func \"" << Escape::Quotes(func->GetDeclaration()).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; - } - - // Write global properties - strm << "\n// Properties\n"; - - c = engine->GetGlobalPropertyCount(); - for( n = 0; n < c; n++ ) - { - const char *name; - int typeId; - bool isConst; - asDWORD accessMask; - const char *nameSpace; - engine->GetGlobalPropertyByIndex(n, &name, &nameSpace, &typeId, &isConst, 0, 0, &accessMask); - if( accessMask != currAccessMask ) - { - strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; - currAccessMask = accessMask; - } - if( nameSpace != currNamespace ) - { - strm << "namespace \"" << nameSpace << "\"\n"; - currNamespace = nameSpace; - engine->SetDefaultNamespace(currNamespace.c_str()); - } - strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n"; - } - - // Write string factory - strm << "\n// String factory\n"; - - // Reset the namespace for the string factory and default array type - if ("" != currNamespace) - { - strm << "namespace \"\"\n"; - currNamespace = ""; - engine->SetDefaultNamespace(""); - } - - asDWORD flags = 0; - int typeId = engine->GetStringFactoryReturnTypeId(&flags); - if( typeId > 0 ) - strm << "strfactory \"" << ((flags & asTM_CONST) ? "const " : "") << engine->GetTypeDeclaration(typeId) << ((flags & asTM_INOUTREF) ? "&" : "") << "\"\n"; - - // Write default array type - strm << "\n// Default array type\n"; - typeId = engine->GetDefaultArrayTypeId(); - if( typeId > 0 ) - strm << "defarray \"" << engine->GetTypeDeclaration(typeId) << "\"\n"; - - // Restore original settings - engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, expandDefArrayToTempl); - - return 0; -} - -int ConfigEngineFromStream(asIScriptEngine *engine, istream &strm, const char *configFile, asIStringFactory *stringFactory) -{ - int r; - - // Some helper functions for parsing the configuration - struct in - { - static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos) - { - asUINT len = 0; - asETokenClass t = engine->ParseToken(&text[pos], text.length() - pos, &len); - while( (t == asTC_WHITESPACE || t == asTC_COMMENT) && pos < text.length() ) - { - pos += len; - t = engine->ParseToken(&text[pos], text.length() - pos, &len); - } - - token.assign(&text[pos], len); - - pos += len; - - return t; - } - - static void ReplaceSlashQuote(string &str) - { - size_t pos = 0; - for(;;) - { - // Search for \" in the string - pos = str.find("\\\"", pos); - if( pos == string::npos ) - break; - - // Remove the \ character - str.erase(pos, 1); - } - } - - static asUINT GetLineNumber(const string &text, asUINT pos) - { - asUINT count = 1; - for( asUINT n = 0; n < pos; n++ ) - if( text[n] == '\n' ) - count++; - - return count; - } - }; - - // Since we are only going to compile the script and never actually execute it, - // we turn off the initialization of global variables, so that the compiler can - // just register dummy types and functions for the application interface. - r = engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false); assert( r >= 0 ); - - // Read the entire file - char buffer[1000]; - string config; - do { - strm.getline(buffer, 1000); - config += buffer; - config += "\n"; - } while( !strm.eof() && strm.good() ); - - // Process the configuration file and register each entity - asUINT pos = 0; - while( pos < config.length() ) - { - string token; - // TODO: The position where the initial token is found should be stored for error messages - in::GetToken(engine, token, config, pos); - if( token == "ep" ) - { - string tmp; - in::GetToken(engine, tmp, config, pos); - - asEEngineProp ep = asEEngineProp(atol(tmp.c_str())); - - // Only set properties that affect the compiler - if( ep != asEP_COPY_SCRIPT_SECTIONS && - ep != asEP_MAX_STACK_SIZE && - ep != asEP_INIT_GLOBAL_VARS_AFTER_BUILD && - ep != asEP_EXPAND_DEF_ARRAY_TO_TMPL && - ep != asEP_AUTO_GARBAGE_COLLECT ) - { - // Get the value for the property - in::GetToken(engine, tmp, config, pos); - stringstream s(tmp); - asPWORD value; - - s >> value; - - engine->SetEngineProperty(ep, value); - } - } - else if( token == "namespace" ) - { - string ns; - in::GetToken(engine, ns, config, pos); - ns = ns.substr(1, ns.length() - 2); - - r = engine->SetDefaultNamespace(ns.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to set namespace"); - return -1; - } - } - else if( token == "access" ) - { - string maskStr; - in::GetToken(engine, maskStr, config, pos); - asDWORD mask = strtoul(maskStr.c_str(), 0, 16); - engine->SetDefaultAccessMask(mask); - } - else if( token == "objtype" ) - { - string name, flags; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, flags, config, pos); - - // The size of the value type doesn't matter, because the - // engine must adjust it anyway for different platforms - r = engine->RegisterObjectType(name.c_str(), (atol(flags.c_str()) & asOBJ_VALUE) ? 1 : 0, atol(flags.c_str())); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object type"); - return -1; - } - } - else if( token == "objbeh" ) - { - string name, behaviour, decl; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, behaviour, config, pos); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - // Remove the $ that the engine prefixes the behaviours with - size_t n = decl.find("$"); - if( n != string::npos ) - decl[n] = ' '; - - asEBehaviours behave = static_cast(atol(behaviour.c_str())); - if( behave == asBEHAVE_TEMPLATE_CALLBACK ) - { - // TODO: How can we let the compiler register this? Maybe through a plug-in system? Or maybe by implementing the callback as a script itself - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register template callback without the actual implementation"); - } - else - { - r = engine->RegisterObjectBehaviour(name.c_str(), behave, decl.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register behaviour"); - return -1; - } - } - } - else if( token == "objmthd" ) - { - string name, decl; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - r = engine->RegisterObjectMethod(name.c_str(), decl.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object method"); - return -1; - } - } - else if( token == "objprop" ) - { - string name, decl, compositeOffset, isCompositeIndirect; - in::GetToken(engine, name, config, pos); - name = name.substr(1, name.length() - 2); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::GetToken(engine, compositeOffset, config, pos); - in::GetToken(engine, isCompositeIndirect, config, pos); - - asITypeInfo *type = engine->GetTypeInfoById(engine->GetTypeIdByDecl(name.c_str())); - if( type == 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Type doesn't exist for property registration"); - return -1; - } - - // All properties must have different offsets in order to make them - // distinct, so we simply register them with an incremental offset - r = engine->RegisterObjectProperty(name.c_str(), decl.c_str(), type->GetPropertyCount(), compositeOffset != "0" ? type->GetPropertyCount() : 0, isCompositeIndirect != "0"); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object property"); - return -1; - } - } - else if( token == "intf" ) - { - string name, size, flags; - in::GetToken(engine, name, config, pos); - - r = engine->RegisterInterface(name.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface"); - return -1; - } - } - else if( token == "intfmthd" ) - { - string name, decl; - in::GetToken(engine, name, config, pos); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - r = engine->RegisterInterfaceMethod(name.c_str(), decl.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface method"); - return -1; - } - } - else if( token == "func" ) - { - string decl; - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - in::ReplaceSlashQuote(decl); - - r = engine->RegisterGlobalFunction(decl.c_str(), asFUNCTION(0), asCALL_GENERIC); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global function"); - return -1; - } - } - else if( token == "prop" ) - { - string decl; - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - // All properties must have different offsets in order to make them - // distinct, so we simply register them with an incremental offset. - // The pointer must also be non-null so we add 1 to have a value. - r = engine->RegisterGlobalProperty(decl.c_str(), reinterpret_cast(asPWORD(engine->GetGlobalPropertyCount()+1))); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global property"); - return -1; - } - } - else if( token == "strfactory" ) - { - string type; - in::GetToken(engine, type, config, pos); - type = type.substr(1, type.length() - 2); - - if (stringFactory == 0) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register string factory without the actual implementation"); - return -1; - } - else - { - r = engine->RegisterStringFactory(type.c_str(), stringFactory); - if (r < 0) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register string factory"); - return -1; - } - } - } - else if( token == "defarray" ) - { - string type; - in::GetToken(engine, type, config, pos); - type = type.substr(1, type.length() - 2); - - r = engine->RegisterDefaultArrayType(type.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register the default array type"); - return -1; - } - } - else if( token == "enum" ) - { - string type; - in::GetToken(engine, type, config, pos); - - r = engine->RegisterEnum(type.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum type"); - return -1; - } - } - else if( token == "enumval" ) - { - string type, name, value; - in::GetToken(engine, type, config, pos); - in::GetToken(engine, name, config, pos); - in::GetToken(engine, value, config, pos); - - r = engine->RegisterEnumValue(type.c_str(), name.c_str(), atol(value.c_str())); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum value"); - return -1; - } - } - else if( token == "typedef" ) - { - string type, decl; - in::GetToken(engine, type, config, pos); - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - r = engine->RegisterTypedef(type.c_str(), decl.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register typedef"); - return -1; - } - } - else if( token == "funcdef" ) - { - string decl; - in::GetToken(engine, decl, config, pos); - decl = decl.substr(1, decl.length() - 2); - - r = engine->RegisterFuncdef(decl.c_str()); - if( r < 0 ) - { - engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register funcdef"); - return -1; - } - } - } - - return 0; -} - -string GetExceptionInfo(asIScriptContext *ctx, bool showStack) -{ - if( ctx->GetState() != asEXECUTION_EXCEPTION ) return ""; - - stringstream text; - - const asIScriptFunction *function = ctx->GetExceptionFunction(); - text << "func: " << function->GetDeclaration() << "\n"; - text << "modl: " << (function->GetModuleName() ? function->GetModuleName() : "") << "\n"; - text << "sect: " << (function->GetScriptSectionName() ? function->GetScriptSectionName() : "") << "\n"; - text << "line: " << ctx->GetExceptionLineNumber() << "\n"; - text << "desc: " << ctx->GetExceptionString() << "\n"; - - if( showStack ) - { - text << "--- call stack ---\n"; - for( asUINT n = 1; n < ctx->GetCallstackSize(); n++ ) - { - function = ctx->GetFunction(n); - if( function ) - { - if( function->GetFuncType() == asFUNC_SCRIPT ) - { - text << (function->GetScriptSectionName() ? function->GetScriptSectionName() : "") << " (" << ctx->GetLineNumber(n) << "): " << function->GetDeclaration() << "\n"; - } - else - { - // The context is being reused by the application for a nested call - text << "{...application...}: " << function->GetDeclaration() << "\n"; - } - } - else - { - // The context is being reused by the script engine for a nested call - text << "{...script engine...}\n"; - } - } - } - - return text.str(); -} - -void ScriptThrow(const string &msg) -{ - asIScriptContext *ctx = asGetActiveContext(); - if (ctx) - ctx->SetException(msg.c_str()); -} - -string ScriptGetExceptionInfo() -{ - asIScriptContext *ctx = asGetActiveContext(); - if (!ctx) - return ""; - - const char *msg = ctx->GetExceptionString(); - if (msg == 0) - return ""; - - return string(msg); -} - -void RegisterExceptionRoutines(asIScriptEngine *engine) -{ - [[maybe_unused]] int r; - - // The string type must be available - assert(engine->GetTypeInfoByDecl("string")); - - r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); -} - -END_AS_NAMESPACE diff --git a/extern/angelscript_addons/scripthelper/scripthelper.h b/extern/angelscript_addons/scripthelper/scripthelper.h deleted file mode 100644 index dc3e0b8..0000000 --- a/extern/angelscript_addons/scripthelper/scripthelper.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef SCRIPTHELPER_H -#define SCRIPTHELPER_H - -#include -#include - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - - -BEGIN_AS_NAMESPACE - -// Compare relation between two objects of the same type -int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result); - -// Compare equality between two objects of the same type -int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result); - -// Compile and execute simple statements -// The module is optional. If given the statements can access the entities compiled in the module. -// The caller can optionally provide its own context, for example if a context should be reused. -int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); - -// Compile and execute simple statements with option of return value -// The module is optional. If given the statements can access the entitites compiled in the module. -// The caller can optionally provide its own context, for example if a context should be reused. -int ExecuteString(asIScriptEngine *engine, const char *code, void *ret, int retTypeId, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); - -// Write the registered application interface to a file for an offline compiler. -// The format is compatible with the offline compiler in /sdk/samples/asbuild/. -int WriteConfigToFile(asIScriptEngine *engine, const char *filename); - -// Write the registered application interface to a text stream. -int WriteConfigToStream(asIScriptEngine *engine, std::ostream &strm); - -// Loads an interface from a text stream and configures the engine with it. This will not -// set the correct function pointers, so it is not possible to use this engine to execute -// scripts, but it can be used to compile scripts and save the byte code. -int ConfigEngineFromStream(asIScriptEngine *engine, std::istream &strm, const char *nameOfStream = "config", asIStringFactory *stringFactory = 0); - -// Format the details of the script exception into a human readable text -std::string GetExceptionInfo(asIScriptContext *ctx, bool showStack = false); - -// Register the exception routines -// 'void throw(const string &msg)' -// 'string getExceptionInfo()' -void RegisterExceptionRoutines(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/extern/angelscript_addons/scriptstdstring/scriptstdstring.cpp b/extern/angelscript_addons/scriptstdstring/scriptstdstring.cpp deleted file mode 100644 index 2a96ad4..0000000 --- a/extern/angelscript_addons/scriptstdstring/scriptstdstring.cpp +++ /dev/null @@ -1,1365 +0,0 @@ -#include "scriptstdstring.h" -#include // assert() -#include // std::stringstream -#include // strstr() -#include // sprintf() -#include // strtod() -#ifndef __psp2__ - #include // setlocale() -#endif - -using namespace std; - -// This macro is used to avoid warnings about unused variables. -// Usually where the variables are only used in debug mode. -#define UNUSED_VAR(x) (void)(x) - -#ifdef AS_CAN_USE_CPP11 -// The string factory doesn't need to keep a specific order in the -// cache, so the unordered_map is faster than the ordinary map -#include // std::unordered_map -BEGIN_AS_NAMESPACE -typedef unordered_map map_t; -END_AS_NAMESPACE -#else -#include // std::map -BEGIN_AS_NAMESPACE -typedef map map_t; -END_AS_NAMESPACE -#endif - -BEGIN_AS_NAMESPACE -class CStdStringFactory : public asIStringFactory -{ -public: - CStdStringFactory() {} - ~CStdStringFactory() - { - // The script engine must release each string - // constant that it has requested - assert(stringCache.size() == 0); - } - - const void *GetStringConstant(const char *data, asUINT length) - { - // The string factory might be modified from multiple - // threads, so it is necessary to use a mutex. - asAcquireExclusiveLock(); - - string str(data, length); - map_t::iterator it = stringCache.find(str); - if (it != stringCache.end()) - it->second++; - else - it = stringCache.insert(map_t::value_type(str, 1)).first; - - asReleaseExclusiveLock(); - - return reinterpret_cast(&it->first); - } - - int ReleaseStringConstant(const void *str) - { - if (str == 0) - return asERROR; - - int ret = asSUCCESS; - - // The string factory might be modified from multiple - // threads, so it is necessary to use a mutex. - asAcquireExclusiveLock(); - - map_t::iterator it = stringCache.find(*reinterpret_cast(str)); - if (it == stringCache.end()) - ret = asERROR; - else - { - it->second--; - if (it->second == 0) - stringCache.erase(it); - } - - asReleaseExclusiveLock(); - - return ret; - } - - int GetRawStringData(const void *str, char *data, asUINT *length) const - { - if (str == 0) - return asERROR; - - if (length) - *length = (asUINT)reinterpret_cast(str)->length(); - - if (data) - memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); - - return asSUCCESS; - } - - // THe access to the string cache is protected with the common mutex provided by AngelScript - map_t stringCache; -}; - -static CStdStringFactory *stringFactory = 0; - -// TODO: Make this public so the application can also use the string -// factory and share the string constants if so desired, or to -// monitor the size of the string factory cache. -CStdStringFactory *GetStdStringFactorySingleton() -{ - if( stringFactory == 0 ) - { - // The following instance will be destroyed by the global - // CStdStringFactoryCleaner instance upon application shutdown - stringFactory = new CStdStringFactory(); - } - return stringFactory; -} - -class CStdStringFactoryCleaner -{ -public: - ~CStdStringFactoryCleaner() - { - if (stringFactory) - { - // Only delete the string factory if the stringCache is empty - // If it is not empty, it means that someone might still attempt - // to release string constants, so if we delete the string factory - // the application might crash. Not deleting the cache would - // lead to a memory leak, but since this is only happens when the - // application is shutting down anyway, it is not important. - if (stringFactory->stringCache.empty()) - { - delete stringFactory; - stringFactory = 0; - } - } - } -}; - -static CStdStringFactoryCleaner cleaner; - - -static void ConstructString(string *thisPointer) -{ - new(thisPointer) string(); -} - -static void CopyConstructString(const string &other, string *thisPointer) -{ - new(thisPointer) string(other); -} - -static void DestructString(string *thisPointer) -{ - thisPointer->~string(); -} - -static string &AddAssignStringToString(const string &str, string &dest) -{ - // We don't register the method directly because some compilers - // and standard libraries inline the definition, resulting in the - // linker being unable to find the declaration. - // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 - dest += str; - return dest; -} - -// bool string::isEmpty() -// bool string::empty() // if AS_USE_STLNAMES == 1 -static bool StringIsEmpty(const string &str) -{ - // We don't register the method directly because some compilers - // and standard libraries inline the definition, resulting in the - // linker being unable to find the declaration - // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 - return str.empty(); -} - -static string &AssignUInt64ToString(asQWORD i, string &dest) -{ - ostringstream stream; - stream << i; - dest = stream.str(); - return dest; -} - -static string &AddAssignUInt64ToString(asQWORD i, string &dest) -{ - ostringstream stream; - stream << i; - dest += stream.str(); - return dest; -} - -static string AddStringUInt64(const string &str, asQWORD i) -{ - ostringstream stream; - stream << i; - return str + stream.str(); -} - -static string AddInt64String(asINT64 i, const string &str) -{ - ostringstream stream; - stream << i; - return stream.str() + str; -} - -static string &AssignInt64ToString(asINT64 i, string &dest) -{ - ostringstream stream; - stream << i; - dest = stream.str(); - return dest; -} - -static string &AddAssignInt64ToString(asINT64 i, string &dest) -{ - ostringstream stream; - stream << i; - dest += stream.str(); - return dest; -} - -static string AddStringInt64(const string &str, asINT64 i) -{ - ostringstream stream; - stream << i; - return str + stream.str(); -} - -static string AddUInt64String(asQWORD i, const string &str) -{ - ostringstream stream; - stream << i; - return stream.str() + str; -} - -static string &AssignDoubleToString(double f, string &dest) -{ - ostringstream stream; - stream << f; - dest = stream.str(); - return dest; -} - -static string &AddAssignDoubleToString(double f, string &dest) -{ - ostringstream stream; - stream << f; - dest += stream.str(); - return dest; -} - -static string &AssignFloatToString(float f, string &dest) -{ - ostringstream stream; - stream << f; - dest = stream.str(); - return dest; -} - -static string &AddAssignFloatToString(float f, string &dest) -{ - ostringstream stream; - stream << f; - dest += stream.str(); - return dest; -} - -static string &AssignBoolToString(bool b, string &dest) -{ - ostringstream stream; - stream << (b ? "true" : "false"); - dest = stream.str(); - return dest; -} - -static string &AddAssignBoolToString(bool b, string &dest) -{ - ostringstream stream; - stream << (b ? "true" : "false"); - dest += stream.str(); - return dest; -} - -static string AddStringDouble(const string &str, double f) -{ - ostringstream stream; - stream << f; - return str + stream.str(); -} - -static string AddDoubleString(double f, const string &str) -{ - ostringstream stream; - stream << f; - return stream.str() + str; -} - -static string AddStringFloat(const string &str, float f) -{ - ostringstream stream; - stream << f; - return str + stream.str(); -} - -static string AddFloatString(float f, const string &str) -{ - ostringstream stream; - stream << f; - return stream.str() + str; -} - -static string AddStringBool(const string &str, bool b) -{ - ostringstream stream; - stream << (b ? "true" : "false"); - return str + stream.str(); -} - -static string AddBoolString(bool b, const string &str) -{ - ostringstream stream; - stream << (b ? "true" : "false"); - return stream.str() + str; -} - -static char *StringCharAt(unsigned int i, string &str) -{ - if( i >= str.size() ) - { - // Set a script exception - asIScriptContext *ctx = asGetActiveContext(); - ctx->SetException("Out of range"); - - // Return a null pointer - return 0; - } - - return &str[i]; -} - -// AngelScript signature: -// int string::opCmp(const string &in) const -static int StringCmp(const string &a, const string &b) -{ - int cmp = 0; - if( a < b ) cmp = -1; - else if( a > b ) cmp = 1; - return cmp; -} - -// This function returns the index of the first position where the substring -// exists in the input string. If the substring doesn't exist in the input -// string -1 is returned. -// -// AngelScript signature: -// int string::findFirst(const string &in sub, uint start = 0) const -static int StringFindFirst(const string &sub, asUINT start, const string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start)); -} - -// This function returns the index of the first position where the one of the bytes in substring -// exists in the input string. If the characters in the substring doesn't exist in the input -// string -1 is returned. -// -// AngelScript signature: -// int string::findFirstOf(const string &in sub, uint start = 0) const -static int StringFindFirstOf(const string &sub, asUINT start, const string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_first_of(sub, (size_t)(start < 0 ? string::npos : start)); -} - -// This function returns the index of the last position where the one of the bytes in substring -// exists in the input string. If the characters in the substring doesn't exist in the input -// string -1 is returned. -// -// AngelScript signature: -// int string::findLastOf(const string &in sub, uint start = -1) const -static int StringFindLastOf(const string &sub, asUINT start, const string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); -} - -// This function returns the index of the first position where a byte other than those in substring -// exists in the input string. If none is found -1 is returned. -// -// AngelScript signature: -// int string::findFirstNotOf(const string &in sub, uint start = 0) const -static int StringFindFirstNotOf(const string &sub, asUINT start, const string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_first_not_of(sub, (size_t)(start < 0 ? string::npos : start)); -} - -// This function returns the index of the last position where a byte other than those in substring -// exists in the input string. If none is found -1 is returned. -// -// AngelScript signature: -// int string::findLastNotOf(const string &in sub, uint start = -1) const -static int StringFindLastNotOf(const string &sub, asUINT start, const string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.find_last_not_of(sub, (size_t)(start < 0 ? string::npos : start)); -} - -// This function returns the index of the last position where the substring -// exists in the input string. If the substring doesn't exist in the input -// string -1 is returned. -// -// AngelScript signature: -// int string::findLast(const string &in sub, int start = -1) const -static int StringFindLast(const string &sub, int start, const string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - return (int)str.rfind(sub, (size_t)(start < 0 ? string::npos : start)); -} - -// AngelScript signature: -// void string::insert(uint pos, const string &in other) -static void StringInsert(unsigned int pos, const string &other, string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - str.insert(pos, other); -} - -// AngelScript signature: -// void string::erase(uint pos, int count = -1) -static void StringErase(unsigned int pos, int count, string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - str.erase(pos, (size_t)(count < 0 ? string::npos : count)); -} - - -// AngelScript signature: -// uint string::length() const -static asUINT StringLength(const string &str) -{ - // We don't register the method directly because the return type changes between 32bit and 64bit platforms - return (asUINT)str.length(); -} - - -// AngelScript signature: -// void string::resize(uint l) -static void StringResize(asUINT l, string &str) -{ - // We don't register the method directly because the argument types change between 32bit and 64bit platforms - str.resize(l); -} - -// AngelScript signature: -// string formatInt(int64 val, const string &in options, uint width) -static string formatInt(asINT64 value, const string &options, asUINT width) -{ - bool leftJustify = options.find("l") != string::npos; - bool padWithZero = options.find("0") != string::npos; - bool alwaysSign = options.find("+") != string::npos; - bool spaceOnSign = options.find(" ") != string::npos; - bool hexSmall = options.find("h") != string::npos; - bool hexLarge = options.find("H") != string::npos; - - string fmt = "%"; - if( leftJustify ) fmt += "-"; - if( alwaysSign ) fmt += "+"; - if( spaceOnSign ) fmt += " "; - if( padWithZero ) fmt += "0"; - -#ifdef _WIN32 - fmt += "*I64"; -#else -#ifdef _LP64 - fmt += "*l"; -#else - fmt += "*ll"; -#endif -#endif - - if( hexSmall ) fmt += "x"; - else if( hexLarge ) fmt += "X"; - else fmt += "d"; - - string buf; - buf.resize(width+30); -#if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 or newer - sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); -#else - sprintf(&buf[0], fmt.c_str(), width, value); -#endif - buf.resize(strlen(&buf[0])); - - return buf; -} - -// AngelScript signature: -// string formatUInt(uint64 val, const string &in options, uint width) -static string formatUInt(asQWORD value, const string &options, asUINT width) -{ - bool leftJustify = options.find("l") != string::npos; - bool padWithZero = options.find("0") != string::npos; - bool alwaysSign = options.find("+") != string::npos; - bool spaceOnSign = options.find(" ") != string::npos; - bool hexSmall = options.find("h") != string::npos; - bool hexLarge = options.find("H") != string::npos; - - string fmt = "%"; - if( leftJustify ) fmt += "-"; - if( alwaysSign ) fmt += "+"; - if( spaceOnSign ) fmt += " "; - if( padWithZero ) fmt += "0"; - -#ifdef _WIN32 - fmt += "*I64"; -#else -#ifdef _LP64 - fmt += "*l"; -#else - fmt += "*ll"; -#endif -#endif - - if( hexSmall ) fmt += "x"; - else if( hexLarge ) fmt += "X"; - else fmt += "u"; - - string buf; - buf.resize(width+30); -#if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 or newer - sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); -#else - sprintf(&buf[0], fmt.c_str(), width, value); -#endif - buf.resize(strlen(&buf[0])); - - return buf; -} - -// AngelScript signature: -// string formatFloat(double val, const string &in options, uint width, uint precision) -static string formatFloat(double value, const string &options, asUINT width, asUINT precision) -{ - bool leftJustify = options.find("l") != string::npos; - bool padWithZero = options.find("0") != string::npos; - bool alwaysSign = options.find("+") != string::npos; - bool spaceOnSign = options.find(" ") != string::npos; - bool expSmall = options.find("e") != string::npos; - bool expLarge = options.find("E") != string::npos; - - string fmt = "%"; - if( leftJustify ) fmt += "-"; - if( alwaysSign ) fmt += "+"; - if( spaceOnSign ) fmt += " "; - if( padWithZero ) fmt += "0"; - - fmt += "*.*"; - - if( expSmall ) fmt += "e"; - else if( expLarge ) fmt += "E"; - else fmt += "f"; - - string buf; - buf.resize(width+precision+50); -#if _MSC_VER >= 1400 && !defined(__S3E__) - // MSVC 8.0 / 2005 or newer - sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, precision, value); -#else - sprintf(&buf[0], fmt.c_str(), width, precision, value); -#endif - buf.resize(strlen(&buf[0])); - - return buf; -} - -// AngelScript signature: -// int64 parseInt(const string &in val, uint base = 10, uint &out byteCount = 0) -static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount) -{ - // Only accept base 10 and 16 - if( base != 10 && base != 16 ) - { - if( byteCount ) *byteCount = 0; - return 0; - } - - const char *end = &val[0]; - - // Determine the sign - bool sign = false; - if( *end == '-' ) - { - sign = true; - end++; - } - else if( *end == '+' ) - end++; - - asINT64 res = 0; - if( base == 10 ) - { - while( *end >= '0' && *end <= '9' ) - { - res *= 10; - res += *end++ - '0'; - } - } - else if( base == 16 ) - { - while( (*end >= '0' && *end <= '9') || - (*end >= 'a' && *end <= 'f') || - (*end >= 'A' && *end <= 'F') ) - { - res *= 16; - if( *end >= '0' && *end <= '9' ) - res += *end++ - '0'; - else if( *end >= 'a' && *end <= 'f' ) - res += *end++ - 'a' + 10; - else if( *end >= 'A' && *end <= 'F' ) - res += *end++ - 'A' + 10; - } - } - - if( byteCount ) - *byteCount = asUINT(size_t(end - val.c_str())); - - if( sign ) - res = -res; - - return res; -} - -// AngelScript signature: -// uint64 parseUInt(const string &in val, uint base = 10, uint &out byteCount = 0) -static asQWORD parseUInt(const string &val, asUINT base, asUINT *byteCount) -{ - // Only accept base 10 and 16 - if (base != 10 && base != 16) - { - if (byteCount) *byteCount = 0; - return 0; - } - - const char *end = &val[0]; - - asQWORD res = 0; - if (base == 10) - { - while (*end >= '0' && *end <= '9') - { - res *= 10; - res += *end++ - '0'; - } - } - else if (base == 16) - { - while ((*end >= '0' && *end <= '9') || - (*end >= 'a' && *end <= 'f') || - (*end >= 'A' && *end <= 'F')) - { - res *= 16; - if (*end >= '0' && *end <= '9') - res += *end++ - '0'; - else if (*end >= 'a' && *end <= 'f') - res += *end++ - 'a' + 10; - else if (*end >= 'A' && *end <= 'F') - res += *end++ - 'A' + 10; - } - } - - if (byteCount) - *byteCount = asUINT(size_t(end - val.c_str())); - - return res; -} - -// AngelScript signature: -// double parseFloat(const string &in val, uint &out byteCount = 0) -double parseFloat(const string &val, asUINT *byteCount) -{ - char *end; - - // WinCE doesn't have setlocale. Some quick testing on my current platform - // still manages to parse the numbers such as "3.14" even if the decimal for the - // locale is ",". -#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) - // Set the locale to C so that we are guaranteed to parse the float value correctly - char *tmp = setlocale(LC_NUMERIC, 0); - string orig = tmp ? tmp : "C"; - setlocale(LC_NUMERIC, "C"); -#endif - - double res = strtod(val.c_str(), &end); - -#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) - // Restore the locale - setlocale(LC_NUMERIC, orig.c_str()); -#endif - - if( byteCount ) - *byteCount = asUINT(size_t(end - val.c_str())); - - return res; -} - -// This function returns a string containing the substring of the input string -// determined by the starting index and count of characters. -// -// AngelScript signature: -// string string::substr(uint start = 0, int count = -1) const -static string StringSubString(asUINT start, int count, const string &str) -{ - // Check for out-of-bounds - string ret; - if( start < str.length() && count != 0 ) - ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); - - return ret; -} - -// String equality comparison. -// Returns true iff lhs is equal to rhs. -// -// For some reason gcc 4.7 has difficulties resolving the -// asFUNCTIONPR(operator==, (const string &, const string &) -// makro, so this wrapper was introduced as work around. -static bool StringEquals(const std::string& lhs, const std::string& rhs) -{ - return lhs == rhs; -} - -void RegisterStdString_Native(asIScriptEngine *engine) -{ - int r = 0; - UNUSED_VAR(r); - - // Register the string type -#if AS_CAN_USE_CPP11 - // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags to use - r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asGetTypeTraits()); assert( r >= 0 ); -#else - r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); -#endif - - r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); - - // Register the object operator overloads - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asMETHODPR(string, operator =, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); - // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails - r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); -// r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); - - // Need to use a wrapper for operator== otherwise gcc 4.7 fails to compile - r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTIONPR(StringEquals, (const string &, const string &), bool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTIONPR(operator +, (const string &, const string &), string), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - - // The string length can be accessed through methods or through virtual property - // TODO: Register as size() for consistency with other types -#if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); -#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - // Don't register these if STL names is used, as they conflict with the method size() - r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); -#endif - // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails -// r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asMETHOD(string, empty), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Register the index operator, both as a mutator and as an inspector - // Note that we don't register the operator[] directly, as it doesn't do bounds checking - r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Automatic conversion from values - r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddStringFloat), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloatString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddStringBool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBoolString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - - // Utilities - r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0); - - - r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt), asCALL_CDECL); assert(r >= 0); - r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat), asCALL_CDECL); assert(r >= 0); - -#if AS_USE_STLNAMES == 1 - // Same as length - r = engine->RegisterObjectMethod("string", "uint size() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - // Same as isEmpty - r = engine->RegisterObjectMethod("string", "bool empty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - // Same as findFirst - r = engine->RegisterObjectMethod("string", "int find(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); - // Same as findLast - r = engine->RegisterObjectMethod("string", "int rfind(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); -#endif - - // TODO: Implement the following - // findAndReplace - replaces a text found in the string - // replaceRange - replaces a range of bytes in the string - // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" -} - -static void ConstructStringGeneric(asIScriptGeneric * gen) -{ - new (gen->GetObject()) string(); -} - -static void CopyConstructStringGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetArgObject(0)); - new (gen->GetObject()) string(*a); -} - -static void DestructStringGeneric(asIScriptGeneric * gen) -{ - string * ptr = static_cast(gen->GetObject()); - ptr->~string(); -} - -static void AssignStringGeneric(asIScriptGeneric *gen) -{ - string * a = static_cast(gen->GetArgObject(0)); - string * self = static_cast(gen->GetObject()); - *self = *a; - gen->SetReturnAddress(self); -} - -static void AddAssignStringGeneric(asIScriptGeneric *gen) -{ - string * a = static_cast(gen->GetArgObject(0)); - string * self = static_cast(gen->GetObject()); - *self += *a; - gen->SetReturnAddress(self); -} - -static void StringEqualsGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); -} - -static void StringCmpGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - - int cmp = 0; - if( *a < *b ) cmp = -1; - else if( *a > *b ) cmp = 1; - - *(int*)gen->GetAddressOfReturnLocation() = cmp; -} - -static void StringAddGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - string * b = static_cast(gen->GetArgAddress(0)); - string ret_val = *a + *b; - gen->SetReturnObject(&ret_val); -} - -static void StringLengthGeneric(asIScriptGeneric * gen) -{ - string * self = static_cast(gen->GetObject()); - *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); -} - -static void StringIsEmptyGeneric(asIScriptGeneric * gen) -{ - string * self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); -} - -static void StringResizeGeneric(asIScriptGeneric * gen) -{ - string * self = static_cast(gen->GetObject()); - self->resize(*static_cast(gen->GetAddressOfArg(0))); -} - -static void StringInsert_Generic(asIScriptGeneric *gen) -{ - string * self = static_cast(gen->GetObject()); - asUINT pos = gen->GetArgDWord(0); - string *other = reinterpret_cast(gen->GetArgAddress(1)); - StringInsert(pos, *other, *self); -} - -static void StringErase_Generic(asIScriptGeneric *gen) -{ - string * self = static_cast(gen->GetObject()); - asUINT pos = gen->GetArgDWord(0); - int count = int(gen->GetArgDWord(1)); - StringErase(pos, count, *self); -} - -static void StringFindFirst_Generic(asIScriptGeneric * gen) -{ - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirst(*find, start, *self); -} - -static void StringFindLast_Generic(asIScriptGeneric * gen) -{ - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLast(*find, start, *self); -} - -static void StringFindFirstOf_Generic(asIScriptGeneric * gen) -{ - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstOf(*find, start, *self); -} - -static void StringFindLastOf_Generic(asIScriptGeneric * gen) -{ - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastOf(*find, start, *self); -} - -static void StringFindFirstNotOf_Generic(asIScriptGeneric * gen) -{ - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstNotOf(*find, start, *self); -} - -static void StringFindLastNotOf_Generic(asIScriptGeneric * gen) -{ - string *find = reinterpret_cast(gen->GetArgAddress(0)); - asUINT start = gen->GetArgDWord(1); - string *self = reinterpret_cast(gen->GetObject()); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastNotOf(*find, start, *self); -} - -static void formatInt_Generic(asIScriptGeneric * gen) -{ - asINT64 val = gen->GetArgQWord(0); - string *options = reinterpret_cast(gen->GetArgAddress(1)); - asUINT width = gen->GetArgDWord(2); - new(gen->GetAddressOfReturnLocation()) string(formatInt(val, *options, width)); -} - -static void formatUInt_Generic(asIScriptGeneric * gen) -{ - asQWORD val = gen->GetArgQWord(0); - string *options = reinterpret_cast(gen->GetArgAddress(1)); - asUINT width = gen->GetArgDWord(2); - new(gen->GetAddressOfReturnLocation()) string(formatUInt(val, *options, width)); -} - -static void formatFloat_Generic(asIScriptGeneric *gen) -{ - double val = gen->GetArgDouble(0); - string *options = reinterpret_cast(gen->GetArgAddress(1)); - asUINT width = gen->GetArgDWord(2); - asUINT precision = gen->GetArgDWord(3); - new(gen->GetAddressOfReturnLocation()) string(formatFloat(val, *options, width, precision)); -} - -static void parseInt_Generic(asIScriptGeneric *gen) -{ - string *str = reinterpret_cast(gen->GetArgAddress(0)); - asUINT base = gen->GetArgDWord(1); - asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); - gen->SetReturnQWord(parseInt(*str,base,byteCount)); -} - -static void parseUInt_Generic(asIScriptGeneric *gen) -{ - string *str = reinterpret_cast(gen->GetArgAddress(0)); - asUINT base = gen->GetArgDWord(1); - asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); - gen->SetReturnQWord(parseUInt(*str, base, byteCount)); -} - -static void parseFloat_Generic(asIScriptGeneric *gen) -{ - string *str = reinterpret_cast(gen->GetArgAddress(0)); - asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(1)); - gen->SetReturnDouble(parseFloat(*str,byteCount)); -} - -static void StringCharAtGeneric(asIScriptGeneric * gen) -{ - unsigned int index = gen->GetArgDWord(0); - string * self = static_cast(gen->GetObject()); - - if (index >= self->size()) - { - // Set a script exception - asIScriptContext *ctx = asGetActiveContext(); - ctx->SetException("Out of range"); - - gen->SetReturnAddress(0); - } - else - { - gen->SetReturnAddress(&(self->operator [](index))); - } -} - -static void AssignInt2StringGeneric(asIScriptGeneric *gen) -{ - asINT64 *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); -} - -static void AssignUInt2StringGeneric(asIScriptGeneric *gen) -{ - asQWORD *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); -} - -static void AssignDouble2StringGeneric(asIScriptGeneric *gen) -{ - double *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); -} - -static void AssignFloat2StringGeneric(asIScriptGeneric *gen) -{ - float *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self = sstr.str(); - gen->SetReturnAddress(self); -} - -static void AssignBool2StringGeneric(asIScriptGeneric *gen) -{ - bool *a = static_cast(gen->GetAddressOfArg(0)); - string *self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false"); - *self = sstr.str(); - gen->SetReturnAddress(self); -} - -static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) -{ - double * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); -} - -static void AddAssignFloat2StringGeneric(asIScriptGeneric * gen) -{ - float * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); -} - -static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) -{ - asINT64 * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); -} - -static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) -{ - asQWORD * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a; - *self += sstr.str(); - gen->SetReturnAddress(self); -} - -static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) -{ - bool * a = static_cast(gen->GetAddressOfArg(0)); - string * self = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false"); - *self += sstr.str(); - gen->SetReturnAddress(self); -} - -static void AddString2DoubleGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - double * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddString2FloatGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - float * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddString2IntGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - asINT64 * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddString2UIntGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - asQWORD * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddString2BoolGeneric(asIScriptGeneric * gen) -{ - string * a = static_cast(gen->GetObject()); - bool * b = static_cast(gen->GetAddressOfArg(0)); - std::stringstream sstr; - sstr << *a << (*b ? "true" : "false"); - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddDouble2StringGeneric(asIScriptGeneric * gen) -{ - double* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddFloat2StringGeneric(asIScriptGeneric * gen) -{ - float* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddInt2StringGeneric(asIScriptGeneric * gen) -{ - asINT64* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddUInt2StringGeneric(asIScriptGeneric * gen) -{ - asQWORD* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << *a << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void AddBool2StringGeneric(asIScriptGeneric * gen) -{ - bool* a = static_cast(gen->GetAddressOfArg(0)); - string * b = static_cast(gen->GetObject()); - std::stringstream sstr; - sstr << (*a ? "true" : "false") << *b; - std::string ret_val = sstr.str(); - gen->SetReturnObject(&ret_val); -} - -static void StringSubString_Generic(asIScriptGeneric *gen) -{ - // Get the arguments - string *str = (string*)gen->GetObject(); - asUINT start = *(int*)gen->GetAddressOfArg(0); - int count = *(int*)gen->GetAddressOfArg(1); - - // Return the substring - new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); -} - -void RegisterStdString_Generic(asIScriptEngine *engine) -{ - int r = 0; - UNUSED_VAR(r); - - // Register the string type - r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); - - r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); - - // Register the object operator overloads - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asFUNCTION(AssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEqualsGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmpGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTION(StringAddGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Register the object methods -#if AS_USE_ACCESSORS != 1 - r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); -#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 - r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); -#endif - r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmptyGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Register the index operator, both as a mutator and as an inspector - r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Automatic conversion from values - r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddString2FloatGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); - - r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0); - - - r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat_Generic), asCALL_GENERIC); assert(r >= 0); -} - -void RegisterStdString(asIScriptEngine * engine) -{ - if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) - RegisterStdString_Generic(engine); - else - RegisterStdString_Native(engine); -} - -END_AS_NAMESPACE - - - - diff --git a/extern/angelscript_addons/scriptstdstring/scriptstdstring.h b/extern/angelscript_addons/scriptstdstring/scriptstdstring.h deleted file mode 100644 index 0960beb..0000000 --- a/extern/angelscript_addons/scriptstdstring/scriptstdstring.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Script std::string -// -// This function registers the std::string type with AngelScript to be used as the default string type. -// -// The string type is registered as a value type, thus may have performance issues if a lot of -// string operations are performed in the script. However, for relatively few operations, this should -// not cause any problem for most applications. -// - -#ifndef SCRIPTSTDSTRING_H -#define SCRIPTSTDSTRING_H - -#ifndef ANGELSCRIPT_H -// Avoid having to inform include path if header is already include before -#include -#endif - -#include - -//--------------------------- -// Compilation settings -// - -// Sometimes it may be desired to use the same method names as used by C++ STL. -// This may for example reduce time when converting code from script to C++ or -// back. -// -// 0 = off -// 1 = on -#ifndef AS_USE_STLNAMES -#define AS_USE_STLNAMES 0 -#endif - -// Some prefer to use property accessors to get/set the length of the string -// This option registers the accessors instead of the method length() -#ifndef AS_USE_ACCESSORS -#define AS_USE_ACCESSORS 0 -#endif - -BEGIN_AS_NAMESPACE - -void RegisterStdString(asIScriptEngine *engine); -void RegisterStdStringUtils(asIScriptEngine *engine); - -END_AS_NAMESPACE - -#endif diff --git a/extern/angelscript_addons/scriptstdstring/scriptstdstring_utils.cpp b/extern/angelscript_addons/scriptstdstring/scriptstdstring_utils.cpp deleted file mode 100644 index 7b8067f..0000000 --- a/extern/angelscript_addons/scriptstdstring/scriptstdstring_utils.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include -#include "scriptstdstring.h" -#include "../scriptarray/scriptarray.h" -#include -#include - -using namespace std; - -BEGIN_AS_NAMESPACE - -// This function takes an input string and splits it into parts by looking -// for a specified delimiter. Example: -// -// string str = "A|B||D"; -// array@ array = str.split("|"); -// -// The resulting array has the following elements: -// -// {"A", "B", "", "D"} -// -// AngelScript signature: -// array@ string::split(const string &in delim) const -static CScriptArray *StringSplit(const string &delim, const string &str) -{ - // Obtain a pointer to the engine - asIScriptContext *ctx = asGetActiveContext(); - asIScriptEngine *engine = ctx->GetEngine(); - - // TODO: This should only be done once - // TODO: This assumes that CScriptArray was already registered - asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); - - // Create the array object - CScriptArray *array = CScriptArray::Create(arrayType); - - // Find the existence of the delimiter in the input string - int pos = 0, prev = 0, count = 0; - while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) - { - // Add the part to the array - array->Resize(array->GetSize()+1); - ((string*)array->At(count))->assign(&str[prev], pos-prev); - - // Find the next part - count++; - prev = pos + (int)delim.length(); - } - - // Add the remaining part - array->Resize(array->GetSize()+1); - ((string*)array->At(count))->assign(&str[prev]); - - return array; -} - -static void StringSplit_Generic(asIScriptGeneric *gen) -{ - // Get the arguments - string *str = (string*)gen->GetObject(); - string *delim = *(string**)gen->GetAddressOfArg(0); - - // Return the array by handle - *(CScriptArray**)gen->GetAddressOfReturnLocation() = StringSplit(*delim, *str); -} - - - -// This function takes as input an array of string handles as well as a -// delimiter and concatenates the array elements into one delimited string. -// Example: -// -// array array = {"A", "B", "", "D"}; -// string str = join(array, "|"); -// -// The resulting string is: -// -// "A|B||D" -// -// AngelScript signature: -// string join(const array &in array, const string &in delim) -static string StringJoin(const CScriptArray &array, const string &delim) -{ - // Create the new string - string str = ""; - if( array.GetSize() ) - { - int n; - for( n = 0; n < (int)array.GetSize() - 1; n++ ) - { - str += *(string*)array.At(n); - str += delim; - } - - // Add the last part - str += *(string*)array.At(n); - } - - return str; -} - -static void StringJoin_Generic(asIScriptGeneric *gen) -{ - // Get the arguments - CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0); - string *delim = *(string**)gen->GetAddressOfArg(1); - - // Return the string - new(gen->GetAddressOfReturnLocation()) string(StringJoin(*array, *delim)); -} - -// This is where the utility functions are registered. -// The string type must have been registered first. -void RegisterStdStringUtils(asIScriptEngine *engine) -{ - [[maybe_unused]] int r; - - if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) - { - r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); - r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); - } - else - { - r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); - r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); - } -} - -END_AS_NAMESPACE diff --git a/extern/doctest.hpp b/extern/doctest.hpp deleted file mode 100644 index d3b5601..0000000 --- a/extern/doctest.hpp +++ /dev/null @@ -1,5965 +0,0 @@ -// ====================================================================== lgtm [cpp/missing-header-guard] -// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == -// ====================================================================== -// -// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD -// -// Copyright (c) 2016-2019 Viktor Kirilov -// -// Distributed under the MIT Software License -// See accompanying file LICENSE.txt or copy at -// https://opensource.org/licenses/MIT -// -// The documentation can be found at the library's page: -// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md -// -// ================================================================================================= -// ================================================================================================= -// ================================================================================================= -// -// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2 -// which uses the Boost Software License - Version 1.0 -// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt -// -// The concept of subcases (sections in Catch) and expression decomposition are from there. -// Some parts of the code are taken directly: -// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> -// - the Approx() helper class for floating point comparison -// - colors in the console -// - breaking into a debugger -// - signal / SEH handling -// - timer -// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste) -// -// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest -// which uses the Boost Software License - Version 1.0 -// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt -// -// ================================================================================================= -// ================================================================================================= -// ================================================================================================= - -#ifndef DOCTEST_LIBRARY_INCLUDED -#define DOCTEST_LIBRARY_INCLUDED - -// ================================================================================================= -// == VERSION ====================================================================================== -// ================================================================================================= - -#define DOCTEST_VERSION_MAJOR 2 -#define DOCTEST_VERSION_MINOR 4 -#define DOCTEST_VERSION_PATCH 0 -#define DOCTEST_VERSION_STR "2.4.0" - -#define DOCTEST_VERSION (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) - -// ================================================================================================= -// == COMPILER VERSION ============================================================================= -// ================================================================================================= - -// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect - -#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH)) - -// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... -#if defined(_MSC_VER) && defined(_MSC_FULL_VER) -#if _MSC_VER == _MSC_FULL_VER / 10000 -#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) -#else // MSVC -#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) -#endif // MSVC -#endif // MSVC -#if defined(__clang__) && defined(__clang_minor__) -#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) -#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__INTEL_COMPILER) -#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#endif // GCC - -#ifndef DOCTEST_MSVC -#define DOCTEST_MSVC 0 -#endif // DOCTEST_MSVC -#ifndef DOCTEST_CLANG -#define DOCTEST_CLANG 0 -#endif // DOCTEST_CLANG -#ifndef DOCTEST_GCC -#define DOCTEST_GCC 0 -#endif // DOCTEST_GCC - -// ================================================================================================= -// == COMPILER WARNINGS HELPERS ==================================================================== -// ================================================================================================= - -#if DOCTEST_CLANG -#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) -#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") -#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) -#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") -#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ - DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) -#else // DOCTEST_CLANG -#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -#define DOCTEST_CLANG_SUPPRESS_WARNING(w) -#define DOCTEST_CLANG_SUPPRESS_WARNING_POP -#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // DOCTEST_CLANG - -#if DOCTEST_GCC -#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") -#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) -#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") -#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) -#else // DOCTEST_GCC -#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH -#define DOCTEST_GCC_SUPPRESS_WARNING(w) -#define DOCTEST_GCC_SUPPRESS_WARNING_POP -#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // DOCTEST_GCC - -#if DOCTEST_MSVC -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) -#else // DOCTEST_MSVC -#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -#define DOCTEST_MSVC_SUPPRESS_WARNING(w) -#define DOCTEST_MSVC_SUPPRESS_WARNING_POP -#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) -#endif // DOCTEST_MSVC - -// ================================================================================================= -// == COMPILER WARNINGS ============================================================================ -// ================================================================================================= - -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") - -DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") -DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") -DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") -DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") - -DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration -DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression -DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated -DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant -DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding -DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe -// static analysis -DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' -DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable -DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... -DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtr... -DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' - -// 4548 - expression before comma has no effect; expected expression with side - effect -// 4265 - class has virtual functions, but destructor is not virtual -// 4986 - exception specification does not match previous declaration -// 4350 - behavior change: 'member1' called instead of 'member2' -// 4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' -// 4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch -// 4774 - format string expected in argument 'x' is not a string literal -// 4820 - padding in structs - -// only 4 should be disabled globally: -// - 4514 # unreferenced inline function has been removed -// - 4571 # SEH related -// - 4710 # function not inlined -// - 4711 # function 'x' selected for automatic inline expansion - -#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ - DOCTEST_MSVC_SUPPRESS_WARNING(4548) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4265) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4986) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4350) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4668) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4365) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4774) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4820) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4625) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4626) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5027) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5026) \ - DOCTEST_MSVC_SUPPRESS_WARNING(4623) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5039) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5045) \ - DOCTEST_MSVC_SUPPRESS_WARNING(5105) - -#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP - -// ================================================================================================= -// == FEATURE DETECTION ============================================================================ -// ================================================================================================= - -// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support -// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx -// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html -// MSVC version table: -// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering -// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) -// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) -// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) -// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) -// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) -// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) -// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) -// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) - -#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) -#define DOCTEST_CONFIG_WINDOWS_SEH -#endif // MSVC -#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH) -#undef DOCTEST_CONFIG_WINDOWS_SEH -#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH - -#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(__EMSCRIPTEN__) -#define DOCTEST_CONFIG_POSIX_SIGNALS -#endif // _WIN32 -#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) -#undef DOCTEST_CONFIG_POSIX_SIGNALS -#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) -#define DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // no exceptions -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS -#define DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) -#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - -#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) -#define DOCTEST_CONFIG_IMPLEMENT -#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN - -#if defined(_WIN32) || defined(__CYGWIN__) -#if DOCTEST_MSVC -#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) -#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) -#else // MSVC -#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport)) -#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport)) -#endif // MSVC -#else // _WIN32 -#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default"))) -#define DOCTEST_SYMBOL_IMPORT -#endif // _WIN32 - -#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL -#ifdef DOCTEST_CONFIG_IMPLEMENT -#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT -#else // DOCTEST_CONFIG_IMPLEMENT -#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT -#endif // DOCTEST_CONFIG_IMPLEMENT -#else // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL -#define DOCTEST_INTERFACE -#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL - -#define DOCTEST_EMPTY - -#if DOCTEST_MSVC -#define DOCTEST_NOINLINE __declspec(noinline) -#define DOCTEST_UNUSED -#define DOCTEST_ALIGNMENT(x) -#else // MSVC -#define DOCTEST_NOINLINE __attribute__((noinline)) -#define DOCTEST_UNUSED __attribute__((unused)) -#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) -#endif // MSVC - -#ifndef DOCTEST_NORETURN -#define DOCTEST_NORETURN [[noreturn]] -#endif // DOCTEST_NORETURN - -#ifndef DOCTEST_NOEXCEPT -#define DOCTEST_NOEXCEPT noexcept -#endif // DOCTEST_NOEXCEPT - -// ================================================================================================= -// == FEATURE DETECTION END ======================================================================== -// ================================================================================================= - -// internal macros for string concatenation and anonymous variable name generation -#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 -#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) -#ifdef __COUNTER__ // not standard and may be missing for some compilers -#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) -#else // __COUNTER__ -#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) -#endif // __COUNTER__ - -#define DOCTEST_TOSTR(x) #x - -#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE -#define DOCTEST_REF_WRAP(x) x& -#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE -#define DOCTEST_REF_WRAP(x) x -#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE - -// not using __APPLE__ because... this is how Catch does it -#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED -#define DOCTEST_PLATFORM_MAC -#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) -#define DOCTEST_PLATFORM_IPHONE -#elif defined(_WIN32) -#define DOCTEST_PLATFORM_WINDOWS -#else // DOCTEST_PLATFORM -#define DOCTEST_PLATFORM_LINUX -#endif // DOCTEST_PLATFORM - -#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ - DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \ - static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp) -#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#ifndef DOCTEST_BREAK_INTO_DEBUGGER -// should probably take a look at https://github.com/scottt/debugbreak -#ifdef DOCTEST_PLATFORM_MAC -#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) -#elif DOCTEST_MSVC -#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() -#elif defined(__MINGW32__) -DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") -extern "C" __declspec(dllimport) void __stdcall DebugBreak(); -DOCTEST_GCC_SUPPRESS_WARNING_POP -#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() -#else // linux -#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) -#endif // linux -#endif // DOCTEST_BREAK_INTO_DEBUGGER - -// this is kept here for backwards compatibility since the config option was changed -#ifdef DOCTEST_CONFIG_USE_IOSFWD -#define DOCTEST_CONFIG_USE_STD_HEADERS -#endif // DOCTEST_CONFIG_USE_IOSFWD - -#ifdef DOCTEST_CONFIG_USE_STD_HEADERS -#include -#include -#include -#else // DOCTEST_CONFIG_USE_STD_HEADERS - -#if DOCTEST_CLANG -// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) -#include -#endif // clang - -#ifdef _LIBCPP_VERSION -#define DOCTEST_STD_NAMESPACE_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD -#define DOCTEST_STD_NAMESPACE_END _LIBCPP_END_NAMESPACE_STD -#else // _LIBCPP_VERSION -#define DOCTEST_STD_NAMESPACE_BEGIN namespace std { -#define DOCTEST_STD_NAMESPACE_END } -#endif // _LIBCPP_VERSION - -// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) - -DOCTEST_STD_NAMESPACE_BEGIN // NOLINT (cert-dcl58-cpp) - typedef decltype(nullptr) nullptr_t; -template struct char_traits; -template <> struct char_traits; -template class basic_ostream; -typedef basic_ostream> ostream; -template class tuple; -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) -// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 -template class allocator; -template class basic_string; -using string = basic_string, allocator>; -#endif // VS 2019 -DOCTEST_STD_NAMESPACE_END - -DOCTEST_MSVC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_CONFIG_USE_STD_HEADERS - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS -#include -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - -namespace doctest { - - DOCTEST_INTERFACE extern bool is_running_in_test; - - // A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length - // of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for: - // - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) - // - if small - capacity left before going on the heap - using the lowest 5 bits - // - if small - 2 bits are left unused - the second and third highest ones - // - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator) - // and the "is small" bit remains "0" ("as well as the capacity left") so its OK - // Idea taken from this lecture about the string implementation of facebook/folly - fbstring - // https://www.youtube.com/watch?v=kPR8h4-qZdk - // TODO: - // - optimizations - like not deleting memory unnecessarily in operator= and etc. - // - resize/reserve/clear - // - substr - // - replace - // - back/front - // - iterator stuff - // - find & friends - // - push_back/pop_back - // - assign/insert/erase - // - relational operators as free functions - taking const char* as one of the params - class DOCTEST_INTERFACE String { - static const unsigned len = 24; //! OCLINT avoid private static members - static const unsigned last = len - 1; //! OCLINT avoid private static members - - struct view // len should be more than sizeof(view) - because of the final byte for flags - { - char* ptr; - unsigned size; - unsigned capacity; - }; - - union { - char buf[len]; - view data; - }; - - bool isOnStack() const { return (buf[last] & 128) == 0; } - void setOnHeap(); - void setLast(unsigned in = last); - - void copy(const String& other); - - public: - String(); - ~String(); - - // cppcheck-suppress noExplicitConstructor - String(const char* in); - String(const char* in, unsigned in_size); - - String(const String& other); - String& operator=(const String& other); - - String& operator+=(const String& other); - String operator+(const String& other) const; - - String(String&& other); - String& operator=(String&& other); - - char operator[](unsigned i) const; - char& operator[](unsigned i); - - // the only functions I'm willing to leave in the interface - available for inlining - const char* c_str() const { return const_cast(this)->c_str(); } // NOLINT - char* c_str() { - if (isOnStack()) - return reinterpret_cast(buf); - return data.ptr; - } - - unsigned size() const; - unsigned capacity() const; - - int compare(const char* other, bool no_case = false) const; - int compare(const String& other, bool no_case = false) const; - }; - - DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs); - DOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs); - - DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); - - namespace Color { - enum Enum { - None = 0, - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White - }; - - DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code); - } // namespace Color - - namespace assertType { - enum Enum { - // macro traits - - is_warn = 1, - is_check = 2 * is_warn, - is_require = 2 * is_check, - - is_normal = 2 * is_require, - is_throws = 2 * is_normal, - is_throws_as = 2 * is_throws, - is_throws_with = 2 * is_throws_as, - is_nothrow = 2 * is_throws_with, - - is_false = 2 * is_nothrow, - is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types - - is_eq = 2 * is_unary, - is_ne = 2 * is_eq, - - is_lt = 2 * is_ne, - is_gt = 2 * is_lt, - - is_ge = 2 * is_gt, - is_le = 2 * is_ge, - - // macro types - - DT_WARN = is_normal | is_warn, - DT_CHECK = is_normal | is_check, - DT_REQUIRE = is_normal | is_require, - - DT_WARN_FALSE = is_normal | is_false | is_warn, - DT_CHECK_FALSE = is_normal | is_false | is_check, - DT_REQUIRE_FALSE = is_normal | is_false | is_require, - - DT_WARN_THROWS = is_throws | is_warn, - DT_CHECK_THROWS = is_throws | is_check, - DT_REQUIRE_THROWS = is_throws | is_require, - - DT_WARN_THROWS_AS = is_throws_as | is_warn, - DT_CHECK_THROWS_AS = is_throws_as | is_check, - DT_REQUIRE_THROWS_AS = is_throws_as | is_require, - - DT_WARN_THROWS_WITH = is_throws_with | is_warn, - DT_CHECK_THROWS_WITH = is_throws_with | is_check, - DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, - - DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, - DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, - DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, - - DT_WARN_NOTHROW = is_nothrow | is_warn, - DT_CHECK_NOTHROW = is_nothrow | is_check, - DT_REQUIRE_NOTHROW = is_nothrow | is_require, - - DT_WARN_EQ = is_normal | is_eq | is_warn, - DT_CHECK_EQ = is_normal | is_eq | is_check, - DT_REQUIRE_EQ = is_normal | is_eq | is_require, - - DT_WARN_NE = is_normal | is_ne | is_warn, - DT_CHECK_NE = is_normal | is_ne | is_check, - DT_REQUIRE_NE = is_normal | is_ne | is_require, - - DT_WARN_GT = is_normal | is_gt | is_warn, - DT_CHECK_GT = is_normal | is_gt | is_check, - DT_REQUIRE_GT = is_normal | is_gt | is_require, - - DT_WARN_LT = is_normal | is_lt | is_warn, - DT_CHECK_LT = is_normal | is_lt | is_check, - DT_REQUIRE_LT = is_normal | is_lt | is_require, - - DT_WARN_GE = is_normal | is_ge | is_warn, - DT_CHECK_GE = is_normal | is_ge | is_check, - DT_REQUIRE_GE = is_normal | is_ge | is_require, - - DT_WARN_LE = is_normal | is_le | is_warn, - DT_CHECK_LE = is_normal | is_le | is_check, - DT_REQUIRE_LE = is_normal | is_le | is_require, - - DT_WARN_UNARY = is_normal | is_unary | is_warn, - DT_CHECK_UNARY = is_normal | is_unary | is_check, - DT_REQUIRE_UNARY = is_normal | is_unary | is_require, - - DT_WARN_UNARY_FALSE = is_normal | is_false | is_unary | is_warn, - DT_CHECK_UNARY_FALSE = is_normal | is_false | is_unary | is_check, - DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require, - }; - } // namespace assertType - - DOCTEST_INTERFACE const char* assertString(assertType::Enum at); - DOCTEST_INTERFACE const char* failureString(assertType::Enum at); - DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file); - - struct DOCTEST_INTERFACE TestCaseData { - String m_file; // the file in which the test was registered - unsigned m_line; // the line where the test was registered - const char* m_name; // name of the test case - const char* m_test_suite; // the test suite in which the test was added - const char* m_description; - bool m_skip; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; - }; - - struct DOCTEST_INTERFACE AssertData { - // common - for all asserts - const TestCaseData* m_test_case; - assertType::Enum m_at; - const char* m_file; - int m_line; - const char* m_expr; - bool m_failed; - - // exception-related - for all asserts - bool m_threw; - String m_exception; - - // for normal asserts - String m_decomp; - - // for specific exception-related asserts - bool m_threw_as; - const char* m_exception_type; - const char* m_exception_string; - }; - - struct DOCTEST_INTERFACE MessageData { - String m_string; - const char* m_file; - int m_line; - assertType::Enum m_severity; - }; - - struct DOCTEST_INTERFACE SubcaseSignature { - String m_name; - const char* m_file; - int m_line; - - bool operator<(const SubcaseSignature& other) const; - }; - - struct DOCTEST_INTERFACE IContextScope { - IContextScope(); - virtual ~IContextScope(); - virtual void stringify(std::ostream*) const = 0; - }; - - struct ContextOptions //! OCLINT too many fields - { - std::ostream* cout; // stdout stream - std::cout by default - std::ostream* cerr; // stderr stream - std::cerr by default - String binary_name; // the test binary name - - // == parameters from the command line - String out; // output filename - String order_by; // how tests should be ordered - unsigned rand_seed; // the seed for rand ordering - - unsigned first; // the first (matching) test to be executed - unsigned last; // the last (matching) test to be executed - - int abort_after; // stop tests after this many failed assertions - int subcase_filter_levels; // apply the subcase filters for the first N levels - - bool success; // include successful assertions in output - bool case_sensitive; // if filtering should be case sensitive - bool exit; // if the program should be exited after the tests are ran/whatever - bool duration; // print the time duration of each test case - bool no_throw; // to skip exceptions-related assertion macros - bool no_exitcode; // if the framework should return 0 as the exitcode - bool no_run; // to not run the tests at all (can be done with an "*" exclude) - bool no_version; // to not print the version of the framework - bool no_colors; // if output to the console should be colorized - bool force_colors; // forces the use of colors even when a tty cannot be detected - bool no_breaks; // to not break into the debugger - bool no_skip; // don't skip test cases which are marked to be skipped - bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): - bool no_path_in_filenames; // if the path to files should be removed from the output - bool no_line_numbers; // if source code line numbers should be omitted from the output - bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! - bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!! - - bool help; // to print the help - bool version; // to print the version - bool count; // if only the count of matching tests is to be retrieved - bool list_test_cases; // to list all tests matching the filters - bool list_test_suites; // to list all suites matching the filters - bool list_reporters; // lists all registered reporters - }; - - namespace detail { -#if defined(DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || defined(DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS) - template struct enable_if {}; - - template struct enable_if { typedef TYPE type; }; -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - // clang-format off - template struct remove_reference { typedef T type; }; - template struct remove_reference { typedef T type; }; - template struct remove_reference { typedef T type; }; - - template struct remove_const { typedef T type; }; - template struct remove_const { typedef T type; }; - // clang-format on - - template - struct deferred_false - // cppcheck-suppress unusedStructMember - { - static const bool value = false; - }; - - namespace has_insertion_operator_impl { - std::ostream& os(); - template DOCTEST_REF_WRAP(T) val(); - - template struct check { static constexpr auto value = false; }; - - template struct check(), void())> { - static constexpr auto value = true; - }; - } // namespace has_insertion_operator_impl - - template using has_insertion_operator = has_insertion_operator_impl::check; - - DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num); - - DOCTEST_INTERFACE std::ostream* getTlsOss(); // returns a thread-local ostringstream - DOCTEST_INTERFACE String getTlsOssResult(); - - template struct StringMakerBase { - template static String convert(const DOCTEST_REF_WRAP(T)) { return "{?}"; } - }; - - template <> struct StringMakerBase { - template static String convert(const DOCTEST_REF_WRAP(T) in) { - *getTlsOss() << in; - return getTlsOssResult(); - } - }; - - DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size); - - template String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { - return rawMemoryToString(&object, sizeof(object)); - } - - template const char* type_to_string() { return "<>"; } - } // namespace detail - - template - struct StringMaker : public detail::StringMakerBase::value> {}; - - template struct StringMaker { - template static String convert(U* p) { - if (p) - return detail::rawMemoryToString(p); - return "NULL"; - } - }; - - template struct StringMaker { - static String convert(R C::*p) { - if (p) - return detail::rawMemoryToString(p); - return "NULL"; - } - }; - - template String toString(const DOCTEST_REF_WRAP(T) value) { return StringMaker::convert(value); } - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE String toString(char* in); - DOCTEST_INTERFACE String toString(const char* in); -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE String toString(bool in); - DOCTEST_INTERFACE String toString(float in); - DOCTEST_INTERFACE String toString(double in); - DOCTEST_INTERFACE String toString(double long in); - - DOCTEST_INTERFACE String toString(char in); - DOCTEST_INTERFACE String toString(char signed in); - DOCTEST_INTERFACE String toString(char unsigned in); - DOCTEST_INTERFACE String toString(int short in); - DOCTEST_INTERFACE String toString(int short unsigned in); - DOCTEST_INTERFACE String toString(int in); - DOCTEST_INTERFACE String toString(int unsigned in); - DOCTEST_INTERFACE String toString(int long in); - DOCTEST_INTERFACE String toString(int long unsigned in); - DOCTEST_INTERFACE String toString(int long long in); - DOCTEST_INTERFACE String toString(int long long unsigned in); - DOCTEST_INTERFACE String toString(std::nullptr_t in); - -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) - // see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 - DOCTEST_INTERFACE String toString(const std::string& in); -#endif // VS 2019 - - class DOCTEST_INTERFACE Approx { - public: - explicit Approx(double value); - - Approx operator()(double value) const; - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - explicit Approx(const T& value, typename detail::enable_if::value>::type* = - static_cast(nullptr)) { - *this = Approx(static_cast(value)); - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - Approx& epsilon(double newEpsilon); - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - typename detail::enable_if::value, Approx&>::type - epsilon(const T& newEpsilon) { - m_epsilon = static_cast(newEpsilon); - return *this; - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - Approx& scale(double newScale); - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - template - typename detail::enable_if::value, Approx&>::type scale(const T& newScale) { - m_scale = static_cast(newScale); - return *this; - } -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - // clang-format off - DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs); - DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs); - DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs); - - DOCTEST_INTERFACE friend String toString(const Approx& in); - -#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - #define DOCTEST_APPROX_PREFIX \ - template friend typename detail::enable_if::value, bool>::type - - DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); } - DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } - DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } - DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } - DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; } - DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; } - DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; } -#undef DOCTEST_APPROX_PREFIX -#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS - - // clang-format on - - private: - double m_epsilon; - double m_scale; - double m_value; - }; - - DOCTEST_INTERFACE String toString(const Approx& in); - - DOCTEST_INTERFACE const ContextOptions* getContextOptions(); - -#if !defined(DOCTEST_CONFIG_DISABLE) - - namespace detail { - // clang-format off -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - template struct decay_array { typedef T type; }; - template struct decay_array { typedef T* type; }; - template struct decay_array { typedef T* type; }; - - template struct not_char_pointer { enum { value = 1 }; }; - template<> struct not_char_pointer { enum { value = 0 }; }; - template<> struct not_char_pointer { enum { value = 0 }; }; - - template struct can_use_op : public not_char_pointer::type> {}; -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - // clang-format on - - struct DOCTEST_INTERFACE TestFailureException {}; - - DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_NORETURN -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_INTERFACE void throwException(); - - struct DOCTEST_INTERFACE Subcase { - SubcaseSignature m_signature; - bool m_entered = false; - - Subcase(const String& name, const char* file, int line); - ~Subcase(); - - operator bool() const; - }; - - template - String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, const DOCTEST_REF_WRAP(R) rhs) { - return toString(lhs) + op + toString(rhs); - } - -#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ - template DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \ - bool res = op_macro(lhs, rhs); \ - if (m_at & assertType::is_false) \ - res = !res; \ - if (!res || doctest::getContextOptions()->success) \ - return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ - return Result(res); \ - } - - // more checks could be added - like in Catch: - // https://github.com/catchorg/Catch2/pull/1480/files - // https://github.com/catchorg/Catch2/pull/1481/files -#define DOCTEST_FORBIT_EXPRESSION(rt, op) \ - template rt& operator op(const R&) { \ - static_assert(deferred_false::value, "Expression Too Complex Please Rewrite As Binary Comparison!"); \ - return *this; \ - } - - struct DOCTEST_INTERFACE Result { - bool m_passed; - String m_decomp; - - Result(bool passed, const String& decomposition = String()); - - // forbidding some expressions based on this table: - // https://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(Result, &) - DOCTEST_FORBIT_EXPRESSION(Result, ^) - DOCTEST_FORBIT_EXPRESSION(Result, |) - DOCTEST_FORBIT_EXPRESSION(Result, &&) - DOCTEST_FORBIT_EXPRESSION(Result, ||) - DOCTEST_FORBIT_EXPRESSION(Result, ==) - DOCTEST_FORBIT_EXPRESSION(Result, !=) - DOCTEST_FORBIT_EXPRESSION(Result, <) - DOCTEST_FORBIT_EXPRESSION(Result, >) - DOCTEST_FORBIT_EXPRESSION(Result, <=) - DOCTEST_FORBIT_EXPRESSION(Result, >=) - DOCTEST_FORBIT_EXPRESSION(Result, =) - DOCTEST_FORBIT_EXPRESSION(Result, +=) - DOCTEST_FORBIT_EXPRESSION(Result, -=) - DOCTEST_FORBIT_EXPRESSION(Result, *=) - DOCTEST_FORBIT_EXPRESSION(Result, /=) - DOCTEST_FORBIT_EXPRESSION(Result, %=) - DOCTEST_FORBIT_EXPRESSION(Result, <<=) - DOCTEST_FORBIT_EXPRESSION(Result, >>=) - DOCTEST_FORBIT_EXPRESSION(Result, &=) - DOCTEST_FORBIT_EXPRESSION(Result, ^=) - DOCTEST_FORBIT_EXPRESSION(Result, |=) - }; - -#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - DOCTEST_CLANG_SUPPRESS_WARNING_PUSH - DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") - DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare") - // DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion") - // DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion") - // DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal") - - DOCTEST_GCC_SUPPRESS_WARNING_PUSH - DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") - DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare") - // DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion") - // DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") - // DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") - - DOCTEST_MSVC_SUPPRESS_WARNING_PUSH - // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 - DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch - DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch - DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch - // DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation - -#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - // clang-format off -#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_COMPARISON_RETURN_TYPE bool -#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - #define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type - inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } - inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } - inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } - inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } - inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } - inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - // clang-format on - -#define DOCTEST_RELATIONAL_OP(name, op) \ - template \ - DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { \ - return lhs op rhs; \ - } - - DOCTEST_RELATIONAL_OP(eq, ==) - DOCTEST_RELATIONAL_OP(ne, !=) - DOCTEST_RELATIONAL_OP(lt, <) - DOCTEST_RELATIONAL_OP(gt, >) - DOCTEST_RELATIONAL_OP(le, <=) - DOCTEST_RELATIONAL_OP(ge, >=) - -#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_CMP_EQ(l, r) l == r -#define DOCTEST_CMP_NE(l, r) l != r -#define DOCTEST_CMP_GT(l, r) l > r -#define DOCTEST_CMP_LT(l, r) l < r -#define DOCTEST_CMP_GE(l, r) l >= r -#define DOCTEST_CMP_LE(l, r) l <= r -#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING -#define DOCTEST_CMP_EQ(l, r) eq(l, r) -#define DOCTEST_CMP_NE(l, r) ne(l, r) -#define DOCTEST_CMP_GT(l, r) gt(l, r) -#define DOCTEST_CMP_LT(l, r) lt(l, r) -#define DOCTEST_CMP_GE(l, r) ge(l, r) -#define DOCTEST_CMP_LE(l, r) le(l, r) -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - - template - // cppcheck-suppress copyCtorAndEqOperator - struct Expression_lhs { - L lhs; - assertType::Enum m_at; - - explicit Expression_lhs(L in, assertType::Enum at) : lhs(in), m_at(at) {} - - DOCTEST_NOINLINE operator Result() { - bool res = !!lhs; - if (m_at & assertType::is_false) //! OCLINT bitwise operator in conditional - res = !res; - - if (!res || getContextOptions()->success) - return Result(res, toString(lhs)); - return Result(res); - } - - // clang-format off - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional - DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional - // clang-format on - - // forbidding some expressions based on this table: - // https://en.cppreference.com/w/cpp/language/operator_precedence - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=) - // these 2 are unfortunate because they should be allowed - they have higher precedence over the - // comparisons, but the ExpressionDecomposer class uses the left shift operator to capture the left operand - // of the binary expression... - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<) - DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>) - }; - -#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION - - struct DOCTEST_INTERFACE ExpressionDecomposer { - assertType::Enum m_at; - - ExpressionDecomposer(assertType::Enum at); - - // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence - // table) but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is - // problematic this will stay for now... https://github.com/catchorg/Catch2/issues/870 - // https://github.com/catchorg/Catch2/issues/565 - template - Expression_lhs operator<<(const DOCTEST_REF_WRAP(L) operand) { - return Expression_lhs(operand, m_at); - } - }; - - struct DOCTEST_INTERFACE TestSuite { - const char* m_test_suite; - const char* m_description; - bool m_skip; - bool m_may_fail; - bool m_should_fail; - int m_expected_failures; - double m_timeout; - - TestSuite& operator*(const char* in); - - template TestSuite& operator*(const T& in) { - in.fill(*this); - return *this; - } - }; - - typedef void (*funcType)(); - - struct DOCTEST_INTERFACE TestCase : public TestCaseData { - funcType m_test; // a function pointer to the test case - - const char* m_type; // for templated test cases - gets appended to the real name - int m_template_id; // an ID used to distinguish between the different versions of a templated test case - String m_full_name; // contains the name (only for templated test cases!) + the template type - - TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, const char* type = "", - int template_id = -1); - - TestCase(const TestCase& other); - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function - TestCase& operator=(const TestCase& other); - DOCTEST_MSVC_SUPPRESS_WARNING_POP - - TestCase& operator*(const char* in); - - template TestCase& operator*(const T& in) { - in.fill(*this); - return *this; - } - - bool operator<(const TestCase& other) const; - }; - - // forward declarations of functions used by the macros - DOCTEST_INTERFACE int regTest(const TestCase& tc); - DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); - DOCTEST_INTERFACE bool isDebuggerActive(); - - template int instantiationHelper(const T&) { return 0; } - - namespace binaryAssertComparison { - enum Enum { eq = 0, ne, gt, lt, ge, le }; - } // namespace binaryAssertComparison - - // clang-format off - template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; - -#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ - template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; - // clang-format on - - DOCTEST_BINARY_RELATIONAL_OP(0, eq) - DOCTEST_BINARY_RELATIONAL_OP(1, ne) - DOCTEST_BINARY_RELATIONAL_OP(2, gt) - DOCTEST_BINARY_RELATIONAL_OP(3, lt) - DOCTEST_BINARY_RELATIONAL_OP(4, ge) - DOCTEST_BINARY_RELATIONAL_OP(5, le) - - struct DOCTEST_INTERFACE ResultBuilder : public AssertData { - ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, - const char* exception_type = "", const char* exception_string = ""); - - void setResult(const Result& res); - - template - DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { - m_failed = !RelationalComparator()(lhs, rhs); - if (m_failed || getContextOptions()->success) - m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); - } - - template DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) { - m_failed = !val; - - if (m_at & assertType::is_false) //! OCLINT bitwise operator in conditional - m_failed = !m_failed; - - if (m_failed || getContextOptions()->success) - m_decomp = toString(val); - } - - void translateException(); - - bool log(); - void react() const; - }; - - namespace assertAction { - enum Enum { nothing = 0, dbgbreak = 1, shouldthrow = 2 }; - } // namespace assertAction - - DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad); - - DOCTEST_INTERFACE void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, - Result result); - -#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ - do { \ - if (!is_running_in_test) { \ - if (failed) { \ - ResultBuilder rb(at, file, line, expr); \ - rb.m_failed = failed; \ - rb.m_decomp = decomp; \ - failed_out_of_a_testing_context(rb); \ - if (isDebuggerActive() && !getContextOptions()->no_breaks) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - if (checkIfShouldThrow(at)) \ - throwException(); \ - } \ - return; \ - } \ - } while (false) - -#define DOCTEST_ASSERT_IN_TESTS(decomp) \ - ResultBuilder rb(at, file, line, expr); \ - rb.m_failed = failed; \ - if (rb.m_failed || getContextOptions()->success) \ - rb.m_decomp = decomp; \ - if (rb.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - if (rb.m_failed && checkIfShouldThrow(at)) \ - throwException() - - template - DOCTEST_NOINLINE void binary_assert(assertType::Enum at, const char* file, int line, const char* expr, - const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { - bool failed = !RelationalComparator()(lhs, rhs); - - // ################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT - // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); - DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); - } - - template - DOCTEST_NOINLINE void unary_assert(assertType::Enum at, const char* file, int line, const char* expr, - const DOCTEST_REF_WRAP(L) val) { - bool failed = !val; - - if (at & assertType::is_false) //! OCLINT bitwise operator in conditional - failed = !failed; - - // ################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT - // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(toString(val)); - DOCTEST_ASSERT_IN_TESTS(toString(val)); - } - - struct DOCTEST_INTERFACE IExceptionTranslator { - IExceptionTranslator(); - virtual ~IExceptionTranslator(); - virtual bool translate(String&) const = 0; - }; - - template - class ExceptionTranslator : public IExceptionTranslator //! OCLINT destructor of virtual class - { - public: - explicit ExceptionTranslator(String (*translateFunction)(T)) : m_translateFunction(translateFunction) {} - - bool translate(String& res) const override { -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - try { - throw; // lgtm [cpp/rethrow-no-exception] - // cppcheck-suppress catchExceptionByValue - } catch (T ex) { // NOLINT - res = m_translateFunction(ex); //! OCLINT parameter reassignment - return true; - } catch (...) { - } //! OCLINT - empty catch statement -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - ((void)res); // to silence -Wunused-parameter - return false; - } - - private: - String (*m_translateFunction)(T); - }; - - DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et); - - template struct StringStreamBase { - template static void convert(std::ostream* s, const T& in) { *s << toString(in); } - - // always treat char* as a string in this context - no matter - // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined - static void convert(std::ostream* s, const char* in) { *s << String(in); } - }; - - template <> struct StringStreamBase { - template static void convert(std::ostream* s, const T& in) { *s << in; } - }; - - template struct StringStream : public StringStreamBase::value> {}; - - template void toStream(std::ostream* s, const T& value) { StringStream::convert(s, value); } - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE void toStream(std::ostream* s, char* in); - DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in); -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - DOCTEST_INTERFACE void toStream(std::ostream* s, bool in); - DOCTEST_INTERFACE void toStream(std::ostream* s, float in); - DOCTEST_INTERFACE void toStream(std::ostream* s, double in); - DOCTEST_INTERFACE void toStream(std::ostream* s, double long in); - - DOCTEST_INTERFACE void toStream(std::ostream* s, char in); - DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in); - DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int short in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in); - DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in); - - // ContextScope base class used to allow implementing methods of ContextScope - // that don't depend on the template parameter in doctest.cpp. - class DOCTEST_INTERFACE ContextScopeBase : public IContextScope { - protected: - ContextScopeBase(); - - void destroy(); - }; - - template class ContextScope : public ContextScopeBase { - const L& lambda_; - - public: - explicit ContextScope(const L& lambda) : lambda_(lambda) {} - - ContextScope(ContextScope&& other) : lambda_(other.lambda_) {} - - void stringify(std::ostream* s) const override { lambda_(s); } - - ~ContextScope() override { destroy(); } - }; - - struct DOCTEST_INTERFACE MessageBuilder : public MessageData { - std::ostream* m_stream; - - MessageBuilder(const char* file, int line, assertType::Enum severity); - MessageBuilder() = delete; - ~MessageBuilder(); - - template MessageBuilder& operator<<(const T& in) { - toStream(m_stream, in); - return *this; - } - - bool log(); - void react(); - }; - - template ContextScope MakeContextScope(const L& lambda) { return ContextScope(lambda); } - } // namespace detail - -#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ - struct name { \ - type data; \ - name(type in = def) : data(in) {} \ - void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; } \ - void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; } \ - } - - DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); - DOCTEST_DEFINE_DECORATOR(description, const char*, ""); - DOCTEST_DEFINE_DECORATOR(skip, bool, true); - DOCTEST_DEFINE_DECORATOR(timeout, double, 0); - DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); - DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); - DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0); - - template int registerExceptionTranslator(String (*translateFunction)(T)) { - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") - static detail::ExceptionTranslator exceptionTranslator(translateFunction); - DOCTEST_CLANG_SUPPRESS_WARNING_POP - detail::registerExceptionTranslatorImpl(&exceptionTranslator); - return 0; - } - -} // namespace doctest - -// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro -// introduces an anonymous namespace in which getCurrentTestSuite gets overridden -namespace doctest_detail_test_suite_ns { - DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); -} // namespace doctest_detail_test_suite_ns - -namespace doctest { -#else // DOCTEST_CONFIG_DISABLE - template int registerExceptionTranslator(String (*)(T)) { return 0; } -#endif // DOCTEST_CONFIG_DISABLE - - namespace detail { - typedef void (*assert_handler)(const AssertData&); - struct ContextState; - } // namespace detail - - class DOCTEST_INTERFACE Context { - detail::ContextState* p; - - void parseArgs(int argc, const char* const* argv, bool withDefaults = false); - - public: - explicit Context(int argc = 0, const char* const* argv = nullptr); - - ~Context(); - - void applyCommandLine(int argc, const char* const* argv); - - void addFilter(const char* filter, const char* value); - void clearFilters(); - void setOption(const char* option, int value); - void setOption(const char* option, const char* value); - - bool shouldExit(); - - void setAsDefaultForAssertsOutOfTestCases(); - - void setAssertHandler(detail::assert_handler ah); - - int run(); - }; - - namespace TestCaseFailureReason { - enum Enum { - None = 0, - AssertFailure = 1, // an assertion has failed in the test case - Exception = 2, // test case threw an exception - Crash = 4, // a crash... - TooManyFailedAsserts = 8, // the abort-after option - Timeout = 16, // see the timeout decorator - ShouldHaveFailedButDidnt = 32, // see the should_fail decorator - ShouldHaveFailedAndDid = 64, // see the should_fail decorator - DidntFailExactlyNumTimes = 128, // see the expected_failures decorator - FailedExactlyNumTimes = 256, // see the expected_failures decorator - CouldHaveFailedAndDid = 512 // see the may_fail decorator - }; - } // namespace TestCaseFailureReason - - struct DOCTEST_INTERFACE CurrentTestCaseStats { - int numAssertsCurrentTest; - int numAssertsFailedCurrentTest; - double seconds; - int failure_flags; // use TestCaseFailureReason::Enum - }; - - struct DOCTEST_INTERFACE TestCaseException { - String error_string; - bool is_crash; - }; - - struct DOCTEST_INTERFACE TestRunStats { - unsigned numTestCases; - unsigned numTestCasesPassingFilters; - unsigned numTestSuitesPassingFilters; - unsigned numTestCasesFailed; - int numAsserts; - int numAssertsFailed; - }; - - struct QueryData { - const TestRunStats* run_stats = nullptr; - const TestCaseData** data = nullptr; - unsigned num_data = 0; - }; - - struct DOCTEST_INTERFACE IReporter { - // The constructor has to accept "const ContextOptions&" as a single argument - // which has most of the options for the run + a pointer to the stdout stream - // Reporter(const ContextOptions& in) - - // called when a query should be reported (listing test cases, printing the version, etc.) - virtual void report_query(const QueryData&) = 0; - - // called when the whole test run starts - virtual void test_run_start() = 0; - // called when the whole test run ends (caching a pointer to the input doesn't make sense here) - virtual void test_run_end(const TestRunStats&) = 0; - - // called when a test case is started (safe to cache a pointer to the input) - virtual void test_case_start(const TestCaseData&) = 0; - // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) - virtual void test_case_reenter(const TestCaseData&) = 0; - // called when a test case has ended - virtual void test_case_end(const CurrentTestCaseStats&) = 0; - - // called when an exception is thrown from the test case (or it crashes) - virtual void test_case_exception(const TestCaseException&) = 0; - - // called whenever a subcase is entered (don't cache pointers to the input) - virtual void subcase_start(const SubcaseSignature&) = 0; - // called whenever a subcase is exited (don't cache pointers to the input) - virtual void subcase_end() = 0; - - // called for each assert (don't cache pointers to the input) - virtual void log_assert(const AssertData&) = 0; - // called for each message (don't cache pointers to the input) - virtual void log_message(const MessageData&) = 0; - - // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator - // or isn't in the execution range (between first and last) (safe to cache a pointer to the input) - virtual void test_case_skipped(const TestCaseData&) = 0; - - // doctest will not be managing the lifetimes of reporters given to it but this would still be nice to have - virtual ~IReporter(); - - // can obtain all currently active contexts and stringify them if one wishes to do so - static int get_num_active_contexts(); - static const IContextScope* const* get_active_contexts(); - - // can iterate through contexts which have been stringified automatically in their destructors when an exception - // has been thrown - static int get_num_stringified_contexts(); - static const String* get_stringified_contexts(); - }; - - namespace detail { - typedef IReporter* (*reporterCreatorFunc)(const ContextOptions&); - - DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter); - - template IReporter* reporterCreator(const ContextOptions& o) { return new Reporter(o); } - } // namespace detail - - template int registerReporter(const char* name, int priority, bool isReporter) { - detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); - return 0; - } -} // namespace doctest - -// if registering is not disabled -#if !defined(DOCTEST_CONFIG_DISABLE) - -// common code in asserts - for convenience -#define DOCTEST_ASSERT_LOG_AND_REACT(b) \ - if (b.log()) \ - DOCTEST_BREAK_INTO_DEBUGGER(); \ - b.react() - -#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_WRAP_IN_TRY(x) x; -#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS -#define DOCTEST_WRAP_IN_TRY(x) \ - try { \ - x; \ - } catch (...) { \ - _DOCTEST_RB.translateException(); \ - } -#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS - -#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS -#define DOCTEST_CAST_TO_VOID(...) \ - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ - static_cast(__VA_ARGS__); \ - DOCTEST_GCC_SUPPRESS_WARNING_POP -#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS -#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; -#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS - -// registers the test by initializing a dummy var with a function -#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ - global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = doctest::detail::regTest( \ - doctest::detail::TestCase(f, __FILE__, __LINE__, doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ - decorators); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() - -#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ - namespace { \ - struct der : public base { \ - void f(); \ - }; \ - static void func() { \ - der v; \ - v.f(); \ - } \ - DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ - } \ - inline DOCTEST_NOINLINE void der::f() - -#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ - static void f(); \ - DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators) \ - static void f() - -#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ - static doctest::detail::funcType proxy() { return f; } \ - DOCTEST_REGISTER_FUNCTION(inline const, proxy(), decorators) \ - static void f() - -// for registering tests -#define DOCTEST_TEST_CASE(decorators) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) - -// for registering tests in classes - requires C++17 for inline variables! -#if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && _MSVC_LANG >= 201703L) -#define DOCTEST_TEST_CASE_CLASS(decorators) \ - DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), \ - DOCTEST_ANONYMOUS(_DOCTEST_ANON_PROXY_), decorators) -#else // DOCTEST_TEST_CASE_CLASS -#define DOCTEST_TEST_CASE_CLASS(...) TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER -#endif // DOCTEST_TEST_CASE_CLASS - -// for registering tests with a fixture -#define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ - DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), \ - decorators) - -// for converting types to strings without the header and demangling -#define DOCTEST_TYPE_TO_STRING_IMPL(...) \ - template <> inline const char* type_to_string<__VA_ARGS__>() { return "<" #__VA_ARGS__ ">"; } -#define DOCTEST_TYPE_TO_STRING(...) \ - namespace doctest { \ - namespace detail { \ - DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \ - } \ - } \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ - template static void func(); \ - namespace { \ - template struct iter; \ - template struct iter> { \ - iter(const char* file, unsigned line, int index) { \ - doctest::detail::regTest( \ - doctest::detail::TestCase(func, file, line, \ - doctest_detail_test_suite_ns::getCurrentTestSuite(), \ - doctest::detail::type_to_string(), int(line) * 1000 + index) * \ - dec); \ - iter>(file, line, index + 1); \ - } \ - }; \ - template <> struct iter> { \ - iter(const char*, unsigned, int) {} \ - }; \ - } \ - template static void func() - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) - -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = \ - doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR) < __VA_ARGS__ > (__FILE__, __LINE__, 0)); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() - -#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ - DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ - template static void anon() - -#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ - DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) - -// for subcases -#define DOCTEST_SUBCASE(name) \ - if (const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ - doctest::detail::Subcase(name, __FILE__, __LINE__)) - -// for grouping tests in test suites by using code blocks -#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ - namespace ns_name { \ - namespace doctest_detail_test_suite_ns { \ - static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ - static doctest::detail::TestSuite data; \ - static bool inited = false; \ - DOCTEST_MSVC_SUPPRESS_WARNING_POP \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP \ - if (!inited) { \ - data* decorators; \ - inited = true; \ - } \ - return data; \ - } \ - } \ - } \ - namespace ns_name - -#define DOCTEST_TEST_SUITE(decorators) DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_)) - -// for starting a testsuite block -#define DOCTEST_TEST_SUITE_BEGIN(decorators) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for ending a testsuite block -#define DOCTEST_TEST_SUITE_END \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ - doctest::detail::setTestSuite(doctest::detail::TestSuite() * ""); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for registering exception translators -#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ - inline doctest::String translatorName(signature); \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = \ - doctest::registerExceptionTranslator(translatorName); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() \ - doctest::String translatorName(signature) - -#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ - DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), signature) - -// for registering reporters -#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ - doctest::registerReporter(name, priority, true); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for registering listeners -#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ - DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ - doctest::registerReporter(name, priority, false); \ - DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for logging -#define DOCTEST_INFO(expression) \ - DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \ - DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), expression) - -#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, expression) \ - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \ - auto lambda_name = [&](std::ostream* s_name) { \ - doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ - mb_name.m_stream = s_name; \ - mb_name << expression; \ - }; \ - DOCTEST_MSVC_SUPPRESS_WARNING_POP \ - auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(lambda_name) - -#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := " << x) - -#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, x) \ - do { \ - doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ - mb << x; \ - DOCTEST_ASSERT_LOG_AND_REACT(mb); \ - } while (false) - -// clang-format off -#define DOCTEST_ADD_MESSAGE_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) -#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) -#define DOCTEST_ADD_FAIL_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) -// clang-format on - -#define DOCTEST_MESSAGE(x) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, x) -#define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x) -#define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x) - -#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. - -#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY( \ - _DOCTEST_RB.setResult(doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) << __VA_ARGS__)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB) \ - DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ - do { \ - DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ - } while (false) - -#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -// necessary for _MESSAGE -#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 - -#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ - doctest::detail::decomp_assert(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, \ - doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ - << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP - -#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__) -#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__) -#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__) -#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__) -#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__) -#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) - -// clang-format off -#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while(false) -#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while(false) -#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while(false) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while(false) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while(false) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while(false) -// clang-format on - -#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ - do { \ - if (!doctest::getContextOptions()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, #expr, \ - #__VA_ARGS__, message); \ - try { \ - DOCTEST_CAST_TO_VOID(expr) \ - } catch ( \ - const doctest::detail::remove_const::type>::type&) { \ - _DOCTEST_RB.translateException(); \ - _DOCTEST_RB.m_threw_as = true; \ - } catch (...) { \ - _DOCTEST_RB.translateException(); \ - } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while (false) - -#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ - do { \ - if (!doctest::getContextOptions()->no_throw) { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, expr_str, \ - "", __VA_ARGS__); \ - try { \ - DOCTEST_CAST_TO_VOID(expr) \ - } catch (...) { \ - _DOCTEST_RB.translateException(); \ - } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } \ - } while (false) - -#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, \ - #__VA_ARGS__); \ - try { \ - DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ - } catch (...) { \ - _DOCTEST_RB.translateException(); \ - } \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while (false) - -// clang-format off -#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") -#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") -#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") - -#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) - -#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) -#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) -#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) - -#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) -#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) -#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) - -#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) -#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) -#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS(expr); } while(false) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS(expr); } while(false) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS(expr); } while(false) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_AS(expr, ex); } while(false) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_AS(expr, ex); } while(false) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while(false) -#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH(expr, with); } while(false) -#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH(expr, with); } while(false) -#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } while(false) -#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } while(false) -#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } while(false) -#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } while(false) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_NOTHROW(expr); } while(false) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_NOTHROW(expr); } while(false) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_NOTHROW(expr); } while(false) -// clang-format on - -#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, \ - #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.binary_assert(__VA_ARGS__)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while (false) - -#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ - do { \ - doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, \ - #__VA_ARGS__); \ - DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__)) \ - DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ - } while (false) - -#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...) \ - doctest::detail::binary_assert( \ - doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) - -#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ - doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) - -#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS - -#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__) -#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__) -#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__) -#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__) -#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__) -#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__) -#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__) -#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__) -#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__) -#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__) -#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__) -#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__) -#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__) -#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__) -#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__) -#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__) -#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__) -#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__) - -#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__) -#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__) -#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__) -#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__) -#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__) -#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__) - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS - -#undef DOCTEST_WARN_THROWS -#undef DOCTEST_CHECK_THROWS -#undef DOCTEST_REQUIRE_THROWS -#undef DOCTEST_WARN_THROWS_AS -#undef DOCTEST_CHECK_THROWS_AS -#undef DOCTEST_REQUIRE_THROWS_AS -#undef DOCTEST_WARN_THROWS_WITH -#undef DOCTEST_CHECK_THROWS_WITH -#undef DOCTEST_REQUIRE_THROWS_WITH -#undef DOCTEST_WARN_THROWS_WITH_AS -#undef DOCTEST_CHECK_THROWS_WITH_AS -#undef DOCTEST_REQUIRE_THROWS_WITH_AS -#undef DOCTEST_WARN_NOTHROW -#undef DOCTEST_CHECK_NOTHROW -#undef DOCTEST_REQUIRE_NOTHROW - -#undef DOCTEST_WARN_THROWS_MESSAGE -#undef DOCTEST_CHECK_THROWS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_MESSAGE -#undef DOCTEST_WARN_THROWS_AS_MESSAGE -#undef DOCTEST_CHECK_THROWS_AS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE -#undef DOCTEST_WARN_THROWS_WITH_MESSAGE -#undef DOCTEST_CHECK_THROWS_WITH_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_WITH_MESSAGE -#undef DOCTEST_WARN_THROWS_WITH_AS_MESSAGE -#undef DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE -#undef DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE -#undef DOCTEST_WARN_NOTHROW_MESSAGE -#undef DOCTEST_CHECK_NOTHROW_MESSAGE -#undef DOCTEST_REQUIRE_NOTHROW_MESSAGE - -#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#define DOCTEST_WARN_THROWS(...) ((void)0) -#define DOCTEST_CHECK_THROWS(...) ((void)0) -#define DOCTEST_REQUIRE_THROWS(...) ((void)0) -#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0) -#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ((void)0) -#define DOCTEST_WARN_NOTHROW(...) ((void)0) -#define DOCTEST_CHECK_NOTHROW(...) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW(...) ((void)0) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) -#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) - -#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#undef DOCTEST_REQUIRE -#undef DOCTEST_REQUIRE_FALSE -#undef DOCTEST_REQUIRE_MESSAGE -#undef DOCTEST_REQUIRE_FALSE_MESSAGE -#undef DOCTEST_REQUIRE_EQ -#undef DOCTEST_REQUIRE_NE -#undef DOCTEST_REQUIRE_GT -#undef DOCTEST_REQUIRE_LT -#undef DOCTEST_REQUIRE_GE -#undef DOCTEST_REQUIRE_LE -#undef DOCTEST_REQUIRE_UNARY -#undef DOCTEST_REQUIRE_UNARY_FALSE - -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS - -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - -// ================================================================================================= -// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == -// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == -// ================================================================================================= -#else // DOCTEST_CONFIG_DISABLE - -#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ - namespace { \ - template struct der : public base { void f(); }; \ - } \ - template inline void der::f() - -#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ - template static inline void f() - -// for registering tests -#define DOCTEST_TEST_CASE(name) DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) - -// for registering tests in classes -#define DOCTEST_TEST_CASE_CLASS(name) DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) - -// for registering tests with a fixture -#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ - DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) - -// for converting types to strings without the header and demangling -#define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) -#define DOCTEST_TYPE_TO_STRING_IMPL(...) - -// for typed tests -#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ - template inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() - -#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ - template inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() - -#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for subcases -#define DOCTEST_SUBCASE(name) - -// for a testsuite block -#define DOCTEST_TEST_SUITE(name) namespace - -// for starting a testsuite block -#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -// for ending a testsuite block -#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) - -#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ - template \ - static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) - -#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) -#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) - -#define DOCTEST_INFO(x) ((void)0) -#define DOCTEST_CAPTURE(x) ((void)0) -#define DOCTEST_ADD_MESSAGE_AT(file, line, x) ((void)0) -#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) ((void)0) -#define DOCTEST_ADD_FAIL_AT(file, line, x) ((void)0) -#define DOCTEST_MESSAGE(x) ((void)0) -#define DOCTEST_FAIL_CHECK(x) ((void)0) -#define DOCTEST_FAIL(x) ((void)0) - -#define DOCTEST_WARN(...) ((void)0) -#define DOCTEST_CHECK(...) ((void)0) -#define DOCTEST_REQUIRE(...) ((void)0) -#define DOCTEST_WARN_FALSE(...) ((void)0) -#define DOCTEST_CHECK_FALSE(...) ((void)0) -#define DOCTEST_REQUIRE_FALSE(...) ((void)0) - -#define DOCTEST_WARN_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_CHECK_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_REQUIRE_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) ((void)0) -#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) ((void)0) - -#define DOCTEST_WARN_THROWS(...) ((void)0) -#define DOCTEST_CHECK_THROWS(...) ((void)0) -#define DOCTEST_REQUIRE_THROWS(...) ((void)0) -#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) -#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0) -#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ((void)0) -#define DOCTEST_WARN_NOTHROW(...) ((void)0) -#define DOCTEST_CHECK_NOTHROW(...) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW(...) ((void)0) - -#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) -#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) -#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) -#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) -#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) -#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) -#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) - -#define DOCTEST_WARN_EQ(...) ((void)0) -#define DOCTEST_CHECK_EQ(...) ((void)0) -#define DOCTEST_REQUIRE_EQ(...) ((void)0) -#define DOCTEST_WARN_NE(...) ((void)0) -#define DOCTEST_CHECK_NE(...) ((void)0) -#define DOCTEST_REQUIRE_NE(...) ((void)0) -#define DOCTEST_WARN_GT(...) ((void)0) -#define DOCTEST_CHECK_GT(...) ((void)0) -#define DOCTEST_REQUIRE_GT(...) ((void)0) -#define DOCTEST_WARN_LT(...) ((void)0) -#define DOCTEST_CHECK_LT(...) ((void)0) -#define DOCTEST_REQUIRE_LT(...) ((void)0) -#define DOCTEST_WARN_GE(...) ((void)0) -#define DOCTEST_CHECK_GE(...) ((void)0) -#define DOCTEST_REQUIRE_GE(...) ((void)0) -#define DOCTEST_WARN_LE(...) ((void)0) -#define DOCTEST_CHECK_LE(...) ((void)0) -#define DOCTEST_REQUIRE_LE(...) ((void)0) - -#define DOCTEST_WARN_UNARY(...) ((void)0) -#define DOCTEST_CHECK_UNARY(...) ((void)0) -#define DOCTEST_REQUIRE_UNARY(...) ((void)0) -#define DOCTEST_WARN_UNARY_FALSE(...) ((void)0) -#define DOCTEST_CHECK_UNARY_FALSE(...) ((void)0) -#define DOCTEST_REQUIRE_UNARY_FALSE(...) ((void)0) - -#endif // DOCTEST_CONFIG_DISABLE - -// clang-format off -// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS -#define DOCTEST_FAST_WARN_EQ DOCTEST_WARN_EQ -#define DOCTEST_FAST_CHECK_EQ DOCTEST_CHECK_EQ -#define DOCTEST_FAST_REQUIRE_EQ DOCTEST_REQUIRE_EQ -#define DOCTEST_FAST_WARN_NE DOCTEST_WARN_NE -#define DOCTEST_FAST_CHECK_NE DOCTEST_CHECK_NE -#define DOCTEST_FAST_REQUIRE_NE DOCTEST_REQUIRE_NE -#define DOCTEST_FAST_WARN_GT DOCTEST_WARN_GT -#define DOCTEST_FAST_CHECK_GT DOCTEST_CHECK_GT -#define DOCTEST_FAST_REQUIRE_GT DOCTEST_REQUIRE_GT -#define DOCTEST_FAST_WARN_LT DOCTEST_WARN_LT -#define DOCTEST_FAST_CHECK_LT DOCTEST_CHECK_LT -#define DOCTEST_FAST_REQUIRE_LT DOCTEST_REQUIRE_LT -#define DOCTEST_FAST_WARN_GE DOCTEST_WARN_GE -#define DOCTEST_FAST_CHECK_GE DOCTEST_CHECK_GE -#define DOCTEST_FAST_REQUIRE_GE DOCTEST_REQUIRE_GE -#define DOCTEST_FAST_WARN_LE DOCTEST_WARN_LE -#define DOCTEST_FAST_CHECK_LE DOCTEST_CHECK_LE -#define DOCTEST_FAST_REQUIRE_LE DOCTEST_REQUIRE_LE - -#define DOCTEST_FAST_WARN_UNARY DOCTEST_WARN_UNARY -#define DOCTEST_FAST_CHECK_UNARY DOCTEST_CHECK_UNARY -#define DOCTEST_FAST_REQUIRE_UNARY DOCTEST_REQUIRE_UNARY -#define DOCTEST_FAST_WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE -#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE -#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE - -#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INVOKE -// clang-format on - -// BDD style macros -// clang-format off -#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(" Scenario: " name) -#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(" Scenario: " name) -#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) -#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) - -#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) -#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) -#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " name) -#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) -#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) -// clang-format on - -// == SHORT VERSIONS OF THE MACROS -#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) - -#define TEST_CASE DOCTEST_TEST_CASE -#define TEST_CASE_CLASS DOCTEST_TEST_CASE_CLASS -#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE -#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING -#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE -#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE -#define TEST_CASE_TEMPLATE_INVOKE DOCTEST_TEST_CASE_TEMPLATE_INVOKE -#define TEST_CASE_TEMPLATE_APPLY DOCTEST_TEST_CASE_TEMPLATE_APPLY -#define SUBCASE DOCTEST_SUBCASE -#define TEST_SUITE DOCTEST_TEST_SUITE -#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN -#define TEST_SUITE_END DOCTEST_TEST_SUITE_END -#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR -#define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER -#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER -#define INFO DOCTEST_INFO -#define CAPTURE DOCTEST_CAPTURE -#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT -#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT -#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT -#define MESSAGE DOCTEST_MESSAGE -#define FAIL_CHECK DOCTEST_FAIL_CHECK -#define FAIL DOCTEST_FAIL -#define TO_LVALUE DOCTEST_TO_LVALUE - -#define WARN DOCTEST_WARN -#define WARN_FALSE DOCTEST_WARN_FALSE -#define WARN_THROWS DOCTEST_WARN_THROWS -#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS -#define WARN_THROWS_WITH DOCTEST_WARN_THROWS_WITH -#define WARN_THROWS_WITH_AS DOCTEST_WARN_THROWS_WITH_AS -#define WARN_NOTHROW DOCTEST_WARN_NOTHROW -#define CHECK DOCTEST_CHECK -#define CHECK_FALSE DOCTEST_CHECK_FALSE -#define CHECK_THROWS DOCTEST_CHECK_THROWS -#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS -#define CHECK_THROWS_WITH DOCTEST_CHECK_THROWS_WITH -#define CHECK_THROWS_WITH_AS DOCTEST_CHECK_THROWS_WITH_AS -#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW -#define REQUIRE DOCTEST_REQUIRE -#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE -#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS -#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS -#define REQUIRE_THROWS_WITH DOCTEST_REQUIRE_THROWS_WITH -#define REQUIRE_THROWS_WITH_AS DOCTEST_REQUIRE_THROWS_WITH_AS -#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW - -#define WARN_MESSAGE DOCTEST_WARN_MESSAGE -#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE -#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE -#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE -#define WARN_THROWS_WITH_MESSAGE DOCTEST_WARN_THROWS_WITH_MESSAGE -#define WARN_THROWS_WITH_AS_MESSAGE DOCTEST_WARN_THROWS_WITH_AS_MESSAGE -#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE -#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE -#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE -#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE -#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE -#define CHECK_THROWS_WITH_MESSAGE DOCTEST_CHECK_THROWS_WITH_MESSAGE -#define CHECK_THROWS_WITH_AS_MESSAGE DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE -#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE -#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE -#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE -#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE -#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE -#define REQUIRE_THROWS_WITH_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_MESSAGE -#define REQUIRE_THROWS_WITH_AS_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE -#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE - -#define SCENARIO DOCTEST_SCENARIO -#define SCENARIO_CLASS DOCTEST_SCENARIO_CLASS -#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE -#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE -#define GIVEN DOCTEST_GIVEN -#define WHEN DOCTEST_WHEN -#define AND_WHEN DOCTEST_AND_WHEN -#define THEN DOCTEST_THEN -#define AND_THEN DOCTEST_AND_THEN - -#define WARN_EQ DOCTEST_WARN_EQ -#define CHECK_EQ DOCTEST_CHECK_EQ -#define REQUIRE_EQ DOCTEST_REQUIRE_EQ -#define WARN_NE DOCTEST_WARN_NE -#define CHECK_NE DOCTEST_CHECK_NE -#define REQUIRE_NE DOCTEST_REQUIRE_NE -#define WARN_GT DOCTEST_WARN_GT -#define CHECK_GT DOCTEST_CHECK_GT -#define REQUIRE_GT DOCTEST_REQUIRE_GT -#define WARN_LT DOCTEST_WARN_LT -#define CHECK_LT DOCTEST_CHECK_LT -#define REQUIRE_LT DOCTEST_REQUIRE_LT -#define WARN_GE DOCTEST_WARN_GE -#define CHECK_GE DOCTEST_CHECK_GE -#define REQUIRE_GE DOCTEST_REQUIRE_GE -#define WARN_LE DOCTEST_WARN_LE -#define CHECK_LE DOCTEST_CHECK_LE -#define REQUIRE_LE DOCTEST_REQUIRE_LE -#define WARN_UNARY DOCTEST_WARN_UNARY -#define CHECK_UNARY DOCTEST_CHECK_UNARY -#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY -#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE -#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE -#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE - -// KEPT FOR BACKWARDS COMPATIBILITY -#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ -#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ -#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ -#define FAST_WARN_NE DOCTEST_FAST_WARN_NE -#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE -#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE -#define FAST_WARN_GT DOCTEST_FAST_WARN_GT -#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT -#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT -#define FAST_WARN_LT DOCTEST_FAST_WARN_LT -#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT -#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT -#define FAST_WARN_GE DOCTEST_FAST_WARN_GE -#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE -#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE -#define FAST_WARN_LE DOCTEST_FAST_WARN_LE -#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE -#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE - -#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY -#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY -#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY -#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE -#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE -#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE - -#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE - -#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES - -#if !defined(DOCTEST_CONFIG_DISABLE) - -// this is here to clear the 'current test suite' for the current translation unit - at the top -DOCTEST_TEST_SUITE_END(); - -// add stringification for primitive/fundamental types -namespace doctest { - namespace detail { - DOCTEST_TYPE_TO_STRING_IMPL(bool) - DOCTEST_TYPE_TO_STRING_IMPL(float) - DOCTEST_TYPE_TO_STRING_IMPL(double) - DOCTEST_TYPE_TO_STRING_IMPL(long double) - DOCTEST_TYPE_TO_STRING_IMPL(char) - DOCTEST_TYPE_TO_STRING_IMPL(signed char) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned char) -#if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) - DOCTEST_TYPE_TO_STRING_IMPL(wchar_t) -#endif // not MSVC or wchar_t support enabled - DOCTEST_TYPE_TO_STRING_IMPL(short int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int) - DOCTEST_TYPE_TO_STRING_IMPL(int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned int) - DOCTEST_TYPE_TO_STRING_IMPL(long int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int) - DOCTEST_TYPE_TO_STRING_IMPL(long long int) - DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int) - } -} // namespace doctest::detail - -#endif // DOCTEST_CONFIG_DISABLE - -DOCTEST_CLANG_SUPPRESS_WARNING_POP -DOCTEST_MSVC_SUPPRESS_WARNING_POP -DOCTEST_GCC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_LIBRARY_INCLUDED - -#ifndef DOCTEST_SINGLE_HEADER -#define DOCTEST_SINGLE_HEADER -#endif // DOCTEST_SINGLE_HEADER - -#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) - -#ifndef DOCTEST_SINGLE_HEADER -#include "doctest_fwd.h" -#endif // DOCTEST_SINGLE_HEADER - -DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") - -#ifndef DOCTEST_LIBRARY_IMPLEMENTATION -#define DOCTEST_LIBRARY_IMPLEMENTATION - -DOCTEST_CLANG_SUPPRESS_WARNING_POP - -DOCTEST_CLANG_SUPPRESS_WARNING_PUSH -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") -DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") - -DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") -DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") -DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") -DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") -DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") -DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") -DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") -DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") -DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") -DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") -DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") -DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") -DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") - -DOCTEST_MSVC_SUPPRESS_WARNING_PUSH -DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning -DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration -DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data -DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression -DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated -DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant -DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled -DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified -DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal -DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch -DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs -DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe -DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C -DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff -DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted -DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) -// static analysis -DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' -DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable -DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... -DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtor... -DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' - -DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN - -// required includes - will go only in one translation unit! -#include -#include -#include -// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 -#ifdef __BORLANDC__ -#include -#endif // __BORLANDC__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef DOCTEST_CONFIG_POSIX_SIGNALS -#include -#endif // DOCTEST_CONFIG_POSIX_SIGNALS -#include -#include -#include - -#ifdef DOCTEST_PLATFORM_MAC -#include -#include -#include -#endif // DOCTEST_PLATFORM_MAC - -#ifdef DOCTEST_PLATFORM_WINDOWS - -// defines for a leaner windows.h -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// not sure what AfxWin.h is for - here I do what Catch does -#ifdef __AFXDLL -#include -#else -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else // MINGW -#include -#endif // MINGW -#endif -#include - -#else // DOCTEST_PLATFORM_WINDOWS - -#include -#include - -#endif // DOCTEST_PLATFORM_WINDOWS - -// this is a fix for https://github.com/onqtam/doctest/issues/348 -// https://mail.gnome.org/archives/xml/2012-January/msg00000.html -#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) -#define STDOUT_FILENO fileno(stdout) -#endif // HAVE_UNISTD_H - -DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END - -// counts the number of elements in a C array -#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) - -#ifdef DOCTEST_CONFIG_DISABLE -#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled -#else // DOCTEST_CONFIG_DISABLE -#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled -#endif // DOCTEST_CONFIG_DISABLE - -#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX -#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" -#endif - -#ifndef DOCTEST_THREAD_LOCAL -#define DOCTEST_THREAD_LOCAL thread_local -#endif - -#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS -#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX -#else -#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" -#endif - -namespace doctest { - - bool is_running_in_test = false; - - namespace { - using namespace detail; - // case insensitive strcmp - int stricmp(const char* a, const char* b) { - for (;; a++, b++) { - const int d = tolower(*a) - tolower(*b); - if (d != 0 || !*a) - return d; - } - } - - template String fpToString(T value, int precision) { - std::ostringstream oss; - oss << std::setprecision(precision) << std::fixed << value; - std::string d = oss.str(); - size_t i = d.find_last_not_of('0'); - if (i != std::string::npos && i != d.size() - 1) { - if (d[i] == '.') - i++; - d = d.substr(0, i + 1); - } - return d.c_str(); - } - - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - int x = 1; - // casting any data pointer to char* is allowed - auto ptr = reinterpret_cast(&x); - if (*ptr) - return Little; - return Big; - } - }; - } // namespace - - namespace detail { - void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); } - - String rawMemoryToString(const void* object, unsigned size) { - // Reverse order for little endian architectures - int i = 0, end = static_cast(size), inc = 1; - if (Endianness::which() == Endianness::Little) { - i = end - 1; - end = inc = -1; - } - - unsigned const char* bytes = static_cast(object); - std::ostringstream oss; - oss << "0x" << std::setfill('0') << std::hex; - for (; i != end; i += inc) - oss << std::setw(2) << static_cast(bytes[i]); - return oss.str().c_str(); - } - - DOCTEST_THREAD_LOCAL std::ostringstream g_oss; // NOLINT(cert-err58-cpp) - - std::ostream* getTlsOss() { - g_oss.clear(); // there shouldn't be anything worth clearing in the flags - g_oss.str(""); // the slow way of resetting a string stream - // g_oss.seekp(0); // optimal reset - as seen here: https://stackoverflow.com/a/624291/3162383 - return &g_oss; - } - - String getTlsOssResult() { - // g_oss << std::ends; // needed - as shown here: https://stackoverflow.com/a/624291/3162383 - return g_oss.str().c_str(); - } - -#ifndef DOCTEST_CONFIG_DISABLE - - namespace timer_large_integer { - -#if defined(DOCTEST_PLATFORM_WINDOWS) - typedef ULONGLONG type; -#else // DOCTEST_PLATFORM_WINDOWS - using namespace std; - typedef uint64_t type; -#endif // DOCTEST_PLATFORM_WINDOWS - } - - typedef timer_large_integer::type ticks_t; - -#ifdef DOCTEST_CONFIG_GETCURRENTTICKS - ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } -#elif defined(DOCTEST_PLATFORM_WINDOWS) - ticks_t getCurrentTicks() { - static LARGE_INTEGER hz = {0}, hzo = {0}; - if (!hz.QuadPart) { - QueryPerformanceFrequency(&hz); - QueryPerformanceCounter(&hzo); - } - LARGE_INTEGER t; - QueryPerformanceCounter(&t); - return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; - } -#else // DOCTEST_PLATFORM_WINDOWS - ticks_t getCurrentTicks() { - timeval t; - gettimeofday(&t, nullptr); - return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); - } -#endif // DOCTEST_PLATFORM_WINDOWS - - struct Timer { - void start() { m_ticks = getCurrentTicks(); } - unsigned int getElapsedMicroseconds() const { - return static_cast(getCurrentTicks() - m_ticks); - } - // unsigned int getElapsedMilliseconds() const { - // return static_cast(getElapsedMicroseconds() / 1000); - //} - double getElapsedSeconds() const { return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; } - - private: - ticks_t m_ticks = 0; - }; - - // this holds both parameters from the command line and runtime data for tests - struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats { - std::atomic numAssertsCurrentTest_atomic; - std::atomic numAssertsFailedCurrentTest_atomic; - - std::vector> filters = decltype(filters)(9); // 9 different filters - - std::vector reporters_currently_used; - - const TestCase* currentTest = nullptr; - - assert_handler ah = nullptr; - - Timer timer; - - std::vector stringifiedContexts; // logging from INFO() due to an exception - - // stuff for subcases - std::vector subcasesStack; - std::set subcasesPassed; - int subcasesCurrentMaxLevel; - bool should_reenter; - std::atomic shouldLogCurrentException; - - void resetRunData() { - numTestCases = 0; - numTestCasesPassingFilters = 0; - numTestSuitesPassingFilters = 0; - numTestCasesFailed = 0; - numAsserts = 0; - numAssertsFailed = 0; - numAssertsCurrentTest = 0; - numAssertsFailedCurrentTest = 0; - } - - void finalizeTestCaseData() { - seconds = timer.getElapsedSeconds(); - - // update the non-atomic counters - numAsserts += numAssertsCurrentTest_atomic; - numAssertsFailed += numAssertsFailedCurrentTest_atomic; - numAssertsCurrentTest = numAssertsCurrentTest_atomic; - numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic; - - if (numAssertsFailedCurrentTest) - failure_flags |= TestCaseFailureReason::AssertFailure; - - if (Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && - Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout) - failure_flags |= TestCaseFailureReason::Timeout; - - if (currentTest->m_should_fail) { - if (failure_flags) { - failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid; - } else { - failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt; - } - } else if (failure_flags && currentTest->m_may_fail) { - failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid; - } else if (currentTest->m_expected_failures > 0) { - if (numAssertsFailedCurrentTest == currentTest->m_expected_failures) { - failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes; - } else { - failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes; - } - } - - bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) || - (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) || - (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); - - // if any subcase has failed - the whole test case has failed - if (failure_flags && !ok_to_fail) - numTestCasesFailed++; - } - }; - - ContextState* g_cs = nullptr; - - // used to avoid locks for the debug output - // TODO: figure out if this is indeed necessary/correct - seems like either there still - // could be a race or that there wouldn't be a race even if using the context directly - DOCTEST_THREAD_LOCAL bool g_no_colors; - -#endif // DOCTEST_CONFIG_DISABLE - } // namespace detail - - void String::setOnHeap() { *reinterpret_cast(&buf[last]) = 128; } - void String::setLast(unsigned in) { buf[last] = char(in); } - - void String::copy(const String& other) { - using namespace std; - if (other.isOnStack()) { - memcpy(buf, other.buf, len); - } else { - setOnHeap(); - data.size = other.data.size; - data.capacity = data.size + 1; - data.ptr = new char[data.capacity]; - memcpy(data.ptr, other.data.ptr, data.size + 1); - } - } - - String::String() { - buf[0] = '\0'; - setLast(); - } - - String::~String() { - if (!isOnStack()) - delete[] data.ptr; - } - - String::String(const char* in) : String(in, strlen(in)) {} - - String::String(const char* in, unsigned in_size) { - using namespace std; - if (in_size <= last) { - memcpy(buf, in, in_size + 1); - setLast(last - in_size); - } else { - setOnHeap(); - data.size = in_size; - data.capacity = data.size + 1; - data.ptr = new char[data.capacity]; - memcpy(data.ptr, in, in_size + 1); - } - } - - String::String(const String& other) { copy(other); } - - String& String::operator=(const String& other) { - if (this != &other) { - if (!isOnStack()) - delete[] data.ptr; - - copy(other); - } - - return *this; - } - - String& String::operator+=(const String& other) { - const unsigned my_old_size = size(); - const unsigned other_size = other.size(); - const unsigned total_size = my_old_size + other_size; - using namespace std; - if (isOnStack()) { - if (total_size < len) { - // append to the current stack space - memcpy(buf + my_old_size, other.c_str(), other_size + 1); - setLast(last - total_size); - } else { - // alloc new chunk - char* temp = new char[total_size + 1]; - // copy current data to new location before writing in the union - memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed - // update data in union - setOnHeap(); - data.size = total_size; - data.capacity = data.size + 1; - data.ptr = temp; - // transfer the rest of the data - memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); - } - } else { - if (data.capacity > total_size) { - // append to the current heap block - data.size = total_size; - memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); - } else { - // resize - data.capacity *= 2; - if (data.capacity <= total_size) - data.capacity = total_size + 1; - // alloc new chunk - char* temp = new char[data.capacity]; - // copy current data to new location before releasing it - memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed - // release old chunk - delete[] data.ptr; - // update the rest of the union members - data.size = total_size; - data.ptr = temp; - // transfer the rest of the data - memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); - } - } - - return *this; - } - - String String::operator+(const String& other) const { return String(*this) += other; } - - String::String(String&& other) { - using namespace std; - memcpy(buf, other.buf, len); - other.buf[0] = '\0'; - other.setLast(); - } - - String& String::operator=(String&& other) { - using namespace std; - if (this != &other) { - if (!isOnStack()) - delete[] data.ptr; - memcpy(buf, other.buf, len); - other.buf[0] = '\0'; - other.setLast(); - } - return *this; - } - - char String::operator[](unsigned i) const { - return const_cast(this)->operator[](i); // NOLINT - } - - char& String::operator[](unsigned i) { - if (isOnStack()) - return reinterpret_cast(buf)[i]; - return data.ptr[i]; - } - - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") - unsigned String::size() const { - if (isOnStack()) - return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32 - return data.size; - } - DOCTEST_GCC_SUPPRESS_WARNING_POP - - unsigned String::capacity() const { - if (isOnStack()) - return len; - return data.capacity; - } - - int String::compare(const char* other, bool no_case) const { - if (no_case) - return doctest::stricmp(c_str(), other); - return std::strcmp(c_str(), other); - } - - int String::compare(const String& other, bool no_case) const { return compare(other.c_str(), no_case); } - - // clang-format off -bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } -bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } -bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } -bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } -bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } -bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } - // clang-format on - - std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); } - - namespace { - void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) - } // namespace - - namespace Color { - std::ostream& operator<<(std::ostream& s, Color::Enum code) { - color_to_stream(s, code); - return s; - } - } // namespace Color - - // clang-format off -const char* assertString(assertType::Enum at) { - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4062) // enum 'x' in switch of enum 'y' is not handled - switch(at) { //!OCLINT missing default in switch statements - case assertType::DT_WARN : return "WARN"; - case assertType::DT_CHECK : return "CHECK"; - case assertType::DT_REQUIRE : return "REQUIRE"; - - case assertType::DT_WARN_FALSE : return "WARN_FALSE"; - case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; - case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; - - case assertType::DT_WARN_THROWS : return "WARN_THROWS"; - case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; - case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; - - case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; - case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; - case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; - - case assertType::DT_WARN_THROWS_WITH : return "WARN_THROWS_WITH"; - case assertType::DT_CHECK_THROWS_WITH : return "CHECK_THROWS_WITH"; - case assertType::DT_REQUIRE_THROWS_WITH : return "REQUIRE_THROWS_WITH"; - - case assertType::DT_WARN_THROWS_WITH_AS : return "WARN_THROWS_WITH_AS"; - case assertType::DT_CHECK_THROWS_WITH_AS : return "CHECK_THROWS_WITH_AS"; - case assertType::DT_REQUIRE_THROWS_WITH_AS : return "REQUIRE_THROWS_WITH_AS"; - - case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; - case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; - case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; - - case assertType::DT_WARN_EQ : return "WARN_EQ"; - case assertType::DT_CHECK_EQ : return "CHECK_EQ"; - case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; - case assertType::DT_WARN_NE : return "WARN_NE"; - case assertType::DT_CHECK_NE : return "CHECK_NE"; - case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; - case assertType::DT_WARN_GT : return "WARN_GT"; - case assertType::DT_CHECK_GT : return "CHECK_GT"; - case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; - case assertType::DT_WARN_LT : return "WARN_LT"; - case assertType::DT_CHECK_LT : return "CHECK_LT"; - case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; - case assertType::DT_WARN_GE : return "WARN_GE"; - case assertType::DT_CHECK_GE : return "CHECK_GE"; - case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; - case assertType::DT_WARN_LE : return "WARN_LE"; - case assertType::DT_CHECK_LE : return "CHECK_LE"; - case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; - - case assertType::DT_WARN_UNARY : return "WARN_UNARY"; - case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; - case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; - case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; - case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; - case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; - } - DOCTEST_MSVC_SUPPRESS_WARNING_POP - return ""; -} - // clang-format on - - const char* failureString(assertType::Enum at) { - if (at & assertType::is_warn) //! OCLINT bitwise operator in conditional - return "WARNING"; - if (at & assertType::is_check) //! OCLINT bitwise operator in conditional - return "ERROR"; - if (at & assertType::is_require) //! OCLINT bitwise operator in conditional - return "FATAL ERROR"; - return ""; - } - - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") - // depending on the current options this will remove the path of filenames - const char* skipPathFromFilename(const char* file) { - if (getContextOptions()->no_path_in_filenames) { - auto back = std::strrchr(file, '\\'); - auto forward = std::strrchr(file, '/'); - if (back || forward) { - if (back > forward) - forward = back; - return forward + 1; - } - } - return file; - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - - bool SubcaseSignature::operator<(const SubcaseSignature& other) const { - if (m_line != other.m_line) - return m_line < other.m_line; - if (std::strcmp(m_file, other.m_file) != 0) - return std::strcmp(m_file, other.m_file) < 0; - return m_name.compare(other.m_name) < 0; - } - - IContextScope::IContextScope() = default; - IContextScope::~IContextScope() = default; - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - String toString(char* in) { return toString(static_cast(in)); } - String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - String toString(bool in) { return in ? "true" : "false"; } - String toString(float in) { return fpToString(in, 5) + "f"; } - String toString(double in) { return fpToString(in, 10); } - String toString(double long in) { return fpToString(in, 15); } - -#define DOCTEST_TO_STRING_OVERLOAD(type, fmt) \ - String toString(type in) { \ - char buf[64]; \ - std::sprintf(buf, fmt, in); \ - return buf; \ - } - - DOCTEST_TO_STRING_OVERLOAD(char, "%d") - DOCTEST_TO_STRING_OVERLOAD(char signed, "%d") - DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u") - DOCTEST_TO_STRING_OVERLOAD(int short, "%d") - DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u") - DOCTEST_TO_STRING_OVERLOAD(int, "%d") - DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u") - DOCTEST_TO_STRING_OVERLOAD(int long, "%ld") - DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu") - DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld") - DOCTEST_TO_STRING_OVERLOAD(int long long unsigned, "%llu") - - String toString(std::nullptr_t) { return "NULL"; } - -#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) - // see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 - String toString(const std::string& in) { return in.c_str(); } -#endif // VS 2019 - - Approx::Approx(double value) - : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100), m_scale(1.0), m_value(value) {} - - Approx Approx::operator()(double value) const { - Approx approx(value); - approx.epsilon(m_epsilon); - approx.scale(m_scale); - return approx; - } - - Approx& Approx::epsilon(double newEpsilon) { - m_epsilon = newEpsilon; - return *this; - } - Approx& Approx::scale(double newScale) { - m_scale = newScale; - return *this; - } - - bool operator==(double lhs, const Approx& rhs) { - // Thanks to Richard Harris for his help refining this formula - return std::fabs(lhs - rhs.m_value) < - rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); - } - bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); } - bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } - bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); } - bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; } - bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } - bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; } - bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } - bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; } - bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } - bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; } - bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } - - String toString(const Approx& in) { return String("Approx( ") + doctest::toString(in.m_value) + " )"; } - const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } - -} // namespace doctest - -#ifdef DOCTEST_CONFIG_DISABLE -namespace doctest { - Context::Context(int, const char* const*) {} - Context::~Context() = default; - void Context::applyCommandLine(int, const char* const*) {} - void Context::addFilter(const char*, const char*) {} - void Context::clearFilters() {} - void Context::setOption(const char*, int) {} - void Context::setOption(const char*, const char*) {} - bool Context::shouldExit() { return false; } - void Context::setAsDefaultForAssertsOutOfTestCases() {} - void Context::setAssertHandler(detail::assert_handler) {} - int Context::run() { return 0; } - - IReporter::~IReporter() = default; - - int IReporter::get_num_active_contexts() { return 0; } - const IContextScope* const* IReporter::get_active_contexts() { return nullptr; } - int IReporter::get_num_stringified_contexts() { return 0; } - const String* IReporter::get_stringified_contexts() { return nullptr; } - - int registerReporter(const char*, int, IReporter*) { return 0; } - -} // namespace doctest -#else // DOCTEST_CONFIG_DISABLE - -#if !defined(DOCTEST_CONFIG_COLORS_NONE) -#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) -#ifdef DOCTEST_PLATFORM_WINDOWS -#define DOCTEST_CONFIG_COLORS_WINDOWS -#else // linux -#define DOCTEST_CONFIG_COLORS_ANSI -#endif // platform -#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI -#endif // DOCTEST_CONFIG_COLORS_NONE - -namespace doctest_detail_test_suite_ns { - // holds the current test suite - doctest::detail::TestSuite& getCurrentTestSuite() { - static doctest::detail::TestSuite data; - return data; - } -} // namespace doctest_detail_test_suite_ns - -namespace doctest { - namespace { - // the int (priority) is part of the key for automatic sorting - sadly one can register a - // reporter with a duplicate name and a different priority but hopefully that won't happen often :| - typedef std::map, reporterCreatorFunc> reporterMap; - - reporterMap& getReporters() { - static reporterMap data; - return data; - } - reporterMap& getListeners() { - static reporterMap data; - return data; - } - } // namespace - namespace detail { -#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ - for (auto& curr_rep : g_cs->reporters_currently_used) \ - curr_rep->function(__VA_ARGS__) - - bool checkIfShouldThrow(assertType::Enum at) { - if (at & assertType::is_require) //! OCLINT bitwise operator in conditional - return true; - - if ((at & assertType::is_check) //! OCLINT bitwise operator in conditional - && getContextOptions()->abort_after > 0 && - (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >= getContextOptions()->abort_after) - return true; - - return false; - } - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - DOCTEST_NORETURN void throwException() { - g_cs->shouldLogCurrentException = false; - throw TestFailureException(); - } // NOLINT(cert-err60-cpp) -#else // DOCTEST_CONFIG_NO_EXCEPTIONS - void throwException() {} -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } // namespace detail - - namespace { - using namespace detail; - // matching of a string against a wildcard mask (case sensitivity configurable) taken from - // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing - int wildcmp(const char* str, const char* wild, bool caseSensitive) { - const char* cp = str; - const char* mp = wild; - - while ((*str) && (*wild != '*')) { - if ((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && (*wild != '?')) { - return 0; - } - wild++; - str++; - } - - while (*str) { - if (*wild == '*') { - if (!*++wild) { - return 1; - } - mp = wild; - cp = str + 1; - } else if ((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || (*wild == '?')) { - wild++; - str++; - } else { - wild = mp; //! OCLINT parameter reassignment - str = cp++; //! OCLINT parameter reassignment - } - } - - while (*wild == '*') { - wild++; - } - return !*wild; - } - - //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html - // unsigned hashStr(unsigned const char* str) { - // unsigned long hash = 5381; - // char c; - // while((c = *str++)) - // hash = ((hash << 5) + hash) + c; // hash * 33 + c - // return hash; - //} - - // checks if the name matches any of the filters (and can be configured what to do when empty) - bool matchesAny(const char* name, const std::vector& filters, bool matchEmpty, bool caseSensitive) { - if (filters.empty() && matchEmpty) - return true; - for (auto& curr : filters) - if (wildcmp(name, curr.c_str(), caseSensitive)) - return true; - return false; - } - } // namespace - namespace detail { - - Subcase::Subcase(const String& name, const char* file, int line) : m_signature({name, file, line}) { - ContextState* s = g_cs; - - // check subcase filters - if (s->subcasesStack.size() < size_t(s->subcase_filter_levels)) { - if (!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive)) - return; - if (matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive)) - return; - } - - // if a Subcase on the same level has already been entered - if (s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) { - s->should_reenter = true; - return; - } - - // push the current signature to the stack so we can check if the - // current stack + the current new subcase have been traversed - s->subcasesStack.push_back(m_signature); - if (s->subcasesPassed.count(s->subcasesStack) != 0) { - // pop - revert to previous stack since we've already passed this - s->subcasesStack.pop_back(); - return; - } - - s->subcasesCurrentMaxLevel = s->subcasesStack.size(); - m_entered = true; - - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); - } - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - - Subcase::~Subcase() { - if (m_entered) { - // only mark the subcase stack as passed if no subcases have been skipped - if (g_cs->should_reenter == false) - g_cs->subcasesPassed.insert(g_cs->subcasesStack); - g_cs->subcasesStack.pop_back(); - -#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L - if (std::uncaught_exceptions() > 0 -#else - if (std::uncaught_exception() -#endif - && g_cs->shouldLogCurrentException) { - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, - {"exception thrown in subcase - will translate later " - "when the whole test case has been exited (cannot " - "translate while there is an active exception)", - false}); - g_cs->shouldLogCurrentException = false; - } - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); - } - } - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP - - Subcase::operator bool() const { return m_entered; } - - Result::Result(bool passed, const String& decomposition) : m_passed(passed), m_decomp(decomposition) {} - - ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) : m_at(at) {} - - TestSuite& TestSuite::operator*(const char* in) { - m_test_suite = in; - // clear state - m_description = nullptr; - m_skip = false; - m_may_fail = false; - m_should_fail = false; - m_expected_failures = 0; - m_timeout = 0; - return *this; - } - - TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, - const char* type, int template_id) { - m_file = file; - m_line = line; - m_name = nullptr; // will be later overridden in operator* - m_test_suite = test_suite.m_test_suite; - m_description = test_suite.m_description; - m_skip = test_suite.m_skip; - m_may_fail = test_suite.m_may_fail; - m_should_fail = test_suite.m_should_fail; - m_expected_failures = test_suite.m_expected_failures; - m_timeout = test_suite.m_timeout; - - m_test = test; - m_type = type; - m_template_id = template_id; - } - - TestCase::TestCase(const TestCase& other) : TestCaseData() { *this = other; } - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function - DOCTEST_MSVC_SUPPRESS_WARNING(26437) // Do not slice - TestCase& TestCase::operator=(const TestCase& other) { - static_cast(*this) = static_cast(other); - - m_test = other.m_test; - m_type = other.m_type; - m_template_id = other.m_template_id; - m_full_name = other.m_full_name; - - if (m_template_id != -1) - m_name = m_full_name.c_str(); - return *this; - } - DOCTEST_MSVC_SUPPRESS_WARNING_POP - - TestCase& TestCase::operator*(const char* in) { - m_name = in; - // make a new name with an appended type for templated test case - if (m_template_id != -1) { - m_full_name = String(m_name) + m_type; - // redirect the name to point to the newly constructed full name - m_name = m_full_name.c_str(); - } - return *this; - } - - bool TestCase::operator<(const TestCase& other) const { - if (m_line != other.m_line) - return m_line < other.m_line; - const int file_cmp = m_file.compare(other.m_file); - if (file_cmp != 0) - return file_cmp < 0; - return m_template_id < other.m_template_id; - } - } // namespace detail - namespace { - using namespace detail; - // for sorting tests by file/line - bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) { - // this is needed because MSVC gives different case for drive letters - // for __FILE__ when evaluated in a header and a source file - const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC)); - if (res != 0) - return res < 0; - if (lhs->m_line != rhs->m_line) - return lhs->m_line < rhs->m_line; - return lhs->m_template_id < rhs->m_template_id; - } - - // for sorting tests by suite/file/line - bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) { - const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); - if (res != 0) - return res < 0; - return fileOrderComparator(lhs, rhs); - } - - // for sorting tests by name/suite/file/line - bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) { - const int res = std::strcmp(lhs->m_name, rhs->m_name); - if (res != 0) - return res < 0; - return suiteOrderComparator(lhs, rhs); - } - - // all the registered tests - std::set& getRegisteredTests() { - static std::set data; - return data; - } - -#ifdef DOCTEST_CONFIG_COLORS_WINDOWS - HANDLE g_stdoutHandle; - WORD g_origFgAttrs; - WORD g_origBgAttrs; - bool g_attrsInitted = false; - - int colors_init() { - if (!g_attrsInitted) { - g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); - g_attrsInitted = true; - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo); - g_origFgAttrs = csbiInfo.wAttributes & - ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY); - g_origBgAttrs = csbiInfo.wAttributes & - ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY); - } - return 0; - } - - int dumy_init_console_colors = colors_init(); -#endif // DOCTEST_CONFIG_COLORS_WINDOWS - - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - void color_to_stream(std::ostream& s, Color::Enum code) { - ((void)s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS - ((void)code); // for DOCTEST_CONFIG_COLORS_NONE -#ifdef DOCTEST_CONFIG_COLORS_ANSI - if (g_no_colors || (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) - return; - - auto col = ""; - // clang-format off - switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement - case Color::Red: col = "[0;31m"; break; - case Color::Green: col = "[0;32m"; break; - case Color::Blue: col = "[0;34m"; break; - case Color::Cyan: col = "[0;36m"; break; - case Color::Yellow: col = "[0;33m"; break; - case Color::Grey: col = "[1;30m"; break; - case Color::LightGrey: col = "[0;37m"; break; - case Color::BrightRed: col = "[1;31m"; break; - case Color::BrightGreen: col = "[1;32m"; break; - case Color::BrightWhite: col = "[1;37m"; break; - case Color::Bright: // invalid - case Color::None: - case Color::White: - default: col = "[0m"; - } - // clang-format on - s << "\033" << col; -#endif // DOCTEST_CONFIG_COLORS_ANSI - -#ifdef DOCTEST_CONFIG_COLORS_WINDOWS - if (g_no_colors || (isatty(fileno(stdout)) == false && getContextOptions()->force_colors == false)) - return; - -#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | g_origBgAttrs) - - // clang-format off - switch (code) { - case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; - case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; - case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; - case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; - case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; - case Color::Grey: DOCTEST_SET_ATTR(0); break; - case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; - case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; - case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; - case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; - case Color::None: - case Color::Bright: // invalid - default: DOCTEST_SET_ATTR(g_origFgAttrs); - } - // clang-format on -#endif // DOCTEST_CONFIG_COLORS_WINDOWS - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - - std::vector& getExceptionTranslators() { - static std::vector data; - return data; - } - - String translateActiveException() { -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - String res; - auto& translators = getExceptionTranslators(); - for (auto& curr : translators) - if (curr->translate(res)) - return res; - // clang-format off - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") - try { - throw; - } catch(std::exception& ex) { - return ex.what(); - } catch(std::string& msg) { - return msg.c_str(); - } catch(const char* msg) { - return msg; - } catch(...) { - return "unknown exception"; - } - DOCTEST_GCC_SUPPRESS_WARNING_POP -// clang-format on -#else // DOCTEST_CONFIG_NO_EXCEPTIONS - return ""; -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } - } // namespace - - namespace detail { - // used by the macros for registering tests - int regTest(const TestCase& tc) { - getRegisteredTests().insert(tc); - return 0; - } - - // sets the current test suite - int setTestSuite(const TestSuite& ts) { - doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; - return 0; - } - -#ifdef DOCTEST_IS_DEBUGGER_ACTIVE - bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); } -#else // DOCTEST_IS_DEBUGGER_ACTIVE -#ifdef DOCTEST_PLATFORM_MAC - // The following function is taken directly from the following technical note: - // https://developer.apple.com/library/archive/qa/qa1361/_index.html - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive() { - int mib[4]; - kinfo_proc info; - size_t size; - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - info.kp_proc.p_flag = 0; - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - // Call sysctl. - size = sizeof(info); - if (sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { - std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; - return false; - } - // We're being debugged if the P_TRACED flag is set. - return ((info.kp_proc.p_flag & P_TRACED) != 0); - } -#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) - bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } -#else - bool isDebuggerActive() { return false; } -#endif // Platform -#endif // DOCTEST_IS_DEBUGGER_ACTIVE - - void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { - if (std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == - getExceptionTranslators().end()) - getExceptionTranslators().push_back(et); - } - -#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - void toStream(std::ostream* s, char* in) { *s << in; } - void toStream(std::ostream* s, const char* in) { *s << in; } -#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING - void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; } - void toStream(std::ostream* s, float in) { *s << in; } - void toStream(std::ostream* s, double in) { *s << in; } - void toStream(std::ostream* s, double long in) { *s << in; } - - void toStream(std::ostream* s, char in) { *s << in; } - void toStream(std::ostream* s, char signed in) { *s << in; } - void toStream(std::ostream* s, char unsigned in) { *s << in; } - void toStream(std::ostream* s, int short in) { *s << in; } - void toStream(std::ostream* s, int short unsigned in) { *s << in; } - void toStream(std::ostream* s, int in) { *s << in; } - void toStream(std::ostream* s, int unsigned in) { *s << in; } - void toStream(std::ostream* s, int long in) { *s << in; } - void toStream(std::ostream* s, int long unsigned in) { *s << in; } - void toStream(std::ostream* s, int long long in) { *s << in; } - void toStream(std::ostream* s, int long long unsigned in) { *s << in; } - - DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() - - ContextScopeBase::ContextScopeBase() { g_infoContexts.push_back(this); } - - DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 - DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - - // destroy cannot be inlined into the destructor because that would mean calling stringify after - // ContextScope has been destroyed (base class destructors run after derived class destructors). - // Instead, ContextScope calls this method directly from its destructor. - void ContextScopeBase::destroy() { -#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L - if (std::uncaught_exceptions() > 0) { -#else - if (std::uncaught_exception()) { -#endif - std::ostringstream s; - this->stringify(&s); - g_cs->stringifiedContexts.push_back(s.str().c_str()); - } - g_infoContexts.pop_back(); - } - - DOCTEST_CLANG_SUPPRESS_WARNING_POP - DOCTEST_GCC_SUPPRESS_WARNING_POP - DOCTEST_MSVC_SUPPRESS_WARNING_POP - } // namespace detail - namespace { - using namespace detail; - -#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) - struct FatalConditionHandler { - void reset() {} - }; -#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - - void reportFatal(const std::string&); - -#ifdef DOCTEST_PLATFORM_WINDOWS - - struct SignalDefs { - DWORD id; - const char* name; - }; - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - SignalDefs signalDefs[] = { - {EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal"}, - {EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow"}, - {EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal"}, - {EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error"}, - }; - - struct FatalConditionHandler { - static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) { - for (size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { - reportFatal(signalDefs[i].name); - break; - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } - - FatalConditionHandler() { - isSet = true; - // 32k seems enough for doctest to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - // Register an unhandled exception filter - previousTop = SetUnhandledExceptionFilter(handleException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } - - static void reset() { - if (isSet) { - // Unregister handler and restore the old guarantee - SetUnhandledExceptionFilter(previousTop); - SetThreadStackGuarantee(&guaranteeSize); - previousTop = nullptr; - isSet = false; - } - } - - ~FatalConditionHandler() { reset(); } - - private: - static bool isSet; - static ULONG guaranteeSize; - static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; - }; - - bool FatalConditionHandler::isSet = false; - ULONG FatalConditionHandler::guaranteeSize = 0; - LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; - -#else // DOCTEST_PLATFORM_WINDOWS - - struct SignalDefs { - int id; - const char* name; - }; - SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"}, - {SIGILL, "SIGILL - Illegal instruction signal"}, - {SIGFPE, "SIGFPE - Floating point error signal"}, - {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, - {SIGTERM, "SIGTERM - Termination request signal"}, - {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}}; - - struct FatalConditionHandler { - static bool isSet; - static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; - static stack_t oldSigStack; - static char altStackMem[4 * SIGSTKSZ]; - - static void handleSignal(int sig) { - const char* name = ""; - for (std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - SignalDefs& def = signalDefs[i]; - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise(sig); - } - - FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = sizeof(altStackMem); - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = {}; - sa.sa_handler = handleSignal; // NOLINT - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - ~FatalConditionHandler() { reset(); } - static void reset() { - if (isSet) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for (std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - }; - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[] = {}; - -#endif // DOCTEST_PLATFORM_WINDOWS -#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - - } // namespace - - namespace { - using namespace detail; - -#ifdef DOCTEST_PLATFORM_WINDOWS -#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) -#else - // TODO: integration with XCode and other IDEs -#define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros) -#endif // Platform - - void addAssert(assertType::Enum at) { - if ((at & assertType::is_warn) == 0) //! OCLINT bitwise operator in conditional - g_cs->numAssertsCurrentTest_atomic++; - } - - void addFailedAssert(assertType::Enum at) { - if ((at & assertType::is_warn) == 0) //! OCLINT bitwise operator in conditional - g_cs->numAssertsFailedCurrentTest_atomic++; - } - -#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) - void reportFatal(const std::string& message) { - g_cs->failure_flags |= TestCaseFailureReason::Crash; - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); - - while (g_cs->subcasesStack.size()) { - g_cs->subcasesStack.pop_back(); - DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); - } - - g_cs->finalizeTestCaseData(); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); - } -#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH - } // namespace - namespace detail { - - ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, - const char* exception_type, const char* exception_string) { - m_test_case = g_cs->currentTest; - m_at = at; - m_file = file; - m_line = line; - m_expr = expr; - m_failed = true; - m_threw = false; - m_threw_as = false; - m_exception_type = exception_type; - m_exception_string = exception_string; -#if DOCTEST_MSVC - if (m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC - ++m_expr; -#endif // MSVC - } - - void ResultBuilder::setResult(const Result& res) { - m_decomp = res.m_decomp; - m_failed = !res.m_passed; - } - - void ResultBuilder::translateException() { - m_threw = true; - m_exception = translateActiveException(); - } - - bool ResultBuilder::log() { - if (m_at & assertType::is_throws) { //! OCLINT bitwise operator in conditional - m_failed = !m_threw; - } else if ((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //! OCLINT - m_failed = !m_threw_as || (m_exception != m_exception_string); - } else if (m_at & assertType::is_throws_as) { //! OCLINT bitwise operator in conditional - m_failed = !m_threw_as; - } else if (m_at & assertType::is_throws_with) { //! OCLINT bitwise operator in conditional - m_failed = m_exception != m_exception_string; - } else if (m_at & assertType::is_nothrow) { //! OCLINT bitwise operator in conditional - m_failed = m_threw; - } - - if (m_exception.size()) - m_exception = String("\"") + m_exception + "\""; - - if (is_running_in_test) { - addAssert(m_at); - DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this); - - if (m_failed) - addFailedAssert(m_at); - } else if (m_failed) { - failed_out_of_a_testing_context(*this); - } - - return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks; // break into debugger - } - - void ResultBuilder::react() const { - if (m_failed && checkIfShouldThrow(m_at)) - throwException(); - } - - void failed_out_of_a_testing_context(const AssertData& ad) { - if (g_cs->ah) - g_cs->ah(ad); - else - std::abort(); - } - - void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, Result result) { - bool failed = !result.m_passed; - - // ################################################################################### - // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT - // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED - // ################################################################################### - DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); - DOCTEST_ASSERT_IN_TESTS(result.m_decomp); - } - - MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { - m_stream = getTlsOss(); - m_file = file; - m_line = line; - m_severity = severity; - } - - IExceptionTranslator::IExceptionTranslator() = default; - IExceptionTranslator::~IExceptionTranslator() = default; - - bool MessageBuilder::log() { - m_string = getTlsOssResult(); - DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); - - const bool isWarn = m_severity & assertType::is_warn; - - // warn is just a message in this context so we don't treat it as an assert - if (!isWarn) { - addAssert(m_severity); - addFailedAssert(m_severity); - } - - return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn; // break - } - - void MessageBuilder::react() { - if (m_severity & assertType::is_require) //! OCLINT bitwise operator in conditional - throwException(); - } - - MessageBuilder::~MessageBuilder() = default; - } // namespace detail - namespace { - using namespace detail; - - template DOCTEST_NORETURN void throw_exception(Ex const& e) { -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - throw e; -#else // DOCTEST_CONFIG_NO_EXCEPTIONS - std::cerr << "doctest will terminate because it needed to throw an exception.\n" - << "The message was: " << e.what() << '\n'; - std::terminate(); -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - } - -#ifndef DOCTEST_INTERNAL_ERROR -#define DOCTEST_INTERNAL_ERROR(msg) \ - throw_exception(std::logic_error(__FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) -#endif // DOCTEST_INTERNAL_ERROR - - // clang-format off - -// ================================================================================================= -// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp -// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. -// ================================================================================================= - - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; - ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = std::cout ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, const char* attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - std::stringstream rss; - rss << attribute; - return writeAttribute( name, rss.str() ); - } - - XmlWriter& writeText( std::string const& text, bool indent = true ); - - //XmlWriter& writeComment( std::string const& text ); - - //void writeStylesheetRef( std::string const& url ); - - //XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - }; - -// ================================================================================================= -// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp -// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. -// ================================================================================================= - -using uchar = unsigned char; - -namespace { - - size_t trailingBytes(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return 2; - } - if ((c & 0xF0) == 0xE0) { - return 3; - } - if ((c & 0xF8) == 0xF0) { - return 4; - } - DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - uint32_t headerValue(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return c & 0x1F; - } - if ((c & 0xF0) == 0xE0) { - return c & 0x0F; - } - if ((c & 0xF8) == 0xF0) { - return c & 0x07; - } - DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - void hexEscapeChar(std::ostream& os, unsigned char c) { - std::ios_base::fmtflags f(os.flags()); - os << "\\x" - << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast(c); - os.flags(f); - } - -} // anonymous namespace - - XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) - : m_str( str ), - m_forWhat( forWhat ) - {} - - void XmlEncode::encodeTo( std::ostream& os ) const { - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: https://www.w3.org/TR/xml/#syntax) - - for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; - switch (c) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: https://www.w3.org/TR/xml/#syntax - if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') - os << ">"; - else - os << c; - break; - - case '\"': - if (m_forWhat == ForAttributes) - os << """; - else - os << c; - break; - - default: - // Check for control characters and invalid utf-8 - - // Escape control characters in standard ascii - // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { - hexEscapeChar(os, c); - break; - } - - // Plain ASCII: Write it to stream - if (c < 0x7F) { - os << c; - break; - } - - // UTF-8 territory - // Check if the encoding is valid and if it is not, hex escape bytes. - // Important: We do not check the exact decoded values for validity, only the encoding format - // First check that this bytes is a valid lead byte: - // This means that it is not encoded as 1111 1XXX - // Or as 10XX XXXX - if (c < 0xC0 || - c >= 0xF8) { - hexEscapeChar(os, c); - break; - } - - auto encBytes = trailingBytes(c); - // Are there enough bytes left to avoid accessing out-of-bounds memory? - if (idx + encBytes - 1 >= m_str.size()) { - hexEscapeChar(os, c); - break; - } - // The header is valid, check data - // The next encBytes bytes must together be a valid utf-8 - // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) - bool valid = true; - uint32_t value = headerValue(c); - for (std::size_t n = 1; n < encBytes; ++n) { - uchar nc = m_str[idx + n]; - valid &= ((nc & 0xC0) == 0x80); - value = (value << 6) | (nc & 0x3F); - } - - if ( - // Wrong bit pattern of following bytes - (!valid) || - // Overlong encodings - (value < 0x80) || - ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant - (0x800 < value && value < 0x10000 && encBytes > 3) || - // Encoded value out of range - (value >= 0x110000) - ) { - hexEscapeChar(os, c); - break; - } - - // If we got here, this is in fact a valid(ish) utf-8 sequence - for (std::size_t n = 0; n < encBytes; ++n) { - os << m_str[idx + n]; - } - idx += encBytes - 1; - break; - } - } - } - - std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } - - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - return *this; - } - - - XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); - return *this; - } - - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } - - XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - - XmlWriter& XmlWriter::startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) { - if( !name.empty() && attribute && attribute[0] != '\0' ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } - - //XmlWriter& XmlWriter::writeComment( std::string const& text ) { - // ensureTagClosed(); - // m_os << m_indent << ""; - // m_needsNewline = true; - // return *this; - //} - - //void XmlWriter::writeStylesheetRef( std::string const& url ) { - // m_os << "\n"; - //} - - //XmlWriter& XmlWriter::writeBlankLine() { - // ensureTagClosed(); - // m_os << '\n'; - // return *this; - //} - - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } - - void XmlWriter::writeDeclaration() { - m_os << "\n"; - } - - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } - -// ================================================================================================= -// End of copy-pasted code from Catch -// ================================================================================================= - - // clang-format on - - struct XmlReporter : public IReporter { - XmlWriter xml; - std::mutex mutex; - - // caching pointers/references to objects of these types - safe to do - const ContextOptions& opt; - const TestCaseData* tc = nullptr; - - XmlReporter(const ContextOptions& co) : xml(*co.cout), opt(co) {} - - void log_contexts() { - int num_contexts = get_num_active_contexts(); - if (num_contexts) { - auto contexts = get_active_contexts(); - std::stringstream ss; - for (int i = 0; i < num_contexts; ++i) { - contexts[i]->stringify(&ss); - xml.scopedElement("Info").writeText(ss.str()); - ss.str(""); - } - } - } - - unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } - - void test_case_start_impl(const TestCaseData& in) { - bool open_ts_tag = false; - if (tc != nullptr) { // we have already opened a test suite - if (std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { - xml.endElement(); - open_ts_tag = true; - } - } else { - open_ts_tag = true; // first test case ==> first test suite - } - - if (open_ts_tag) { - xml.startElement("TestSuite"); - xml.writeAttribute("name", in.m_test_suite); - } - - tc = ∈ - xml.startElement("TestCase") - .writeAttribute("name", in.m_name) - .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) - .writeAttribute("line", line(in.m_line)) - .writeAttribute("description", in.m_description); - - if (Approx(in.m_timeout) != 0) - xml.writeAttribute("timeout", in.m_timeout); - if (in.m_may_fail) - xml.writeAttribute("may_fail", true); - if (in.m_should_fail) - xml.writeAttribute("should_fail", true); - } - - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= - - void report_query(const QueryData& in) override { - test_run_start(); - if (opt.list_reporters) { - for (auto& curr : getListeners()) - xml.scopedElement("Listener") - .writeAttribute("priority", curr.first.first) - .writeAttribute("name", curr.first.second); - for (auto& curr : getReporters()) - xml.scopedElement("Reporter") - .writeAttribute("priority", curr.first.first) - .writeAttribute("name", curr.first.second); - } else if (opt.count || opt.list_test_cases) { - for (unsigned i = 0; i < in.num_data; ++i) { - xml.scopedElement("TestCase") - .writeAttribute("name", in.data[i]->m_name) - .writeAttribute("testsuite", in.data[i]->m_test_suite) - .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) - .writeAttribute("line", line(in.data[i]->m_line)); - } - xml.scopedElement("OverallResultsTestCases") - .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); - } else if (opt.list_test_suites) { - for (unsigned i = 0; i < in.num_data; ++i) - xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); - xml.scopedElement("OverallResultsTestCases") - .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); - xml.scopedElement("OverallResultsTestSuites") - .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters); - } - xml.endElement(); - } - - void test_run_start() override { - // remove .exe extension - mainly to have the same output on UNIX and Windows - std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); -#ifdef DOCTEST_PLATFORM_WINDOWS - if (binary_name.rfind(".exe") != std::string::npos) - binary_name = binary_name.substr(0, binary_name.length() - 4); -#endif // DOCTEST_PLATFORM_WINDOWS - - xml.startElement("doctest").writeAttribute("binary", binary_name); - if (opt.no_version == false) - xml.writeAttribute("version", DOCTEST_VERSION_STR); - - // only the consequential ones (TODO: filters) - xml.scopedElement("Options") - .writeAttribute("order_by", opt.order_by.c_str()) - .writeAttribute("rand_seed", opt.rand_seed) - .writeAttribute("first", opt.first) - .writeAttribute("last", opt.last) - .writeAttribute("abort_after", opt.abort_after) - .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels) - .writeAttribute("case_sensitive", opt.case_sensitive) - .writeAttribute("no_throw", opt.no_throw) - .writeAttribute("no_skip", opt.no_skip); - } - - void test_run_end(const TestRunStats& p) override { - if (tc) // the TestSuite tag - only if there has been at least 1 test case - xml.endElement(); - - xml.scopedElement("OverallResultsAsserts") - .writeAttribute("successes", p.numAsserts - p.numAssertsFailed) - .writeAttribute("failures", p.numAssertsFailed); - - xml.startElement("OverallResultsTestCases") - .writeAttribute("successes", p.numTestCasesPassingFilters - p.numTestCasesFailed) - .writeAttribute("failures", p.numTestCasesFailed); - if (opt.no_skipped_summary == false) - xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters); - xml.endElement(); - - xml.endElement(); - } - - void test_case_start(const TestCaseData& in) override { - test_case_start_impl(in); - xml.ensureTagClosed(); - } - - void test_case_reenter(const TestCaseData&) override {} - - void test_case_end(const CurrentTestCaseStats& st) override { - xml.startElement("OverallResultsAsserts") - .writeAttribute("successes", st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) - .writeAttribute("failures", st.numAssertsFailedCurrentTest); - if (opt.duration) - xml.writeAttribute("duration", st.seconds); - if (tc->m_expected_failures) - xml.writeAttribute("expected_failures", tc->m_expected_failures); - xml.endElement(); - - xml.endElement(); - } - - void test_case_exception(const TestCaseException& e) override { - std::lock_guard lock(mutex); - - xml.scopedElement("Exception").writeAttribute("crash", e.is_crash).writeText(e.error_string.c_str()); - } - - void subcase_start(const SubcaseSignature& in) override { - std::lock_guard lock(mutex); - - xml.startElement("SubCase") - .writeAttribute("name", in.m_name) - .writeAttribute("filename", skipPathFromFilename(in.m_file)) - .writeAttribute("line", line(in.m_line)); - xml.ensureTagClosed(); - } - - void subcase_end() override { xml.endElement(); } - - void log_assert(const AssertData& rb) override { - if (!rb.m_failed && !opt.success) - return; - - std::lock_guard lock(mutex); - - xml.startElement("Expression") - .writeAttribute("success", !rb.m_failed) - .writeAttribute("type", assertString(rb.m_at)) - .writeAttribute("filename", skipPathFromFilename(rb.m_file)) - .writeAttribute("line", line(rb.m_line)); - - xml.scopedElement("Original").writeText(rb.m_expr); - - if (rb.m_threw) - xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); - - if (rb.m_at & assertType::is_throws_as) - xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); - if (rb.m_at & assertType::is_throws_with) - xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string); - if ((rb.m_at & assertType::is_normal) && !rb.m_threw) - xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); - - log_contexts(); - - xml.endElement(); - } - - void log_message(const MessageData& mb) override { - std::lock_guard lock(mutex); - - xml.startElement("Message") - .writeAttribute("type", failureString(mb.m_severity)) - .writeAttribute("filename", skipPathFromFilename(mb.m_file)) - .writeAttribute("line", line(mb.m_line)); - - xml.scopedElement("Text").writeText(mb.m_string.c_str()); - - log_contexts(); - - xml.endElement(); - } - - void test_case_skipped(const TestCaseData& in) override { - if (opt.no_skipped_summary == false) { - test_case_start_impl(in); - xml.writeAttribute("skipped", "true"); - xml.endElement(); - } - } - }; - - DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); - - void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) { - if ((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == - 0) //! OCLINT bitwise operator in conditional - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " << Color::None; - - if (rb.m_at & assertType::is_throws) { //! OCLINT bitwise operator in conditional - s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; - } else if ((rb.m_at & assertType::is_throws_as) && (rb.m_at & assertType::is_throws_with)) { //! OCLINT - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" << rb.m_exception_string - << "\", " << rb.m_exception_type << " ) " << Color::None; - if (rb.m_threw) { - if (!rb.m_failed) { - s << "threw as expected!\n"; - } else { - s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; - } - } else { - s << "did NOT throw at all!\n"; - } - } else if (rb.m_at & assertType::is_throws_as) { //! OCLINT bitwise operator in conditional - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " << rb.m_exception_type << " ) " - << Color::None - << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : "threw a DIFFERENT exception: ") - : "did NOT throw at all!") - << Color::Cyan << rb.m_exception << "\n"; - } else if (rb.m_at & assertType::is_throws_with) { //! OCLINT bitwise operator in conditional - s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" << rb.m_exception_string - << "\" ) " << Color::None - << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : "threw a DIFFERENT exception: ") - : "did NOT throw at all!") - << Color::Cyan << rb.m_exception << "\n"; - } else if (rb.m_at & assertType::is_nothrow) { //! OCLINT bitwise operator in conditional - s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan << rb.m_exception << "\n"; - } else { - s << (rb.m_threw ? "THREW exception: " : (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); - if (rb.m_threw) - s << rb.m_exception << "\n"; - else - s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; - } - } - - // TODO: - // - log_contexts() - // - log_message() - // - respond to queries - // - honor remaining options - // - more attributes in tags - struct JUnitReporter : public IReporter { - XmlWriter xml; - std::mutex mutex; - Timer timer; - std::vector deepestSubcaseStackNames; - - struct JUnitTestCaseData { - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") // gmtime - static std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - - std::tm* timeInfo; - timeInfo = std::gmtime(&rawtime); - - char timeStamp[timeStampSize]; - const char* const fmt = "%Y-%m-%dT%H:%M:%SZ"; - - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); - return std::string(timeStamp); - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - - struct JUnitTestMessage { - JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details) - : message(_message), type(_type), details(_details) {} - - JUnitTestMessage(const std::string& _message, const std::string& _details) - : message(_message), type(), details(_details) {} - - std::string message, type, details; - }; - - struct JUnitTestCase { - JUnitTestCase(const std::string& _classname, const std::string& _name) - : classname(_classname), name(_name), time(0), failures() {} - - std::string classname, name; - double time; - std::vector failures, errors; - }; - - void add(const std::string& classname, const std::string& name) { - testcases.emplace_back(classname, name); - } - - void appendSubcaseNamesToLastTestcase(std::vector nameStack) { - for (auto& curr : nameStack) - if (curr.size()) - testcases.back().name += std::string("/") + curr.c_str(); - } - - void addTime(double time) { - if (time < 1e-4) - time = 0; - testcases.back().time = time; - totalSeconds += time; - } - - void addFailure(const std::string& message, const std::string& type, const std::string& details) { - testcases.back().failures.emplace_back(message, type, details); - ++totalFailures; - } - - void addError(const std::string& message, const std::string& details) { - testcases.back().errors.emplace_back(message, details); - ++totalErrors; - } - - std::vector testcases; - double totalSeconds = 0; - int totalErrors = 0, totalFailures = 0; - }; - - JUnitTestCaseData testCaseData; - - // caching pointers/references to objects of these types - safe to do - const ContextOptions& opt; - const TestCaseData* tc = nullptr; - - JUnitReporter(const ContextOptions& co) : xml(*co.cout), opt(co) {} - - unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } - - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= - - void report_query(const QueryData&) override {} - - void test_run_start() override {} - - void test_run_end(const TestRunStats& p) override { - // remove .exe extension - mainly to have the same output on UNIX and Windows - std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); -#ifdef DOCTEST_PLATFORM_WINDOWS - if (binary_name.rfind(".exe") != std::string::npos) - binary_name = binary_name.substr(0, binary_name.length() - 4); -#endif // DOCTEST_PLATFORM_WINDOWS - xml.startElement("testsuites"); - xml.startElement("testsuite") - .writeAttribute("name", binary_name) - .writeAttribute("errors", testCaseData.totalErrors) - .writeAttribute("failures", testCaseData.totalFailures) - .writeAttribute("tests", p.numAsserts); - if (opt.no_time_in_output == false) { - xml.writeAttribute("time", testCaseData.totalSeconds); - xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp()); - } - if (opt.no_version == false) - xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR); - - for (const auto& testCase : testCaseData.testcases) { - xml.startElement("testcase") - .writeAttribute("classname", testCase.classname) - .writeAttribute("name", testCase.name); - if (opt.no_time_in_output == false) - xml.writeAttribute("time", testCase.time); - // This is not ideal, but it should be enough to mimic gtest's junit output. - xml.writeAttribute("status", "run"); - - for (const auto& failure : testCase.failures) { - xml.scopedElement("failure") - .writeAttribute("message", failure.message) - .writeAttribute("type", failure.type) - .writeText(failure.details, false); - } - - for (const auto& error : testCase.errors) { - xml.scopedElement("error").writeAttribute("message", error.message).writeText(error.details); - } - - xml.endElement(); - } - xml.endElement(); - xml.endElement(); - } - - void test_case_start(const TestCaseData& in) override { - testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); - timer.start(); - } - - void test_case_reenter(const TestCaseData& in) override { - testCaseData.addTime(timer.getElapsedSeconds()); - testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); - deepestSubcaseStackNames.clear(); - - timer.start(); - testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); - } - - void test_case_end(const CurrentTestCaseStats&) override { - testCaseData.addTime(timer.getElapsedSeconds()); - testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); - deepestSubcaseStackNames.clear(); - } - - void test_case_exception(const TestCaseException& e) override { - std::lock_guard lock(mutex); - testCaseData.addError("exception", e.error_string.c_str()); - } - - void subcase_start(const SubcaseSignature& in) override { - std::lock_guard lock(mutex); - deepestSubcaseStackNames.push_back(in.m_name); - } - - void subcase_end() override {} - - void log_assert(const AssertData& rb) override { - if (!rb.m_failed) // report only failures & ignore the `success` option - return; - - std::lock_guard lock(mutex); - - std::ostringstream os; - os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(") << line(rb.m_line) - << (opt.gnu_file_line ? ":" : "):") << std::endl; - - fulltext_log_assert_to_stream(os, rb); - testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); - } - - void log_message(const MessageData&) override {} - - void test_case_skipped(const TestCaseData&) override {} - }; - - DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); - - struct Whitespace { - int nrSpaces; - explicit Whitespace(int nr) : nrSpaces(nr) {} - }; - - std::ostream& operator<<(std::ostream& out, const Whitespace& ws) { - if (ws.nrSpaces != 0) - out << std::setw(ws.nrSpaces) << ' '; - return out; - } - - struct ConsoleReporter : public IReporter { - std::ostream& s; - bool hasLoggedCurrentTestStart; - std::vector subcasesStack; - size_t currentSubcaseLevel; - std::mutex mutex; - - // caching pointers/references to objects of these types - safe to do - const ContextOptions& opt; - const TestCaseData* tc; - - ConsoleReporter(const ContextOptions& co) : s(*co.cout), opt(co) {} - - ConsoleReporter(const ContextOptions& co, std::ostream& ostr) : s(ostr), opt(co) {} - - // ========================================================================================= - // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE - // ========================================================================================= - - void separator_to_stream() { - s << Color::Yellow - << "===============================================================================" - "\n"; - } - - const char* getSuccessOrFailString(bool success, assertType::Enum at, const char* success_str) { - if (success) - return success_str; - return failureString(at); - } - - Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) { - return success ? Color::BrightGreen : (at & assertType::is_warn) ? Color::Yellow : Color::Red; - } - - void successOrFailColoredStringToStream(bool success, assertType::Enum at, - const char* success_str = "SUCCESS") { - s << getSuccessOrFailColor(success, at) << getSuccessOrFailString(success, at, success_str) << ": "; - } - - void log_contexts() { - int num_contexts = get_num_active_contexts(); - if (num_contexts) { - auto contexts = get_active_contexts(); - - s << Color::None << " logged: "; - for (int i = 0; i < num_contexts; ++i) { - s << (i == 0 ? "" : " "); - contexts[i]->stringify(&s); - s << "\n"; - } - } - - s << "\n"; - } - - // this was requested to be made virtual so users could override it - virtual void file_line_to_stream(const char* file, int line, const char* tail = "") { - s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") - << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option - << (opt.gnu_file_line ? ":" : "):") << tail; - } - - void logTestStart() { - if (hasLoggedCurrentTestStart) - return; - - separator_to_stream(); - file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n"); - if (tc->m_description) - s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; - if (tc->m_test_suite && tc->m_test_suite[0] != '\0') - s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; - if (strncmp(tc->m_name, " Scenario:", 11) != 0) - s << Color::Yellow << "TEST CASE: "; - s << Color::None << tc->m_name << "\n"; - - for (size_t i = 0; i < currentSubcaseLevel; ++i) { - if (subcasesStack[i].m_name[0] != '\0') - s << " " << subcasesStack[i].m_name << "\n"; - } - - if (currentSubcaseLevel != subcasesStack.size()) { - s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" - << Color::None; - for (size_t i = 0; i < subcasesStack.size(); ++i) { - if (subcasesStack[i].m_name[0] != '\0') - s << " " << subcasesStack[i].m_name << "\n"; - } - } - - s << "\n"; - - hasLoggedCurrentTestStart = true; - } - - void printVersion() { - if (opt.no_version == false) - s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" << DOCTEST_VERSION_STR - << "\"\n"; - } - - void printIntro() { - printVersion(); - s << Color::Cyan << "[doctest] " << Color::None - << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; - } - - void printHelp() { - int sizePrefixDisplay = static_cast(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY)); - printVersion(); - // clang-format off - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; - s << Color::Cyan << "[doctest] " << Color::None; - s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "filters use wildcards for matching strings\n"; - s << Color::Cyan << "[doctest] " << Color::None; - s << "something passes a filter if any of the strings in a filter matches\n"; -#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n"; -#endif - s << Color::Cyan << "[doctest]\n" << Color::None; - s << Color::Cyan << "[doctest] " << Color::None; - s << "Query flags - the program quits after them. Available:\n\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h " - << Whitespace(sizePrefixDisplay*0) << "prints this message\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version " - << Whitespace(sizePrefixDisplay*1) << "prints the version\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count " - << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases " - << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites " - << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters " - << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n"; - // ================================================================================== << 79 - s << Color::Cyan << "[doctest] " << Color::None; - s << "The available / options/filters are:\n\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case= " - << Whitespace(sizePrefixDisplay*1) << "filters tests by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file= " - << Whitespace(sizePrefixDisplay*1) << "filters tests by their file\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite= " - << Whitespace(sizePrefixDisplay*1) << "filters tests by their test suite\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase= " - << Whitespace(sizePrefixDisplay*1) << "filters subcases by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude= " - << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters= " - << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out= " - << Whitespace(sizePrefixDisplay*1) << "output filename\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by= " - << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; - s << Whitespace(sizePrefixDisplay*3) << " - by [file/suite/name/rand]\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed= " - << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first= " - << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n"; - s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last= " - << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n"; - s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after= " - << Whitespace(sizePrefixDisplay*1) << "stop after failed assertions\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels= " - << Whitespace(sizePrefixDisplay*1) << "apply filters for the first levels\n"; - s << Color::Cyan << "\n[doctest] " << Color::None; - s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success= " - << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive= " - << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit= " - << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration= " - << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw= " - << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode= " - << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run= " - << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version= " - << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors= " - << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors= " - << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks= " - << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip= " - << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line= " - << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames= " - << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n"; - s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers= " - << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n"; - // ================================================================================== << 79 - // clang-format on - - s << Color::Cyan << "\n[doctest] " << Color::None; - s << "for more information visit the project documentation\n\n"; - } - - void printRegisteredReporters() { - printVersion(); - auto printReporters = [this](const reporterMap& reporters, const char* type) { - if (reporters.size()) { - s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; - for (auto& curr : reporters) - s << "priority: " << std::setw(5) << curr.first.first << " name: " << curr.first.second - << "\n"; - } - }; - printReporters(getListeners(), "listeners"); - printReporters(getReporters(), "reporters"); - } - - void list_query_results() { - separator_to_stream(); - if (opt.count || opt.list_test_cases) { - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " << g_cs->numTestCasesPassingFilters - << "\n"; - } else if (opt.list_test_suites) { - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " << g_cs->numTestCasesPassingFilters - << "\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "test suites with unskipped test cases passing the current filters: " - << g_cs->numTestSuitesPassingFilters << "\n"; - } - } - - // ========================================================================================= - // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE - // ========================================================================================= - - void report_query(const QueryData& in) override { - if (opt.version) { - printVersion(); - } else if (opt.help) { - printHelp(); - } else if (opt.list_reporters) { - printRegisteredReporters(); - } else if (opt.count || opt.list_test_cases) { - if (opt.list_test_cases) { - s << Color::Cyan << "[doctest] " << Color::None << "listing all test case names\n"; - separator_to_stream(); - } - - for (unsigned i = 0; i < in.num_data; ++i) - s << Color::None << in.data[i]->m_name << "\n"; - - separator_to_stream(); - - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " << g_cs->numTestCasesPassingFilters - << "\n"; - - } else if (opt.list_test_suites) { - s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; - separator_to_stream(); - - for (unsigned i = 0; i < in.num_data; ++i) - s << Color::None << in.data[i]->m_test_suite << "\n"; - - separator_to_stream(); - - s << Color::Cyan << "[doctest] " << Color::None - << "unskipped test cases passing the current filters: " << g_cs->numTestCasesPassingFilters - << "\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "test suites with unskipped test cases passing the current filters: " - << g_cs->numTestSuitesPassingFilters << "\n"; - } - } - - void test_run_start() override { printIntro(); } - - void test_run_end(const TestRunStats& p) override { - separator_to_stream(); - s << std::dec; - - const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; - s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(6) - << p.numTestCasesPassingFilters << " | " - << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : Color::Green) - << std::setw(6) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" << Color::None - << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) << std::setw(6) - << p.numTestCasesFailed << " failed" << Color::None << " | "; - if (opt.no_skipped_summary == false) { - const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; - s << (numSkipped == 0 ? Color::None : Color::Yellow) << std::setw(6) << numSkipped << " skipped" - << Color::None; - } - s << "\n"; - s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(6) << p.numAsserts - << " | " << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) << std::setw(6) - << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None << " | " - << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(6) << p.numAssertsFailed - << " failed" << Color::None << " |\n"; - s << Color::Cyan << "[doctest] " << Color::None - << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) - << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl; - } - - void test_case_start(const TestCaseData& in) override { - hasLoggedCurrentTestStart = false; - tc = ∈ - subcasesStack.clear(); - currentSubcaseLevel = 0; - } - - void test_case_reenter(const TestCaseData&) override { subcasesStack.clear(); } - - void test_case_end(const CurrentTestCaseStats& st) override { - // log the preamble of the test case only if there is something - // else to print - something other than that an assert has failed - if (opt.duration || (st.failure_flags && st.failure_flags != TestCaseFailureReason::AssertFailure)) - logTestStart(); - - if (opt.duration) - s << Color::None << std::setprecision(6) << std::fixed << st.seconds << " s: " << tc->m_name - << "\n"; - - if (st.failure_flags & TestCaseFailureReason::Timeout) - s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6) << std::fixed - << tc->m_timeout << "!\n"; - - if (st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { - s << Color::Red << "Should have failed but didn't! Marking it as failed!\n"; - } else if (st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) { - s << Color::Yellow << "Failed as expected so marking it as not failed\n"; - } else if (st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) { - s << Color::Yellow << "Allowed to fail so marking it as not failed\n"; - } else if (st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { - s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures - << " times so marking it as failed!\n"; - } else if (st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) { - s << Color::Yellow << "Failed exactly " << tc->m_expected_failures - << " times as expected so marking it as not failed!\n"; - } - if (st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { - s << Color::Red << "Aborting - too many failed asserts!\n"; - } - s << Color::None; // lgtm [cpp/useless-expression] - } - - void test_case_exception(const TestCaseException& e) override { - logTestStart(); - - file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); - successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : assertType::is_check); - s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ") << Color::Cyan - << e.error_string << "\n"; - - int num_stringified_contexts = get_num_stringified_contexts(); - if (num_stringified_contexts) { - auto stringified_contexts = get_stringified_contexts(); - s << Color::None << " logged: "; - for (int i = num_stringified_contexts; i > 0; --i) { - s << (i == num_stringified_contexts ? "" : " ") << stringified_contexts[i - 1] << "\n"; - } - } - s << "\n" << Color::None; - } - - void subcase_start(const SubcaseSignature& subc) override { - std::lock_guard lock(mutex); - subcasesStack.push_back(subc); - ++currentSubcaseLevel; - hasLoggedCurrentTestStart = false; - } - - void subcase_end() override { - std::lock_guard lock(mutex); - --currentSubcaseLevel; - hasLoggedCurrentTestStart = false; - } - - void log_assert(const AssertData& rb) override { - if (!rb.m_failed && !opt.success) - return; - - std::lock_guard lock(mutex); - - logTestStart(); - - file_line_to_stream(rb.m_file, rb.m_line, " "); - successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); - - fulltext_log_assert_to_stream(s, rb); - - log_contexts(); - } - - void log_message(const MessageData& mb) override { - std::lock_guard lock(mutex); - - logTestStart(); - - file_line_to_stream(mb.m_file, mb.m_line, " "); - s << getSuccessOrFailColor(false, mb.m_severity) - << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, "MESSAGE") << ": "; - s << Color::None << mb.m_string << "\n"; - log_contexts(); - } - - void test_case_skipped(const TestCaseData&) override {} - }; - - DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); - -#ifdef DOCTEST_PLATFORM_WINDOWS - struct DebugOutputWindowReporter : public ConsoleReporter { - DOCTEST_THREAD_LOCAL static std::ostringstream oss; - - DebugOutputWindowReporter(const ContextOptions& co) : ConsoleReporter(co, oss) {} - -#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ - void func(type arg) override { \ - bool with_col = g_no_colors; \ - g_no_colors = false; \ - ConsoleReporter::func(arg); \ - DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ - oss.str(""); \ - g_no_colors = with_col; \ - } - - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in) - DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in) - }; - - DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; -#endif // DOCTEST_PLATFORM_WINDOWS - - // the implementation of parseOption() - bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { - // going from the end to the beginning and stopping on the first occurrence from the end - for (int i = argc; i > 0; --i) { - auto index = i - 1; - auto temp = std::strstr(argv[index], pattern); - if (temp && (value || strlen(temp) == strlen(pattern))) { //! OCLINT prefer early exits and continue - // eliminate matches in which the chars before the option are not '-' - bool noBadCharsFound = true; - auto curr = argv[index]; - while (curr != temp) { - if (*curr++ != '-') { - noBadCharsFound = false; - break; - } - } - if (noBadCharsFound && argv[index][0] == '-') { - if (value) { - // parsing the value of an option - temp += strlen(pattern); - const unsigned len = strlen(temp); - if (len) { - *value = temp; - return true; - } - } else { - // just a flag - no value - return true; - } - } - } - } - return false; - } - - // parses an option and returns the string after the '=' character - bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr, - const String& defaultVal = String()) { - if (value) - *value = defaultVal; -#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - // offset (normally 3 for "dt-") to skip prefix - if (parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) - return true; -#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS - return parseOptionImpl(argc, argv, pattern, value); - } - - // locates a flag on the command line - bool parseFlag(int argc, const char* const* argv, const char* pattern) { - return parseOption(argc, argv, pattern); - } - - // parses a comma separated list of words after a pattern in one of the arguments in argv - bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, std::vector& res) { - String filtersString; - if (parseOption(argc, argv, pattern, &filtersString)) { - // tokenize with "," as a separator - // cppcheck-suppress strtokCalled - DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") - auto pch = std::strtok(filtersString.c_str(), ","); // modifies the string - while (pch != nullptr) { - if (strlen(pch)) - res.push_back(pch); - // uses the strtok() internal state to go to the next token - // cppcheck-suppress strtokCalled - pch = std::strtok(nullptr, ","); - } - DOCTEST_CLANG_SUPPRESS_WARNING_POP - return true; - } - return false; - } - - enum optionType { option_bool, option_int }; - - // parses an int/bool option from the command line - bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, int& res) { - String parsedValue; - if (!parseOption(argc, argv, pattern, &parsedValue)) - return false; - - if (type == 0) { - // boolean - const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 - const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 - - // if the value matches any of the positive/negative possibilities - for (unsigned i = 0; i < 4; i++) { - if (parsedValue.compare(positive[i], true) == 0) { - res = 1; //! OCLINT parameter reassignment - return true; - } - if (parsedValue.compare(negative[i], true) == 0) { - res = 0; //! OCLINT parameter reassignment - return true; - } - } - } else { - // integer - // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes - // '0' on failed parse... - int theInt = std::atoi(parsedValue.c_str()); // NOLINT - if (theInt != 0) { - res = theInt; //! OCLINT parameter reassignment - return true; - } - } - return false; - } - } // namespace - - Context::Context(int argc, const char* const* argv) : p(new detail::ContextState) { - parseArgs(argc, argv, true); - if (argc) - p->binary_name = argv[0]; - } - - Context::~Context() { - if (g_cs == p) - g_cs = nullptr; - delete p; - } - - void Context::applyCommandLine(int argc, const char* const* argv) { - parseArgs(argc, argv); - if (argc) - p->binary_name = argv[0]; - } - - // parses args - void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { - using namespace detail; - - // clang-format off - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]); - parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]); - // clang-format on - - int intRes = 0; - String strRes; - -#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ - if (parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ - parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ - p->var = !!intRes; \ - else if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ - p->var = true; \ - else if (withDefaults) \ - p->var = default - -#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ - if (parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \ - parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \ - p->var = intRes; \ - else if (withDefaults) \ - p->var = default - -#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ - if (parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ - parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || withDefaults) \ - p->var = strRes - - // clang-format off - DOCTEST_PARSE_STR_OPTION("out", "o", out, ""); - DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file"); - DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0); - - DOCTEST_PARSE_INT_OPTION("first", "f", first, 0); - DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX); - - DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0); - DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX); - - DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); - DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false); - // clang-format on - - if (withDefaults) { - p->help = false; - p->version = false; - p->count = false; - p->list_test_cases = false; - p->list_test_suites = false; - p->list_reporters = false; - } - if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) { - p->help = true; - p->exit = true; - } - if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) { - p->version = true; - p->exit = true; - } - if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) { - p->count = true; - p->exit = true; - } - if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) { - p->list_test_cases = true; - p->exit = true; - } - if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) { - p->list_test_suites = true; - p->exit = true; - } - if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") || - parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) { - p->list_reporters = true; - p->exit = true; - } - } - - // allows the user to add procedurally to the filters from the command line - void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } - - // allows the user to clear all filters from the command line - void Context::clearFilters() { - for (auto& curr : p->filters) - curr.clear(); - } - - // allows the user to override procedurally the int/bool options from the command line - void Context::setOption(const char* option, int value) { setOption(option, toString(value).c_str()); } - - // allows the user to override procedurally the string options from the command line - void Context::setOption(const char* option, const char* value) { - auto argv = String("-") + option + "=" + value; - auto lvalue = argv.c_str(); - parseArgs(1, &lvalue); - } - - // users should query this in their main() and exit the program if true - bool Context::shouldExit() { return p->exit; } - - void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; } - - void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; } - - // the main function that does all the filtering and test running - int Context::run() { - using namespace detail; - - // save the old context state in case such was setup - for using asserts out of a testing context - auto old_cs = g_cs; - // this is the current contest - g_cs = p; - is_running_in_test = true; - - g_no_colors = p->no_colors; - p->resetRunData(); - - // stdout by default - p->cout = &std::cout; - p->cerr = &std::cerr; - - // or to a file if specified - std::fstream fstr; - if (p->out.size()) { - fstr.open(p->out.c_str(), std::fstream::out); - p->cout = &fstr; - } - - auto cleanup_and_return = [&]() { - if (fstr.is_open()) - fstr.close(); - - // restore context - g_cs = old_cs; - is_running_in_test = false; - - // we have to free the reporters which were allocated when the run started - for (auto& curr : p->reporters_currently_used) - delete curr; - p->reporters_currently_used.clear(); - - if (p->numTestCasesFailed && !p->no_exitcode) - return EXIT_FAILURE; - return EXIT_SUCCESS; - }; - - // setup default reporter if none is given through the command line - if (p->filters[8].empty()) - p->filters[8].push_back("console"); - - // check to see if any of the registered reporters has been selected - for (auto& curr : getReporters()) { - if (matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive)) - p->reporters_currently_used.push_back(curr.second(*g_cs)); - } - - // TODO: check if there is nothing in reporters_currently_used - - // prepend all listeners - for (auto& curr : getListeners()) - p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); - -#ifdef DOCTEST_PLATFORM_WINDOWS - if (isDebuggerActive()) - p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); -#endif // DOCTEST_PLATFORM_WINDOWS - - // handle version, help and no_run - if (p->no_run || p->version || p->help || p->list_reporters) { - DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData()); - - return cleanup_and_return(); - } - - std::vector testArray; - for (auto& curr : getRegisteredTests()) - testArray.push_back(&curr); - p->numTestCases = testArray.size(); - - // sort the collected records - if (!testArray.empty()) { - if (p->order_by.compare("file", true) == 0) { - std::sort(testArray.begin(), testArray.end(), fileOrderComparator); - } else if (p->order_by.compare("suite", true) == 0) { - std::sort(testArray.begin(), testArray.end(), suiteOrderComparator); - } else if (p->order_by.compare("name", true) == 0) { - std::sort(testArray.begin(), testArray.end(), nameOrderComparator); - } else if (p->order_by.compare("rand", true) == 0) { - std::srand(p->rand_seed); - - // random_shuffle implementation - const auto first = &testArray[0]; - for (size_t i = testArray.size() - 1; i > 0; --i) { - int idxToSwap = std::rand() % (i + 1); // NOLINT - - const auto temp = first[i]; - - first[i] = first[idxToSwap]; - first[idxToSwap] = temp; - } - } - } - - std::set testSuitesPassingFilt; - - bool query_mode = p->count || p->list_test_cases || p->list_test_suites; - std::vector queryResults; - - if (!query_mode) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); - - // invoke the registered functions if they match the filter criteria (or just count them) - for (auto& curr : testArray) { - const auto& tc = *curr; - - bool skip_me = false; - if (tc.m_skip && !p->no_skip) - skip_me = true; - - if (!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) - skip_me = true; - if (matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) - skip_me = true; - if (!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) - skip_me = true; - if (matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive)) - skip_me = true; - if (!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive)) - skip_me = true; - if (matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive)) - skip_me = true; - - if (!skip_me) - p->numTestCasesPassingFilters++; - - // skip the test if it is not in the execution range - if ((p->last < p->numTestCasesPassingFilters && p->first <= p->last) || - (p->first > p->numTestCasesPassingFilters)) - skip_me = true; - - if (skip_me) { - if (!query_mode) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc); - continue; - } - - // do not execute the test if we are to only count the number of filter passing tests - if (p->count) - continue; - - // print the name of the test and don't execute it - if (p->list_test_cases) { - queryResults.push_back(&tc); - continue; - } - - // print the name of the test suite if not done already and don't execute it - if (p->list_test_suites) { - if ((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { - queryResults.push_back(&tc); - testSuitesPassingFilt.insert(tc.m_test_suite); - p->numTestSuitesPassingFilters++; - } - continue; - } - - // execute the test if it passes all the filtering - { - p->currentTest = &tc; - - p->failure_flags = TestCaseFailureReason::None; - p->seconds = 0; - - // reset atomic counters - p->numAssertsFailedCurrentTest_atomic = 0; - p->numAssertsCurrentTest_atomic = 0; - - p->subcasesPassed.clear(); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); - - p->timer.start(); - - bool run_test = true; - - do { - // reset some of the fields for subcases (except for the set of fully passed ones) - p->should_reenter = false; - p->subcasesCurrentMaxLevel = 0; - p->subcasesStack.clear(); - - p->shouldLogCurrentException = true; - - // reset stuff for logging with INFO() - p->stringifiedContexts.clear(); - -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - try { -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - FatalConditionHandler fatalConditionHandler; // Handle signals - // execute the test - tc.m_test(); - fatalConditionHandler.reset(); -#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS - } catch (const TestFailureException&) { - p->failure_flags |= TestCaseFailureReason::AssertFailure; - } catch (...) { - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {translateActiveException(), false}); - p->failure_flags |= TestCaseFailureReason::Exception; - } -#endif // DOCTEST_CONFIG_NO_EXCEPTIONS - - // exit this loop if enough assertions have failed - even if there are more subcases - if (p->abort_after > 0 && - p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { - run_test = false; - p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; - } - - if (p->should_reenter && run_test) - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); - if (!p->should_reenter) - run_test = false; - } while (run_test); - - p->finalizeTestCaseData(); - - DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); - - p->currentTest = nullptr; - - // stop executing tests if enough assertions have failed - if (p->abort_after > 0 && p->numAssertsFailed >= p->abort_after) - break; - } - } - - if (!query_mode) { - DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); - } else { - QueryData qdata; - qdata.run_stats = g_cs; - qdata.data = queryResults.data(); - qdata.num_data = unsigned(queryResults.size()); - DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); - } - - // see these issues on the reasoning for this: - // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903 - // - https://github.com/onqtam/doctest/issues/126 - auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE { - std::cout << std::string(); - }; - DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS(); - - return cleanup_and_return(); - } - - IReporter::~IReporter() = default; - - int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } - const IContextScope* const* IReporter::get_active_contexts() { - return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr; - } - - int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); } - const String* IReporter::get_stringified_contexts() { - return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr; - } - - namespace detail { - void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { - if (isReporter) - getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); - else - getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); - } - } // namespace detail - -} // namespace doctest - -#endif // DOCTEST_CONFIG_DISABLE - -#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 -int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } -DOCTEST_MSVC_SUPPRESS_WARNING_POP -#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN - -DOCTEST_CLANG_SUPPRESS_WARNING_POP -DOCTEST_MSVC_SUPPRESS_WARNING_POP -DOCTEST_GCC_SUPPRESS_WARNING_POP - -#endif // DOCTEST_LIBRARY_IMPLEMENTATION -#endif // DOCTEST_CONFIG_IMPLEMENT diff --git a/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp b/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp index 5c2dd6f..26b7c27 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp @@ -2,7 +2,7 @@ #define PKMNLIB_ANGELSCRIPTITEMUSESCRIPT_HPP #include -#include "../../../extern/angelscript_addons/scriptarray/scriptarray.h" +#include #include "TypeRegistry/NativeArray.hpp" class AngelScriptResolver; diff --git a/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp b/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp index e07eeda..d7c368a 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp +++ b/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp @@ -2,10 +2,10 @@ #include #include #include -#include "../../../extern/angelscript_addons/scriptdictionary/scriptdictionary.h" -#include "../../../extern/angelscript_addons/scripthandle/scripthandle.h" -#include "../../../extern/angelscript_addons/scripthelper/scripthelper.h" -#include "../../../extern/angelscript_addons/scriptstdstring/scriptstdstring.h" +#include +#include +#include +#include #include "../../Battling/PkmnScriptCategory.hpp" #include "../../Battling/Pokemon/Pokemon.hpp" #include "AngelScriptMetadata.hpp" diff --git a/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp b/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp index 25a6275..4b7d690 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp @@ -4,9 +4,9 @@ #include #include #ifdef ANGELSCRIPT_DEBUGGER -#include "../../../extern/AngelscriptDebuggerServer/src/AngelscriptDebugger.hpp" +#include #endif -#include "../../../extern/angelscript_addons/scriptbuilder/scriptbuilder.h" +#include #include "../../Battling/Library/BattleLibrary.hpp" #include "AngelScriptEvolutionScript.hpp" diff --git a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp index db2ca77..345a439 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp @@ -4,8 +4,8 @@ #include #define ANGELSCRIPT_DLL_LIBRARY_IMPORT #include -#include "../../../extern/angelscript_addons/scriptarray/scriptarray.h" -#include "../../../extern/angelscript_addons/scripthandle/scripthandle.h" +#include +#include #include "../../Battling/PkmnScript.hpp" #include "AngelScriptTypeInfo.hpp" #include "TypeRegistry/NativeArray.hpp" diff --git a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp index 97b80c0..ae5152d 100644 --- a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp +++ b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp @@ -2,7 +2,7 @@ #include #include #include -#include "../../../../../extern/angelscript_addons/scripthandle/scripthandle.h" +#include #include "../../../../Battling/Battle/Battle.hpp" #include "../../../../Battling/Pokemon/Pokemon.hpp" #include "../../AngelScriptResolver.hpp" diff --git a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp index bd190fa..ac8b047 100644 --- a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp +++ b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp @@ -1,7 +1,7 @@ #include "RegisterPokemonClass.hpp" #include -#include "../../../../../extern/angelscript_addons/scriptarray/scriptarray.h" -#include "../../../../../extern/angelscript_addons/scripthandle/scripthandle.h" +#include +#include #include "../../../../Battling/PkmnDamageSource.hpp" #include "../../../../Battling/Pokemon/Pokemon.hpp" #include "../../AngelScriptResolver.hpp" diff --git a/tests/BattleTests/DamageTests.cpp b/tests/BattleTests/DamageTests.cpp index 1596af8..05d3bdb 100644 --- a/tests/BattleTests/DamageTests.cpp +++ b/tests/BattleTests/DamageTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Library/DamageLibrary.hpp" #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../TestLibrary/TestLibrary.hpp" diff --git a/tests/LibraryTests/NatureLibraryTests.cpp b/tests/LibraryTests/NatureLibraryTests.cpp index b0b1789..eee1bb7 100644 --- a/tests/LibraryTests/NatureLibraryTests.cpp +++ b/tests/LibraryTests/NatureLibraryTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Library/Natures/NatureLibrary.hpp" #include "../../src/Library/Statistic.hpp" diff --git a/tests/LibraryTests/SpeciesLibraryTests.cpp b/tests/LibraryTests/SpeciesLibraryTests.cpp index 42d770b..02df443 100644 --- a/tests/LibraryTests/SpeciesLibraryTests.cpp +++ b/tests/LibraryTests/SpeciesLibraryTests.cpp @@ -1,6 +1,6 @@ #ifdef TESTS_BUILD #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include "../../extern/doctest.hpp" +#include #include "../../src/Library/Species/SpeciesLibrary.hpp" TEST_CASE("Able to build and destroy empty library") { diff --git a/tests/LibraryTests/SpeciesTests.cpp b/tests/LibraryTests/SpeciesTests.cpp index 36a3796..e60f9f5 100644 --- a/tests/LibraryTests/SpeciesTests.cpp +++ b/tests/LibraryTests/SpeciesTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Library/Species/PokemonSpecies.hpp" diff --git a/tests/LibraryTests/StatCalculationTests.cpp b/tests/LibraryTests/StatCalculationTests.cpp index c30ba78..1cb7a5f 100644 --- a/tests/LibraryTests/StatCalculationTests.cpp +++ b/tests/LibraryTests/StatCalculationTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../TestLibrary/TestLibrary.hpp" diff --git a/tests/PokemonTests/BasicPokemonTests.cpp b/tests/PokemonTests/BasicPokemonTests.cpp index 482b4ec..6fffe4e 100644 --- a/tests/PokemonTests/BasicPokemonTests.cpp +++ b/tests/PokemonTests/BasicPokemonTests.cpp @@ -1,7 +1,7 @@ #ifdef TESTS_BUILD #include #include -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Battle/Battle.hpp" #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../../src/Battling/Pokemon/PokemonParty.hpp" diff --git a/tests/PokemonTests/ExperienceGainTests.cpp b/tests/PokemonTests/ExperienceGainTests.cpp index 83e1d47..a874ea7 100644 --- a/tests/PokemonTests/ExperienceGainTests.cpp +++ b/tests/PokemonTests/ExperienceGainTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Library/ExperienceLibrary.hpp" #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/BaseScriptClassTests.cpp b/tests/ScriptTests/BaseScriptClassTests.cpp index f6ed4c5..7392cd6 100644 --- a/tests/ScriptTests/BaseScriptClassTests.cpp +++ b/tests/ScriptTests/BaseScriptClassTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../src/ScriptResolving/AngelScript/ContextPool.hpp" diff --git a/tests/ScriptTests/ItemUseScriptTests.cpp b/tests/ScriptTests/ItemUseScriptTests.cpp index e0e3f47..820f348 100644 --- a/tests/ScriptTests/ItemUseScriptTests.cpp +++ b/tests/ScriptTests/ItemUseScriptTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/MetadataTests.cpp b/tests/ScriptTests/MetadataTests.cpp index 9ac469e..01d6bcf 100644 --- a/tests/ScriptTests/MetadataTests.cpp +++ b/tests/ScriptTests/MetadataTests.cpp @@ -1,6 +1,6 @@ #ifdef TESTS_BUILD #include -#include "../../extern/doctest.hpp" +#include #include "../../src/ScriptResolving/AngelScript/AngelScriptMetadata.hpp" TEST_CASE("Metadata without parameters") { diff --git a/tests/ScriptTests/ScriptOwnerTest.cpp b/tests/ScriptTests/ScriptOwnerTest.cpp index 8e447a9..cfc0395 100644 --- a/tests/ScriptTests/ScriptOwnerTest.cpp +++ b/tests/ScriptTests/ScriptOwnerTest.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../src/ScriptResolving/AngelScript/ContextPool.hpp" diff --git a/tests/ScriptTests/ScriptResolverTests.cpp b/tests/ScriptTests/ScriptResolverTests.cpp index b1e0acf..b0f9037 100644 --- a/tests/ScriptTests/ScriptResolverTests.cpp +++ b/tests/ScriptTests/ScriptResolverTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../extern/doctest.hpp" +#include #include "../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../src/ScriptResolving/AngelScript/ContextPool.hpp" #include "../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Battle/BattleTests.cpp b/tests/ScriptTests/ScriptTypeTests/Battle/BattleTests.cpp index eaac0d6..0c1cc92 100644 --- a/tests/ScriptTests/ScriptTypeTests/Battle/BattleTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Battle/BattleTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/Battling/Battle/Battle.hpp" #include "../../../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Battle/PokemonTests.cpp b/tests/ScriptTests/ScriptTypeTests/Battle/PokemonTests.cpp index d51ff72..b7092ca 100644 --- a/tests/ScriptTests/ScriptTypeTests/Battle/PokemonTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Battle/PokemonTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/Battling/Pokemon/CreatePokemon.hpp" #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Library/FormesTests.cpp b/tests/ScriptTests/ScriptTypeTests/Library/FormesTests.cpp index 0d52d60..a2eb936 100644 --- a/tests/ScriptTests/ScriptTypeTests/Library/FormesTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Library/FormesTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp" #include "../../../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Library/ItemDataTests.cpp b/tests/ScriptTests/ScriptTypeTests/Library/ItemDataTests.cpp index 662ed14..21f1323 100644 --- a/tests/ScriptTests/ScriptTypeTests/Library/ItemDataTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Library/ItemDataTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp" #include "../../../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Library/MoveTests.cpp b/tests/ScriptTests/ScriptTypeTests/Library/MoveTests.cpp index 9d2b19a..8f023d3 100644 --- a/tests/ScriptTests/ScriptTypeTests/Library/MoveTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Library/MoveTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp" #include "../../../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Library/SpeciesTests.cpp b/tests/ScriptTests/ScriptTypeTests/Library/SpeciesTests.cpp index 8bc928c..a449356 100644 --- a/tests/ScriptTests/ScriptTypeTests/Library/SpeciesTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Library/SpeciesTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp" #include "../../../TestLibrary/TestLibrary.hpp" diff --git a/tests/ScriptTests/ScriptTypeTests/Library/StaticLibraryTests.cpp b/tests/ScriptTests/ScriptTypeTests/Library/StaticLibraryTests.cpp index 1983c49..3d2c0cb 100644 --- a/tests/ScriptTests/ScriptTypeTests/Library/StaticLibraryTests.cpp +++ b/tests/ScriptTests/ScriptTypeTests/Library/StaticLibraryTests.cpp @@ -1,5 +1,5 @@ #ifdef TESTS_BUILD -#include "../../../../extern/doctest.hpp" +#include #include "../../../../src/ScriptResolving/AngelScript/AngelScriptResolver.hpp" #include "../../../../src/ScriptResolving/AngelScript/ContextPool.hpp" #include "../../../TestLibrary/TestLibrary.hpp"