From 5c1a0eda98fbea03e7c6ea29e7d18f9329e7c29d Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Mon, 20 Nov 2017 14:02:33 +0100 Subject: [PATCH 4/4] libs: update angelscript to 2.32.0 Signed-off-by: Igor Gnatenko --- src/scriptengine/script_engine.cpp | 2 +- src/scriptengine/scriptarray.cpp | 480 ++++++++++++------ src/scriptengine/scriptarray.hpp | 40 +- src/scriptengine/scriptstdstring.cpp | 758 +++++++++++++++++------------ src/scriptengine/scriptstdstring.hpp | 16 +- src/scriptengine/scriptstdstring_utils.cpp | 2 +- 6 files changed, 789 insertions(+), 509 deletions(-) diff --git a/src/scriptengine/script_engine.cpp b/src/scriptengine/script_engine.cpp index 47458c93d..2c1ccbf3e 100644 --- a/src/scriptengine/script_engine.cpp +++ b/src/scriptengine/script_engine.cpp @@ -222,7 +222,7 @@ namespace Scripting /* void ScriptEngine::runMethod(asIScriptObject* obj, std::string methodName) { - asIObjectType* type = obj->GetObjectType(); + asITypeInfo* type = obj->GetObjectType(); asIScriptFunction* method = type->GetMethodByName(methodName.c_str()); if (method == NULL) Log::error("Scripting", ("runMethod: object does not implement method " + methodName).c_str()); diff --git a/src/scriptengine/scriptarray.cpp b/src/scriptengine/scriptarray.cpp index 322cdfa17..8557c8cb9 100644 --- a/src/scriptengine/scriptarray.cpp +++ b/src/scriptengine/scriptarray.cpp @@ -1,38 +1,9 @@ -/* -AngelCode Scripting Library -Copyright (c) 2003-2015 Andreas Jonsson - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you -must not claim that you wrote the original software. If you use -this software in a product, an acknowledgment in the product -documentation would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - -The original version of this library can be located at: -http://www.angelcode.com/angelscript/ - -Andreas Jonsson -andreas@angelcode.com -*/ - #include #include #include #include #include // sprintf +#include #include "scriptarray.hpp" @@ -79,7 +50,7 @@ struct SArrayCache // through 1999 for this purpose, so we should be fine. const asPWORD ARRAY_CACHE = 1000; -static void CleanupObjectTypeArrayCache(asIObjectType *type) +static void CleanupTypeInfoArrayCache(asITypeInfo *type) { SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); if( cache ) @@ -89,14 +60,13 @@ static void CleanupObjectTypeArrayCache(asIObjectType *type) } } -CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length) +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length) { - asIScriptContext *ctx = asGetActiveContext(); - // Allocate the memory void *mem = userAlloc(sizeof(CScriptArray)); if( mem == 0 ) { + asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Out of memory"); @@ -104,27 +74,18 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length) } // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, ot); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } + CScriptArray *a = new(mem) CScriptArray(length, ti); return a; } -CScriptArray* CScriptArray::Create(asIObjectType *ot, void *initList) +CScriptArray* CScriptArray::Create(asITypeInfo *ti, void *initList) { - asIScriptContext *ctx = asGetActiveContext(); - // Allocate the memory void *mem = userAlloc(sizeof(CScriptArray)); if( mem == 0 ) { + asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Out of memory"); @@ -132,27 +93,18 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot, void *initList) } // Initialize the object - CScriptArray *a = new(mem) CScriptArray(ot, initList); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } + CScriptArray *a = new(mem) CScriptArray(ti, initList); return a; } -CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length, void *defVal) +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length, void *defVal) { - asIScriptContext *ctx = asGetActiveContext(); - // Allocate the memory void *mem = userAlloc(sizeof(CScriptArray)); if( mem == 0 ) { + asIScriptContext *ctx = asGetActiveContext(); if( ctx ) ctx->SetException("Out of memory"); @@ -160,22 +112,14 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot, asUINT length, void *defVa } // Initialize the object - CScriptArray *a = new(mem) CScriptArray(length, defVal, ot); - - // It's possible the constructor raised a script exception, in which case we - // need to free the memory and return null instead, else we get a memory leak. - if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) - { - a->Release(); - return 0; - } + CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); return a; } -CScriptArray* CScriptArray::Create(asIObjectType *ot) +CScriptArray* CScriptArray::Create(asITypeInfo *ti) { - return CScriptArray::Create(ot, asUINT(0)); + return CScriptArray::Create(ti, asUINT(0)); } // This optional callback is called when the template type is first used by the compiler. @@ -183,16 +127,16 @@ CScriptArray* CScriptArray::Create(asIObjectType *ot) // 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(asIObjectType *ot, bool &dontGarbageCollect) +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 = ot->GetSubTypeId(); + int typeId = ti->GetSubTypeId(); if( typeId == asTYPEID_VOID ) return false; if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) { - asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId); + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); asDWORD flags = subtype->GetFlags(); if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) { @@ -215,7 +159,8 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl if( !found ) { // There is no default constructor - ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has 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; } } @@ -225,7 +170,7 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl // If value assignment for ref type has been disabled then the array // can be created if the type has a default factory function - if( !ot->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + 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++ ) @@ -243,7 +188,8 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl if( !found ) { // No default factory - ot->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has 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; } } @@ -266,7 +212,7 @@ static bool ScriptArrayTemplateCallback(asIObjectType *ot, bool &dontGarbageColl // 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. - asIObjectType *subtype = ot->GetEngine()->GetObjectTypeById(typeId); + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); asDWORD flags = subtype->GetFlags(); if( !(flags & asOBJ_GC) ) { @@ -317,7 +263,7 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine) UNUSED_VAR(r); // Register the object type user data clean up - engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE); + 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 ); @@ -326,45 +272,54 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine) 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, (asIObjectType*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint, const T &in)", asFUNCTIONPR(CScriptArray::Create, (asIObjectType*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + 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)", 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, (asIObjectType*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + 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)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); + 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, const T&in)", asMETHOD(CScriptArray, InsertAt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeAt(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); + 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? r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reserve(uint)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + 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, uint)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), 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, uint)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), 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 ); - r = engine->RegisterObjectMethod("array", "int find(const T&in) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(uint, const T&in) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(uint, const T&in) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), 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 a, const T&in 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); + // Register virtual properties r = engine->RegisterObjectMethod("array", "uint get_length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void set_length(uint)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); @@ -386,7 +341,8 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine) // 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, const T&in)", asMETHOD(CScriptArray, InsertAt), asCALL_THISCALL); assert( r >= 0 ); + 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 @@ -408,17 +364,20 @@ CScriptArray &CScriptArray::operator=(const CScriptArray &other) return *this; } -CScriptArray::CScriptArray(asIObjectType *ot, void *buf) +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 = ot; + objType = ti; objType->AddRef(); buffer = 0; Precache(); - asIScriptEngine *engine = ot->GetEngine(); + asIScriptEngine *engine = ti->GetEngine(); // Determine element size if( subTypeId & asTYPEID_MASK_OBJECT ) @@ -437,7 +396,7 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) } // Copy the values of the array elements from the buffer - if( (ot->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) + if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) { CreateBuffer(&buffer, length); @@ -445,7 +404,7 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) if( length > 0 ) memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); } - else if( ot->GetSubTypeId() & asTYPEID_OBJHANDLE ) + else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) { CreateBuffer(&buffer, length); @@ -459,7 +418,7 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) // its references too memset((((asUINT*)buf)+1), 0, length * elementSize); } - else if( ot->GetSubType()->GetFlags() & asOBJ_REF ) + else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) { // Only allocate the buffer, but not the objects subTypeId |= asTYPEID_OBJHANDLE; @@ -488,8 +447,8 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) { void *obj = At(n); asBYTE *srcObj = (asBYTE*)buf; - srcObj += 4 + n*ot->GetSubType()->GetSize(); - engine->AssignScriptObject(obj, srcObj, ot->GetSubType()); + srcObj += 4 + n*ti->GetSubType()->GetSize(); + engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); } } @@ -498,11 +457,14 @@ CScriptArray::CScriptArray(asIObjectType *ot, void *buf) objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); } -CScriptArray::CScriptArray(asUINT length, asIObjectType *ot) +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 = ot; + objType = ti; objType->AddRef(); buffer = 0; @@ -549,11 +511,14 @@ CScriptArray::CScriptArray(const CScriptArray &other) *this = other; } -CScriptArray::CScriptArray(asUINT length, void *defVal, asIObjectType *ot) +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 = ot; + objType = ti; objType->AddRef(); buffer = 0; @@ -662,9 +627,8 @@ void CScriptArray::Reserve(asUINT maxElements) return; } - // TODO: memcpy assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // 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 @@ -681,6 +645,34 @@ void CScriptArray::Resize(asUINT numElements) 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) { @@ -721,9 +713,8 @@ void CScriptArray::Resize(int delta, asUINT at) return; } - // TODO: memcpy assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // 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); @@ -739,17 +730,15 @@ void CScriptArray::Resize(int delta, asUINT at) else if( delta < 0 ) { Destruct(buffer, at, at-delta); - // TODO: memmove assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // 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 { - // TODO: memmove assumes the objects in the array doesn't hold pointers to themselves - // This should really be using the objects copy/move constructor to copy each object - // to the new location. It would most likely be a hit on the performance though. + // 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; @@ -779,7 +768,7 @@ bool CScriptArray::CheckMaxSize(asUINT numElements) return true; } -asIObjectType *CScriptArray::GetArrayObjectType() const +asITypeInfo *CScriptArray::GetArrayObjectType() const { return objType; } @@ -812,6 +801,61 @@ void CScriptArray::InsertAt(asUINT index, void *value) 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); @@ -859,6 +903,11 @@ 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) @@ -899,7 +948,7 @@ void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end) void **d = (void**)(buf->data + start * sizeof(void*)); asIScriptEngine *engine = objType->GetEngine(); - asIObjectType *subType = objType->GetSubType(); + asITypeInfo *subType = objType->GetSubType(); for( ; d < max; d++ ) { @@ -975,6 +1024,8 @@ bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext } else { + int r = 0; + if( subTypeId & asTYPEID_OBJHANDLE ) { // Allow sort to work even if the array contains null handles @@ -986,7 +1037,7 @@ bool CScriptArray::Less(const void *a, const void *b, bool asc, asIScriptContext if( cache && cache->cmpFunc ) { // TODO: Add proper error handling - int r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); + r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); if( subTypeId & asTYPEID_OBJHANDLE ) { @@ -1219,7 +1270,7 @@ int CScriptArray::Find(asUINT startAt, void *value) const if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) { asIScriptContext *ctx = asGetActiveContext(); - asIObjectType* subType = objType->GetEngine()->GetObjectTypeById(subTypeId); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); // Throw an exception if( ctx ) @@ -1302,6 +1353,8 @@ int CScriptArray::Find(asUINT startAt, void *value) const // 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); @@ -1317,17 +1370,17 @@ void *CScriptArray::GetArrayItemPointer(int index) // internal // Return pointer to data in buffer (object or primitive) -void *CScriptArray::GetDataPointer(void *buffer) +void *CScriptArray::GetDataPointer(void *buf) { if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) { // Real address of object - return reinterpret_cast(*(size_t*)buffer); + return reinterpret_cast(*(size_t*)buf); } else { // Primitive is just a raw data - return buffer; + return buf; } } @@ -1367,7 +1420,7 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) if( !cache || cache->cmpFunc == 0 ) { asIScriptContext *ctx = asGetActiveContext(); - asIObjectType* subType = objType->GetEngine()->GetObjectTypeById(subTypeId); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); // Throw an exception if( ctx ) @@ -1434,10 +1487,7 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) } 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(); + cmpContext = objType->GetEngine()->RequestContext(); } } @@ -1467,7 +1517,88 @@ void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) cmpContext->Abort(); } else - cmpContext->Release(); + objType->GetEngine()->ReturnContext(cmpContext); + } +} + +// 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; + } + + asBYTE tmp[16]; + 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 + 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); } } @@ -1510,7 +1641,7 @@ void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src) void **d = (void**)dst->data; void **s = (void**)src->data; - asIObjectType *subType = objType->GetSubType(); + asITypeInfo *subType = objType->GetSubType(); for( ; d < max; d++, s++ ) engine->AssignScriptObject(*d, *s, subType); } @@ -1561,7 +1692,7 @@ void CScriptArray::Precache() // If the sub type is a handle to const, then the methods must be const too bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; - asIObjectType *subType = objType->GetEngine()->GetObjectTypeById(subTypeId); + asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); if( subType ) { for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) @@ -1710,41 +1841,41 @@ bool CScriptArray::GetFlag() static void ScriptArrayFactory_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); } static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); asUINT length = gen->GetArgDWord(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, length); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); } static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); void *buf = gen->GetArgAddress(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, buf); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); } static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); asUINT length = gen->GetArgDWord(1); void *defVal = gen->GetArgAddress(2); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ot, length, defVal); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); } static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen) { - asIObjectType *ot = *(asIObjectType**)gen->GetAddressOfArg(0); + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); - *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ot, *dontGarbageCollect); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); } static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen) @@ -1808,6 +1939,14 @@ static void ScriptArrayInsertAt_Generic(asIScriptGeneric *gen) 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); @@ -1815,6 +1954,14 @@ static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) 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); @@ -1890,6 +2037,15 @@ static void ScriptArraySortDesc2_Generic(asIScriptGeneric *gen) 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(); @@ -1939,39 +2095,43 @@ static void RegisterScriptArray_Generic(asIScriptEngine *engine) int r = 0; UNUSED_VAR(r); - engine->SetObjectTypeUserDataCleanupCallback(CleanupObjectTypeArrayCache, ARRAY_CACHE); + 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)", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint, const T &in)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length)", 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)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "const T &opIndex(uint) const", asFUNCTION(ScriptArrayAt_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, const T&in)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void removeAt(uint)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void insertLast(const T&in)", asFUNCTION(ScriptArrayInsertLast_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); r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void reserve(uint)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "void resize(uint)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); + 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, uint)", asFUNCTION(ScriptArraySortAsc2_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, uint)", asFUNCTION(ScriptArraySortDesc2_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) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int find(uint, const T&in) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(const T&in) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); - r = engine->RegisterObjectMethod("array", "int findByRef(uint, const T&in) const", asFUNCTION(ScriptArrayFindByRef2_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); r = engine->RegisterObjectMethod("array", "uint get_length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectMethod("array", "void set_length(uint)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); diff --git a/src/scriptengine/scriptarray.hpp b/src/scriptengine/scriptarray.hpp index a1c0a0a1d..e6eb2783a 100644 --- a/src/scriptengine/scriptarray.hpp +++ b/src/scriptengine/scriptarray.hpp @@ -29,19 +29,19 @@ public: static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); // Factory functions - static CScriptArray *Create(asIObjectType *ot); - static CScriptArray *Create(asIObjectType *ot, asUINT length); - static CScriptArray *Create(asIObjectType *ot, asUINT length, void *defaultValue); - static CScriptArray *Create(asIObjectType *ot, void *listBuffer); + 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 - asIObjectType *GetArrayObjectType() const; - int GetArrayTypeId() const; - int GetElementTypeId() const; + asITypeInfo *GetArrayObjectType() const; + int GetArrayTypeId() const; + int GetElementTypeId() const; // Get the current size asUINT GetSize() const; @@ -73,20 +73,26 @@ public: // Array manipulation void InsertAt(asUINT index, void *value); - void RemoveAt(asUINT index); + 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(); @@ -95,17 +101,17 @@ public: void ReleaseAllHandles(asIScriptEngine *engine); protected: - mutable int refCount; - mutable bool gcFlag; - asIObjectType *objType; - SArrayBuffer *buffer; - int elementSize; - int subTypeId; + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SArrayBuffer *buffer; + int elementSize; + int subTypeId; // Constructors - CScriptArray(asIObjectType *ot, void *initBuf); // Called from script when initialized with list - CScriptArray(asUINT length, asIObjectType *ot); - CScriptArray(asUINT length, void *defVal, asIObjectType *ot); + 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(); diff --git a/src/scriptengine/scriptstdstring.cpp b/src/scriptengine/scriptstdstring.cpp index 381a78cc1..4da068109 100644 --- a/src/scriptengine/scriptstdstring.cpp +++ b/src/scriptengine/scriptstdstring.cpp @@ -1,33 +1,3 @@ -/* -AngelCode Scripting Library -Copyright (c) 2003-2015 Andreas Jonsson - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you -must not claim that you wrote the original software. If you use -this software in a product, an acknowledgment in the product -documentation would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - -The original version of this library can be located at: -http://www.angelcode.com/angelscript/ - -Andreas Jonsson -andreas@angelcode.com -*/ - #include "scriptstdstring.hpp" #include // assert() #include // std::stringstream @@ -37,119 +7,85 @@ andreas@angelcode.com #ifndef __psp2__ #include // setlocale() #endif -#include // std::map 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) -#if AS_USE_STRINGPOOL == 1 - -// By keeping the literal strings in a pool the application -// performance is improved as there are less string copies created. - -// The string pool will be kept as user data in the engine. We'll -// need a specific type to identify the string pool user data. -// 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 STRING_POOL = 1001; - -// This global static variable is placed here rather than locally within the -// StringFactory, due to memory leak detectors that don't see the deallocation -// of global variables. By placing the variable globally it will be initialized -// before the memory leak detector starts, thus it won't report the missing -// deallocation. An example of this the Marmalade leak detector initialized with -// IwGxInit() and finished with IwGxTerminate(). -static const string emptyString; +#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 -static const string &StringFactory(asUINT length, const char *s) +class CStdStringFactory : public asIStringFactory { - // Each engine instance has its own string pool - asIScriptContext *ctx = asGetActiveContext(); - if( ctx == 0 ) +public: + CStdStringFactory() {} + ~CStdStringFactory() { - // The string factory can only be called from a script - assert( ctx ); - return emptyString; + // The script engine must release each string + // constant that it has requested + assert(stringCache.size() == 0); } - asIScriptEngine *engine = ctx->GetEngine(); - // TODO: runtime optimize: Use unordered_map if C++11 is supported, i.e. MSVC10+, gcc 4.?+ - map *pool = reinterpret_cast< map* >(engine->GetUserData(STRING_POOL)); + const void *GetStringConstant(const char *data, asUINT length) + { + 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; + + return reinterpret_cast(&it->first); + } - if( !pool ) + int ReleaseStringConstant(const void *str) { - // The string pool hasn't been created yet, so we'll create it now - asAcquireExclusiveLock(); + if (str == 0) + return asERROR; - // Make sure the string pool wasn't created while we were waiting for the lock - pool = reinterpret_cast< map* >(engine->GetUserData(STRING_POOL)); - if( !pool ) - { - #if defined(__S3E__) - pool = new map; - #else - pool = new (nothrow) map; - #endif - if( pool == 0 ) - { - ctx->SetException("Out of memory"); - asReleaseExclusiveLock(); - return emptyString; - } - engine->SetUserData(pool, STRING_POOL); - } + map_t::iterator it = stringCache.find(*reinterpret_cast(str)); + if (it == stringCache.end()) + return asERROR; - asReleaseExclusiveLock(); + it->second--; + if (it->second == 0) + stringCache.erase(it); + return asSUCCESS; } - // We can't let other threads modify the pool while we query it - asAcquireSharedLock(); - - // First check if a string object hasn't been created already - map::iterator it; - it = pool->find(s); - if( it != pool->end() ) + int GetRawStringData(const void *str, char *data, asUINT *length) const { - asReleaseSharedLock(); - return it->second; - } + if (str == 0) + return asERROR; - asReleaseSharedLock(); + if (length) + *length = (asUINT)reinterpret_cast(str)->length(); - // Acquire an exclusive lock so we can add the new string to the pool - asAcquireExclusiveLock(); + if (data) + memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); - // Make sure the string wasn't created while we were waiting for the exclusive lock - it = pool->find(s); - if( it == pool->end() ) - { - // Create a new string object - it = pool->insert(map::value_type(s, string(s, length))).first; + return asSUCCESS; } - asReleaseExclusiveLock(); - return it->second; -} + // TODO: Make sure the access to the string cache is thread safe + map_t stringCache; +}; -static void CleanupEngineStringPool(asIScriptEngine *engine) -{ - map *pool = reinterpret_cast< map* >(engine->GetUserData(STRING_POOL)); - if( pool ) - delete pool; -} +static CStdStringFactory stringFactory; -#else -static string StringFactory(asUINT length, const char *s) -{ - return string(s, length); -} -#endif static void ConstructString(string *thisPointer) { @@ -371,7 +307,53 @@ static int StringCmp(const string &a, const string &b) 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, start); + 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_of(sub, (size_t)(start < 0 ? string::npos : start)); } // This function returns the index of the last position where the substring @@ -383,9 +365,26 @@ static int StringFindFirst(const string &sub, asUINT start, const string &str) 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); + 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) @@ -447,6 +446,50 @@ static string formatInt(asINT64 value, const string &options, asUINT width) 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) @@ -540,15 +583,59 @@ static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount) 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 ",". + // 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 *orig = setlocale(LC_NUMERIC, 0); @@ -578,7 +665,7 @@ 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, count); + ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); return ret; } @@ -591,7 +678,7 @@ static string StringSubString(asUINT start, int count, const string &str) // makro, so this wrapper was introduced as work around. static bool StringEquals(const std::string& lhs, const std::string& rhs) { - return lhs == rhs; + return lhs == rhs; } void RegisterStdString_Native(asIScriptEngine *engine) @@ -607,16 +694,7 @@ void RegisterStdString_Native(asIScriptEngine *engine) r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); #endif -#if AS_USE_STRINGPOOL == 1 - // Register the string factory - r = engine->RegisterStringFactory("const string &", asFUNCTION(StringFactory), asCALL_CDECL); assert( r >= 0 ); - - // Register the cleanup callback for the string pool - engine->SetEngineUserDataCleanupCallback(CleanupEngineStringPool, STRING_POOL); -#else - // Register the string factory - r = engine->RegisterStringFactory("string", asFUNCTION(StringFactory), asCALL_CDECL); assert( r >= 0 ); -#endif + r = engine->RegisterStringFactory("string", &stringFactory); // Register the object operator overloads r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); @@ -675,11 +753,20 @@ void RegisterStdString_Native(asIScriptEngine *engine) // 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 formatFloat(double val, const string &in options, uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); 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 @@ -694,112 +781,103 @@ void RegisterStdString_Native(asIScriptEngine *engine) #endif // TODO: Implement the following - // findFirstOf - // findLastOf - // findFirstNotOf - // findLastNotOf // findAndReplace - replaces a text found in the string // replaceRange - replaces a range of bytes in the string - // trim/trimLeft/trimRight // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" } -#if AS_USE_STRINGPOOL == 1 -static void StringFactoryGeneric(asIScriptGeneric *gen) -{ - asUINT length = gen->GetArgDWord(0); - const char *s = (const char*)gen->GetArgAddress(1); - - // Return a reference to a string - gen->SetReturnAddress(const_cast(&StringFactory(length, s))); -} -#else -static void StringFactoryGeneric(asIScriptGeneric *gen) -{ - asUINT length = gen->GetArgDWord(0); - const char *s = (const char*)gen->GetArgAddress(1); - - // Return a string value - new (gen->GetAddressOfReturnLocation()) string(StringFactory(length, s)); -} -#endif - static void ConstructStringGeneric(asIScriptGeneric * gen) { - new (gen->GetObject()) string(); + new (gen->GetObject()) string(); } static void CopyConstructStringGeneric(asIScriptGeneric * gen) { - string * a = static_cast(gen->GetArgObject(0)); - new (gen->GetObject()) string(*a); + 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(); + 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); + 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); + 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); + 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)); + 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 cmp = 0; + if( *a < *b ) cmp = -1; + else if( *a > *b ) cmp = 1; - *(int*)gen->GetAddressOfReturnLocation() = cmp; + *(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); + 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(); + 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); + 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))); + 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) @@ -818,6 +896,38 @@ static void StringFindLast_Generic(asIScriptGeneric * gen) *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); @@ -826,6 +936,14 @@ static void formatInt_Generic(asIScriptGeneric * gen) 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); @@ -843,6 +961,14 @@ static void parseInt_Generic(asIScriptGeneric *gen) 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)); @@ -852,21 +978,21 @@ static void parseFloat_Generic(asIScriptGeneric *gen) static void StringCharAtGeneric(asIScriptGeneric * gen) { - unsigned int index = gen->GetArgDWord(0); - string * self = static_cast(gen->GetObject()); + 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"); + 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))); - } + gen->SetReturnAddress(0); + } + else + { + gen->SetReturnAddress(&(self->operator [](index))); + } } static void AssignInt2StringGeneric(asIScriptGeneric *gen) @@ -921,163 +1047,163 @@ static void AssignBool2StringGeneric(asIScriptGeneric *gen) 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + // 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)); + new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); } void RegisterStdString_Generic(asIScriptEngine *engine) @@ -1088,16 +1214,7 @@ void RegisterStdString_Generic(asIScriptEngine *engine) // Register the string type r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); -#if AS_USE_STRINGPOOL == 1 - // Register the string factory - r = engine->RegisterStringFactory("const string &", asFUNCTION(StringFactoryGeneric), asCALL_GENERIC); assert( r >= 0 ); - - // Register the cleanup callback for the string pool - engine->SetEngineUserDataCleanupCallback(CleanupEngineStringPool, STRING_POOL); -#else - // Register the string factory - r = engine->RegisterStringFactory("string", asFUNCTION(StringFactoryGeneric), asCALL_GENERIC); assert( r >= 0 ); -#endif + r = engine->RegisterStringFactory("string", &stringFactory); // Register the object operator overloads r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); @@ -1147,13 +1264,22 @@ void RegisterStdString_Generic(asIScriptEngine *engine) 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 findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), 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 formatFloat(double val, const string &in options, uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_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); } diff --git a/src/scriptengine/scriptstdstring.hpp b/src/scriptengine/scriptstdstring.hpp index d7e3a49c6..9d8ac53cf 100644 --- a/src/scriptengine/scriptstdstring.hpp +++ b/src/scriptengine/scriptstdstring.hpp @@ -11,29 +11,17 @@ #ifndef SCRIPTSTDSTRING_H #define SCRIPTSTDSTRING_H -// String must be included before angelscript.h to avoid some errors during -// compilation with GetObject function -#include - #ifndef ANGELSCRIPT_H // Avoid having to inform include path if header is already include before #include #endif +#include + //--------------------------- // Compilation settings // -// The use of the string pool can improve performance quite drastically -// for scripts that work with a lot of literal string constants. -// -// 1 = on -// 0 = off - -#ifndef AS_USE_STRINGPOOL -#define AS_USE_STRINGPOOL 1 -#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. diff --git a/src/scriptengine/scriptstdstring_utils.cpp b/src/scriptengine/scriptstdstring_utils.cpp index d46fea751..3abd02896 100644 --- a/src/scriptengine/scriptstdstring_utils.cpp +++ b/src/scriptengine/scriptstdstring_utils.cpp @@ -28,7 +28,7 @@ static CScriptArray *StringSplit(const string &delim, const string &str) // TODO: This should only be done once // TODO: This assumes that CScriptArray was already registered - asIObjectType *arrayType = engine->GetObjectTypeByDecl("array"); + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); // Create the array object CScriptArray *array = CScriptArray::Create(arrayType);