Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
AngelCode Scripting Library
Copyright c 2003-2017 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:
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.
Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
This notice may not be removed or altered from any source distribution.
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{A70F9EB8-8109-4E35-847D-964A84D8BFE2}</ProjectGuid>
<RootNamespace>as_addons</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)\..\..\lib\win32\</OutDir>
<TargetExt>.lib</TargetExt>
<TargetName>$(ProjectName)d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)\..\..\lib\win64\</OutDir>
<TargetExt>.lib</TargetExt>
<TargetName>$(ProjectName)64d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)\..\..\lib\win32\</OutDir>
<TargetExt>.lib</TargetExt>
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)\..\..\lib\win64\</OutDir>
<TargetExt>.lib</TargetExt>
<TargetName>$(ProjectName)64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../../angelscript/include/;../include/</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>angelscriptd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../lib/win32</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>../../angelscript/include/;../include/</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>angelscriptd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../lib/win32</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>../../angelscript/include/;../include/</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>angelscript.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../lib/win32</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>../../angelscript/include/;../include/</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>angelscript.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>../../lib/win32</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\include\scriptany.h" />
<ClInclude Include="..\include\scriptarray.h" />
<ClInclude Include="..\include\scriptdictionary.h" />
<ClInclude Include="..\include\scripthandle.h" />
<ClInclude Include="..\include\scripthelper.h" />
<ClInclude Include="..\include\scriptmap.h" />
<ClInclude Include="..\include\scriptmath.h" />
<ClInclude Include="..\include\scriptstdstring.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\scriptany.cpp" />
<ClCompile Include="..\source\scriptarray.cpp" />
<ClCompile Include="..\source\scriptdictionary.cpp" />
<ClCompile Include="..\source\scripthandle.cpp" />
<ClCompile Include="..\source\scripthelper.cpp" />
<ClCompile Include="..\source\scriptmap.cpp" />
<ClCompile Include="..\source\scriptmath.cpp" />
<ClCompile Include="..\source\scriptstdstring.cpp" />
<ClCompile Include="..\source\scriptstdstring_utils.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\scriptarray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scriptdictionary.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scripthandle.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scriptmath.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scriptstdstring.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scriptany.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scriptmap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\scripthelper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\source\scriptany.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scriptarray.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scriptdictionary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scripthandle.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scriptmath.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scriptstdstring.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scriptstdstring_utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scriptmap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\source\scripthelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+103
View File
@@ -0,0 +1,103 @@
#Find the correct architecture to build for
ifndef ARCH
ARCH = $(shell getconf LONG_BIT)
endif
#Set correct flags for architecture
ifeq ($(ARCH), 32)
#Global
CXXFLAGS += -m32 -march=pentium4 -mtune=generic
#Arch name
ARCHNAME = x86
else
#Global
CXXFLAGS += -m64 -march=athlon64 -mtune=generic
#Arch name
ARCHNAME = x64
endif
#Global flags
BIN = libas_addons.a
SRCDIR = source/as_addons/source
ifeq ($(origin AR), default)
AR = gcc-ar
endif
UNAME = $(shell uname)
ifeq ($(UNAME), Darwin)
OSNAME = osx
else
OSNAME = lin
endif
ifdef DEBUG
OBJDIR = obj_d/$(OSNAME)$(ARCH)/as_addons
BINDIR = obj_d/$(OSNAME)$(ARCH)
CXXFLAGS += -O0 -g
CXXFLAGS += -D_DEBUG
else
OBJDIR = obj/$(OSNAME)$(ARCH)/as_addons
BINDIR = obj/$(OSNAME)$(ARCH)
CXXFLAGS += -Wno-unused-variable -Wno-unused-but-set-variable
CXXFLAGS += -Ofast
CXXFLAGS += -DNDEBUG
ifndef NLTO
CXXFLAGS += -flto
else
CXXFLAGS += -fno-lto
endif
endif
ifndef CC
CC = g++
endif
CXXFLAGS += -std=c++11
CXXFLAGS += -Wall -Wno-invalid-offsetof -Wno-switch -Wno-reorder
CXXFLAGS += -I./source/as_addons/include -I./source/as_addons/source
CXXFLAGS += -isystem./source/angelscript/include
#Source code files
SOURCES = \
scriptany.cpp \
scriptarray.cpp \
scriptdictionary.cpp \
scriptmap.cpp \
scripthandle.cpp \
scriptmath.cpp \
scriptstdstring.cpp \
scriptstdstring_utils.cpp \
scripthelper.cpp
CPP_FILES = $(addprefix $(SRCDIR)/, $(SOURCES))
OBJ_FILES = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.o))
DEP_FILES = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.d))
-include $(DEP_FILES)
compile: $(DEP_FILES) $(BINDIR)/$(BIN)
#Dependency files to take care of header changes
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
@mkdir -p $(dir $@)
@$(CC) $(CXXFLAGS) -MM -MT "$(@:.d=.o)" $< >> $@
#Object files are compiled separately
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
@mkdir -p $(dir $@)
@echo $<
@$(CC) $(CXXFLAGS) $< -c -o $@
#Complete binary compile
$(BINDIR)/$(BIN): $(OBJ_FILES)
@mkdir -p $(BINDIR)
$(AR) rcs $@ $^
clean:
@rm -rf $(OBJDIR)
@rm -f ./.depend
+76
View File
@@ -0,0 +1,76 @@
#ifndef SCRIPTANY_H
#define SCRIPTANY_H
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif
BEGIN_AS_NAMESPACE
class CScriptAny
{
public:
// Constructors
CScriptAny(asIScriptEngine *engine);
CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine);
// Memory management
int AddRef() const;
int Release() const;
// Copy the stored value from another any object
CScriptAny &operator=(const CScriptAny&);
int CopyFrom(const CScriptAny *other);
// Store the value, either as variable type, integer number, or real number
void Store(void *ref, int refTypeId);
void Store(asINT64 &value);
void Store(double &value);
// Retrieve the stored value, either as variable type, integer number, or real number
bool Retrieve(void *ref, int refTypeId) const;
bool Retrieve(asINT64 &value) const;
bool Retrieve(double &value) const;
// Get the type id of the stored value
int GetTypeId() const;
// GC methods
int GetRefCount();
void SetFlag();
bool GetFlag();
void EnumReferences(asIScriptEngine *engine);
void ReleaseAllHandles(asIScriptEngine *engine);
protected:
virtual ~CScriptAny();
void FreeObject();
mutable int refCount;
mutable bool gcFlag;
asIScriptEngine *engine;
// The structure for holding the values
struct valueStruct
{
union
{
asINT64 valueInt;
double valueFlt;
void *valueObj;
};
int typeId;
};
valueStruct value;
};
void RegisterScriptAny(asIScriptEngine *engine);
void RegisterScriptAny_Native(asIScriptEngine *engine);
void RegisterScriptAny_Generic(asIScriptEngine *engine);
END_AS_NAMESPACE
#endif
+113
View File
@@ -0,0 +1,113 @@
#ifndef SCRIPTARRAY_H
#define SCRIPTARRAY_H
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif
#include "../source/as_atomic.h"
// 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
struct SArrayBuffer;
struct SArrayCache;
class CScriptArray
{
public:
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();
void AddRef() const;
void Release() const;
// Type information
asITypeInfo *GetArrayObjectType() const;
int GetArrayTypeId() const;
int GetElementTypeId() const;
void Reserve(asUINT maxElements);
void Resize(asUINT numElements);
asUINT GetSize() const;
bool IsEmpty() const;
// Get a pointer to an element. Returns 0 if out of bounds
void *At(asUINT index);
const void *At(asUINT index) const;
// Get a pointer to the last element. Returns 0 if empty array.
void *Last();
const void *Last() const;
// Set value of an element
void SetValue(asUINT index, void *value);
CScriptArray &operator=(const CScriptArray&);
bool operator==(const CScriptArray &) const;
void InsertAt(asUINT index, void *value);
void RemoveAt(asUINT index);
void InsertLast(void *value);
void RemoveLast();
void Remove(void *value);
void RemoveAll(void *value);
void SortAsc();
void SortDesc();
void SortAsc(asUINT index, asUINT count);
void SortDesc(asUINT index, asUINT count);
void Sort(asUINT index, asUINT count, bool asc);
void Reverse();
int Find(void *value) const;
int Find(asUINT index, void *value) const;
// GC methods
int GetRefCount();
void SetFlag();
bool GetFlag();
void EnumReferences(asIScriptEngine *engine);
void ReleaseAllHandles(asIScriptEngine *engine);
protected:
mutable asCAtomic refCount;
mutable bool gcFlag;
asITypeInfo *objType;
SArrayBuffer *buffer;
int elementSize;
int subTypeId;
int numElements;
bool Less(const void *a, const void *b, bool asc, asIScriptContext *ctx, SArrayCache *cache);
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
+184
View File
@@ -0,0 +1,184 @@
#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 <angelscript.h>
#endif
#include "../source/as_atomic.h"
#include <string>
#ifdef _MSC_VER
// Turn off annoying warnings about truncated symbol names
#pragma warning (disable:4786)
#endif
#if __cplusplus >= 201103
#include <unordered_map>
#else
#include <map>
#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
{
protected:
// The structure for holding the values
struct valueStruct
{
union
{
asINT64 valueInt;
double valueFlt;
void *valueObj;
};
int typeId;
};
// The type of the internal map
#if __cplusplus >= 201103
typedef std::unordered_map<std::string, valueStruct> mapType;
#else
typedef std::map<std::string, valueStruct> mapType;
#endif
public:
// Memory management
CScriptDictionary(asIScriptEngine *engine);
void AddRef() const;
void Release() const;
CScriptDictionary &operator =(const CScriptDictionary &other);
// Sets/Gets a variable type value for a key
void Set(const std::string &key, void *value, int typeId);
bool Get(const std::string &key, void *value, int typeId) const;
// Sets/Gets an integer number value for a key
void Set(const std::string &key, asINT64 &value);
bool Get(const std::string &key, asINT64 &value) const;
// Sets/Gets a real number value for a key
void Set(const std::string &key, double &value);
bool Get(const std::string &key, double &value) const;
// Returns true if the key is set
bool Exists(const std::string &key) const;
bool IsEmpty() const;
asUINT GetSize() const;
// Deletes the key
void Delete(const std::string &key);
// Deletes all keys
void DeleteAll();
// Deletes all keys that have null reference values
void DeleteNulls();
// Get an array of all keys
CScriptArray *GetKeys() const;
// Garbage collections behaviours
int GetRefCount();
void SetGCFlag();
bool GetGCFlag();
void EnumReferences(asIScriptEngine *engine);
void ReleaseAllReferences(asIScriptEngine *engine);
// An iterator type to wrap for script iteration
struct Iterator
{
public:
// Returns the key of the current element or
// an error string if the iterator is at the end
const std::string &GetKey();
// Get the value of the current element
// Returns true if the value is of the correct type and
// the iterator is not at the end
bool Iterate(void *value, int typeId);
bool Iterate(std::string* key, void *value, int typeId);
// Returns whether the iterator is not at
// the end yet
bool IsValid();
// Copy the iterator
Iterator &operator =(const Iterator &other);
Iterator();
Iterator(const CScriptDictionary *container);
~Iterator();
friend CScriptDictionary;
protected:
bool first;
asUINT modCount;
const CScriptDictionary *container;
mapType::const_iterator it;
};
// Returns an iterator
Iterator GetIterator() const;
// Delete the current element of an iterator
void Delete(Iterator& it);
protected:
// We don't want anyone to call the destructor directly, it should be called through the Release method
virtual ~CScriptDictionary();
// Helper methods
void FreeValue(valueStruct &value);
bool Iterator_GetValue(mapType::const_iterator &it, void *value, int typeId) const;
// Our properties
asIScriptEngine *engine;
mutable asCAtomic refCount;
mutable bool gcFlag;
// Whenever we erase or insert a new key, we increment the modification count.
// Iterators check whether the modification count has changed, and will fail
// when it has. This makes iterator-based iteration safe for scripts.
asUINT modCount;
mapType 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
+65
View File
@@ -0,0 +1,65 @@
#ifndef SCRIPTHANDLE_H
#define SCRIPTHANDLE_H
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#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();
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
+48
View File
@@ -0,0 +1,48 @@
#ifndef SCRIPTHELPER_H
#define SCRIPTHELPER_H
#include <sstream>
#include <string>
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#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");
// Format the details of the script exception into a human readable text
std::string GetExceptionInfo(asIScriptContext *ctx, bool showStack = false);
END_AS_NAMESPACE
#endif
+180
View File
@@ -0,0 +1,180 @@
#ifndef SCRIPTMAP_H
#define SCRIPTMAP_H
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif
#include "../source/as_atomic.h"
#include <string>
#ifdef _MSC_VER
// Turn off annoying warnings about truncated symbol names
#pragma warning (disable:4786)
#endif
#if __cplusplus >= 201103 || _MSC_VER >= 1600
#include <unordered_map>
#else
#include <map>
#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 CScriptMap
{
protected:
// The structure for holding the values
struct valueStruct
{
union
{
asINT64 valueInt;
double valueFlt;
void *valueObj;
};
int typeId;
};
// The type of the internal map
#if __cplusplus >= 201103 || _MSC_VER >= 1600
typedef std::unordered_map<asINT64, valueStruct> mapType;
#else
typedef std::map<asINT64, valueStruct> mapType;
#endif
public:
// Memory management
CScriptMap(asIScriptEngine *engine);
void AddRef() const;
void Release() const;
CScriptMap &operator =(const CScriptMap &other);
// Sets/Gets a variable type value for a key
void Set(asINT64 key, void *value, int typeId);
bool Get(asINT64 key, void *value, int typeId) const;
// Sets/Gets an integer number value for a key
void Set(asINT64 key, asINT64 &value);
bool Get(asINT64 key, asINT64 &value) const;
// Sets/Gets a real number value for a key
void Set(asINT64 key, double &value);
bool Get(asINT64 key, double &value) const;
// Returns true if the key is set
bool Exists(asINT64 key) const;
bool IsEmpty() const;
asUINT GetSize() const;
// Deletes the key
void Delete(asINT64 key);
// Deletes all keys
void DeleteAll();
// Deletes all keys that have null reference values
void DeleteNulls();
// Get an array of all keys
CScriptArray *GetKeys() const;
// Garbage collections behaviours
int GetRefCount();
void SetGCFlag();
bool GetGCFlag();
void EnumReferences(asIScriptEngine *engine);
void ReleaseAllReferences(asIScriptEngine *engine);
// An iterator type to wrap for script iteration
struct Iterator
{
public:
// Returns the key of the current element or
// an error string if the iterator is at the end
asINT64 GetKey();
// Get the value of the current element
// Returns true if the value is of the correct type and
// the iterator is not at the end
bool Iterate(void *value, int typeId);
bool Iterate(asINT64* key, void *value, int typeId);
// Returns whether the iterator is not at
// the end yet
bool IsValid();
// Copy the iterator
Iterator &operator =(const Iterator &other);
Iterator();
Iterator(const CScriptMap *container);
~Iterator();
friend CScriptMap;
protected:
bool first;
asUINT modCount;
const CScriptMap *container;
mapType::const_iterator it;
};
// Returns an iterator
Iterator GetIterator() const;
// Delete the current element of an iterator
void Delete(Iterator& it);
protected:
// We don't want anyone to call the destructor directly, it should be called through the Release method
virtual ~CScriptMap();
// Helper methods
void FreeValue(valueStruct &value);
bool Iterator_GetValue(mapType::const_iterator &it, void *value, int typeId) const;
// Our properties
asIScriptEngine *engine;
mutable asCAtomic refCount;
mutable bool gcFlag;
// Whenever we erase or insert a new key, we increment the modification count.
// Iterators check whether the modification count has changed, and will fail
// when it has. This makes iterator-based iteration safe for scripts.
asUINT modCount;
mapType dict;
};
// This function will determine the configuration of the engine
// and use one of the two functions below to register the map object
void RegisterScriptMap(asIScriptEngine *engine);
// Call this function to register the math functions
// using native calling conventions
void RegisterScriptMap_Native(asIScriptEngine *engine);
// Use this one instead if native calling conventions
// are not supported on the target platform
void RegisterScriptMap_Generic(asIScriptEngine *engine);
END_AS_NAMESPACE
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef SCRIPTMATH_H
#define SCRIPTMATH_H
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif
BEGIN_AS_NAMESPACE
// This function will determine the configuration of the engine
// and use one of the two functions below to register the math functions
void RegisterScriptMath(asIScriptEngine *engine);
// Call this function to register the math functions
// using native calling conventions
void RegisterScriptMath_Native(asIScriptEngine *engine);
// Use this one instead if native calling conventions
// are not supported on the target platform
void RegisterScriptMath_Generic(asIScriptEngine *engine);
END_AS_NAMESPACE
#endif
@@ -0,0 +1,24 @@
//
// 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
#include <angelscript.h>
#include <string>
BEGIN_AS_NAMESPACE
void RegisterStdString(asIScriptEngine *engine);
void RegisterStdStringUtils(asIScriptEngine *engine);
END_AS_NAMESPACE
#endif
+480
View File
@@ -0,0 +1,480 @@
#include "scriptany.h"
#include <new>
#include <assert.h>
#include <string.h>
BEGIN_AS_NAMESPACE
// We'll use the generic interface for the factories as we need the engine pointer
static void ScriptAnyFactory_Generic(asIScriptGeneric *gen)
{
asIScriptEngine *engine = gen->GetEngine();
*(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(engine);
}
static void ScriptAnyFactory2_Generic(asIScriptGeneric *gen)
{
asIScriptEngine *engine = gen->GetEngine();
void *ref = (void*)gen->GetArgAddress(0);
int refType = gen->GetArgTypeId(0);
*(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(ref,refType,engine);
}
static CScriptAny &ScriptAnyAssignment(CScriptAny *other, CScriptAny *self)
{
return *self = *other;
}
static void ScriptAnyAssignment_Generic(asIScriptGeneric *gen)
{
CScriptAny *other = (CScriptAny*)gen->GetArgObject(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
*self = *other;
gen->SetReturnObject(self);
}
static void ScriptAny_Store_Generic(asIScriptGeneric *gen)
{
void *ref = (void*)gen->GetArgAddress(0);
int refTypeId = gen->GetArgTypeId(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
self->Store(ref, refTypeId);
}
static void ScriptAny_StoreInt_Generic(asIScriptGeneric *gen)
{
asINT64 *ref = (asINT64*)gen->GetArgAddress(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
self->Store(*ref);
}
static void ScriptAny_StoreFlt_Generic(asIScriptGeneric *gen)
{
double *ref = (double*)gen->GetArgAddress(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
self->Store(*ref);
}
static void ScriptAny_Retrieve_Generic(asIScriptGeneric *gen)
{
void *ref = (void*)gen->GetArgAddress(0);
int refTypeId = gen->GetArgTypeId(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(ref, refTypeId);
}
static void ScriptAny_RetrieveInt_Generic(asIScriptGeneric *gen)
{
asINT64 *ref = (asINT64*)gen->GetArgAddress(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref);
}
static void ScriptAny_RetrieveFlt_Generic(asIScriptGeneric *gen)
{
double *ref = (double*)gen->GetArgAddress(0);
CScriptAny *self = (CScriptAny*)gen->GetObject();
*(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref);
}
static void ScriptAny_AddRef_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
self->AddRef();
}
static void ScriptAny_Release_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
self->Release();
}
static void ScriptAny_GetRefCount_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
}
static void ScriptAny_SetFlag_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
self->SetFlag();
}
static void ScriptAny_GetFlag_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
*(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag();
}
static void ScriptAny_EnumReferences_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
self->EnumReferences(engine);
}
static void ScriptAny_ReleaseAllHandles_Generic(asIScriptGeneric *gen)
{
CScriptAny *self = (CScriptAny*)gen->GetObject();
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
self->ReleaseAllHandles(engine);
}
void RegisterScriptAny(asIScriptEngine *engine)
{
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
RegisterScriptAny_Generic(engine);
else
RegisterScriptAny_Native(engine);
}
void RegisterScriptAny_Native(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF/* | asOBJ_GC*/); assert( r >= 0 );
// We'll use the generic interface for the constructor as we need the engine pointer
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptAny,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptAny,Release), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "void store(?&in)", asMETHODPR(CScriptAny,Store,(void*,int),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asMETHODPR(CScriptAny,Store,(asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "void store(const double&in)", asMETHODPR(CScriptAny,Store,(double&),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "bool retrieve(?&out)", asMETHODPR(CScriptAny,Retrieve,(void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out)", asMETHODPR(CScriptAny,Retrieve,(asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "bool retrieve(double&out)", asMETHODPR(CScriptAny,Retrieve,(double&) const,bool), asCALL_THISCALL); assert( r >= 0 );
// Register GC behaviours
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptAny,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptAny,SetFlag), asCALL_THISCALL); assert( r >= 0 );
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptAny,GetFlag), asCALL_THISCALL); assert( r >= 0 );
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptAny,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
//r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptAny,ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 );
}
void RegisterScriptAny_Generic(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
// We'll use the generic interface for the constructor as we need the engine pointer
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in)", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptAny_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptAny_Release_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "void store(?&in)", asFUNCTION(ScriptAny_Store_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asFUNCTION(ScriptAny_StoreInt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "void store(const double&in)", asFUNCTION(ScriptAny_StoreFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asFUNCTION(ScriptAny_Retrieve_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asFUNCTION(ScriptAny_RetrieveInt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asFUNCTION(ScriptAny_RetrieveFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
// Register GC behaviours
r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptAny_GetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptAny_SetFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptAny_GetFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptAny_EnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptAny_ReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 );
}
CScriptAny &CScriptAny::operator=(const CScriptAny &other)
{
// Hold on to the object type reference so it isn't destroyed too early
if( other.value.typeId & asTYPEID_MASK_OBJECT )
{
asITypeInfo *ti = engine->GetTypeInfoById(other.value.typeId);
if( ti )
ti->AddRef();
}
FreeObject();
value.typeId = other.value.typeId;
if( value.typeId & asTYPEID_OBJHANDLE )
{
// For handles, copy the pointer and increment the reference count
value.valueObj = other.value.valueObj;
engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
}
else if( value.typeId & asTYPEID_MASK_OBJECT )
{
// Create a copy of the object
value.valueObj = engine->CreateScriptObjectCopy(other.value.valueObj, engine->GetTypeInfoById(value.typeId));
}
else
{
// Primitives can be copied directly
value.valueInt = other.value.valueInt;
}
return *this;
}
int CScriptAny::CopyFrom(const CScriptAny *other)
{
if( other == 0 ) return asINVALID_ARG;
*this = *(CScriptAny*)other;
return 0;
}
CScriptAny::CScriptAny(asIScriptEngine *engine)
{
this->engine = engine;
refCount = 1;
gcFlag = false;
value.typeId = 0;
value.valueInt = 0;
// Notify the garbage collector of this object
//engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any"));
}
CScriptAny::CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine)
{
this->engine = engine;
refCount = 1;
gcFlag = false;
value.typeId = 0;
value.valueInt = 0;
// Notify the garbage collector of this object
//engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any"));
Store(ref, refTypeId);
}
CScriptAny::~CScriptAny()
{
FreeObject();
}
void CScriptAny::Store(void *ref, int refTypeId)
{
// This method is not expected to be used for primitive types, except for bool, int64, or double
assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_VOID || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE );
// Hold on to the object type reference so it isn't destroyed too early
if( refTypeId & asTYPEID_MASK_OBJECT )
{
asITypeInfo *ti = engine->GetTypeInfoById(refTypeId);
if( ti )
ti->AddRef();
}
FreeObject();
value.typeId = refTypeId;
if( value.typeId & asTYPEID_OBJHANDLE )
{
// We're receiving a reference to the handle, so we need to dereference it
value.valueObj = *(void**)ref;
engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
}
else if( value.typeId & asTYPEID_MASK_OBJECT )
{
// Create a copy of the object
value.valueObj = engine->CreateScriptObjectCopy(ref, engine->GetTypeInfoById(value.typeId));
}
else
{
// Primitives can be copied directly
value.valueInt = 0;
// Copy the primitive value
// We receive a pointer to the value.
int size = engine->GetSizeOfPrimitiveType(value.typeId);
memcpy(&value.valueInt, ref, size);
}
}
void CScriptAny::Store(double &ref)
{
Store(&ref, asTYPEID_DOUBLE);
}
void CScriptAny::Store(asINT64 &ref)
{
Store(&ref, asTYPEID_INT64);
}
bool CScriptAny::Retrieve(void *ref, int refTypeId) const
{
// This method is not expected to be used for primitive types, except for bool, int64, or double
assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE );
if( refTypeId & asTYPEID_OBJHANDLE )
{
// Is the handle type compatible with the stored value?
// 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( (value.typeId & asTYPEID_MASK_OBJECT) )
{
// Don't allow the retrieval if the stored handle is to a const object but not the wanted handle
if( (value.typeId & asTYPEID_HANDLETOCONST) && !(refTypeId & asTYPEID_HANDLETOCONST) )
return false;
// RefCastObject will increment the refCount of the returned pointer if successful
engine->RefCastObject(value.valueObj, engine->GetTypeInfoById(value.typeId), engine->GetTypeInfoById(refTypeId), reinterpret_cast<void**>(ref));
if( *(asPWORD*)ref == 0 )
return false;
return true;
}
}
else if( refTypeId & asTYPEID_MASK_OBJECT )
{
// Is the object type compatible with the stored value?
// Copy the object into the given reference
if( value.typeId == refTypeId )
{
engine->AssignScriptObject(ref, value.valueObj, engine->GetTypeInfoById(value.typeId));
return true;
}
}
else
{
// Is the primitive type compatible with the stored value?
if( value.typeId == refTypeId )
{
int size = engine->GetSizeOfPrimitiveType(refTypeId);
memcpy(ref, &value.valueInt, size);
return true;
}
// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
if( value.typeId == asTYPEID_INT64 && refTypeId == asTYPEID_DOUBLE )
{
*(double*)ref = double(value.valueInt);
return true;
}
else if( value.typeId == asTYPEID_DOUBLE && refTypeId == asTYPEID_INT64 )
{
*(asINT64*)ref = asINT64(value.valueFlt);
return true;
}
}
return false;
}
bool CScriptAny::Retrieve(asINT64 &outValue) const
{
return Retrieve(&outValue, asTYPEID_INT64);
}
bool CScriptAny::Retrieve(double &outValue) const
{
return Retrieve(&outValue, asTYPEID_DOUBLE);
}
int CScriptAny::GetTypeId() const
{
return value.typeId;
}
void CScriptAny::FreeObject()
{
// If it is a handle or a ref counted object, call release
if( value.typeId & asTYPEID_MASK_OBJECT )
{
// Let the engine release the object
asITypeInfo *ti = engine->GetTypeInfoById(value.typeId);
engine->ReleaseScriptObject(value.valueObj, ti);
// Release the object type info
if( ti )
ti->Release();
value.valueObj = 0;
value.typeId = 0;
}
// For primitives, there's nothing to do
}
void CScriptAny::EnumReferences(asIScriptEngine *inEngine)
{
// If we're holding a reference, we'll notify the garbage collector of it
if( value.valueObj && (value.typeId & asTYPEID_MASK_OBJECT) )
{
inEngine->GCEnumCallback(value.valueObj);
// The object type itself is also garbage collected
asITypeInfo *ti = inEngine->GetTypeInfoById(value.typeId);
if( ti )
inEngine->GCEnumCallback(ti);
}
}
void CScriptAny::ReleaseAllHandles(asIScriptEngine * /*engine*/)
{
FreeObject();
}
int CScriptAny::AddRef() const
{
// Increase counter and clear flag set by GC
gcFlag = false;
return asAtomicInc(refCount);
}
int CScriptAny::Release() const
{
// Decrease the ref counter
gcFlag = false;
if( asAtomicDec(refCount) == 0 )
{
// Delete this object as no more references to it exists
delete this;
return 0;
}
return refCount;
}
int CScriptAny::GetRefCount()
{
return refCount;
}
void CScriptAny::SetFlag()
{
gcFlag = true;
}
bool CScriptAny::GetFlag()
{
return gcFlag;
}
END_AS_NAMESPACE
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,771 @@
#include <assert.h>
#include <string.h>
#include "scriptdictionary.h"
#include "scriptarray.h"
#include "../source/as_scriptengine.h"
#include "../source/as_scriptobject.h"
BEGIN_AS_NAMESPACE
using namespace std;
bool IsHandleCompatibleWithObject(asCScriptEngine* engine, void *obj, int objTypeId, int handleTypeId)
{
// if equal, then it is obvious they are compatible
if( objTypeId == handleTypeId )
return true;
// Get the actual data types from the type ids
asCDataType objDt = engine->GetDataTypeFromTypeId(objTypeId);
asCDataType hdlDt = engine->GetDataTypeFromTypeId(handleTypeId);
// A handle to const cannot be passed to a handle that is not referencing a const object
if( objDt.IsHandleToConst() && !hdlDt.IsHandleToConst() )
return false;
if( objDt.GetTypeInfo() == hdlDt.GetTypeInfo() )
{
// The object type is equal
return true;
}
else if( objDt.IsScriptObject() && obj )
{
// Get the true type from the object instance
asITypeInfo *objType = ((asCScriptObject*)obj)->GetObjectType();
// Check if the object implements the interface, or derives from the base class
// This will also return true, if the requested handle type is an exact match for the object type
if( objType->Implements(hdlDt.GetTypeInfo()) ||
objType->DerivesFrom(hdlDt.GetTypeInfo()) )
return true;
}
return false;
}
//--------------------------------------------------------------------------
// CScriptDictionary implementation
CScriptDictionary::CScriptDictionary(asIScriptEngine *engine)
{
// We start with one reference
refCount.set(1);
gcFlag = false;
// Start at the zeroth modification
modCount = 0;
// 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.
this->engine = engine;
// Notify the garbage collector of this object
// TODO: The type id should be cached
engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("dictionary"));
}
CScriptDictionary::~CScriptDictionary()
{
// Delete all keys and values
DeleteAll();
}
void CScriptDictionary::AddRef() const
{
// We need to clear the GC flag
gcFlag = false;
refCount.atomicInc();
}
void CScriptDictionary::Release() const
{
// We need to clear the GC flag
gcFlag = false;
if( refCount.atomicDec() == 0 )
delete this;
}
int CScriptDictionary::GetRefCount()
{
return refCount.get();
}
void CScriptDictionary::SetGCFlag()
{
gcFlag = true;
}
bool CScriptDictionary::GetGCFlag()
{
return gcFlag;
}
void CScriptDictionary::EnumReferences(asIScriptEngine *engine)
{
// Call the gc enum callback for each of the objects
mapType::iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
{
if( it->second.typeId & asTYPEID_MASK_OBJECT )
engine->GCEnumCallback(it->second.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
mapType::const_iterator it;
for( it = other.dict.begin(); it != other.dict.end(); it++ )
{
if( it->second.typeId & asTYPEID_OBJHANDLE )
Set(it->first, (void*)&it->second.valueObj, it->second.typeId);
else if( it->second.typeId & asTYPEID_MASK_OBJECT )
Set(it->first, (void*)it->second.valueObj, it->second.typeId);
else
Set(it->first, (void*)&it->second.valueInt, it->second.typeId);
}
return *this;
}
void CScriptDictionary::Set(const string &key, void *value, int typeId)
{
valueStruct valStruct = {{0},0};
valStruct.typeId = typeId;
if( typeId & asTYPEID_OBJHANDLE )
{
// We're receiving a reference to the handle, so we need to dereference it
valStruct.valueObj = *(void**)value;
engine->AddRefScriptObject(valStruct.valueObj, engine->GetTypeInfoById(typeId));
}
else if( typeId & asTYPEID_MASK_OBJECT )
{
// Create a copy of the object
valStruct.valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId));
}
else
{
// Copy the primitive value
// We receive a pointer to the value.
int size = engine->GetSizeOfPrimitiveType(typeId);
memcpy(&valStruct.valueInt, value, size);
}
mapType::iterator it;
it = dict.find(key);
if( it != dict.end() )
{
FreeValue(it->second);
// Insert the new value
it->second = valStruct;
}
else
{
dict.insert(mapType::value_type(key, valStruct));
++modCount;
}
}
// 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 string &key, asINT64 &value)
{
Set(key, &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 string &key, double &value)
{
Set(key, &value, asTYPEID_DOUBLE);
}
// This helper function exists to assist various dictionary and iterator
// methods that want to retrieve a value from a standard iterator
bool CScriptDictionary::Iterator_GetValue(CScriptDictionary::mapType::const_iterator &it, 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( (it->second.typeId & asTYPEID_MASK_OBJECT) &&
IsHandleCompatibleWithObject((asCScriptEngine*)engine, it->second.valueObj, it->second.typeId, typeId) )
{
engine->AddRefScriptObject(it->second.valueObj, engine->GetTypeInfoById(it->second.typeId));
*(void**)value = it->second.valueObj;
return true;
}
}
else if( typeId & asTYPEID_MASK_OBJECT )
{
// Verify that the copy can be made
bool isCompatible = false;
if( it->second.typeId == typeId )
isCompatible = true;
// Copy the object into the given reference
if( isCompatible )
{
engine->AssignScriptObject(value, it->second.valueObj, engine->GetTypeInfoById(typeId));
return true;
}
}
else
{
if( it->second.typeId == typeId )
{
int size = engine->GetSizeOfPrimitiveType(typeId);
memcpy(value, &it->second.valueInt, size);
return true;
}
// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
if( it->second.typeId == asTYPEID_INT64 && typeId == asTYPEID_DOUBLE )
{
*(double*)value = double(it->second.valueInt);
return true;
}
else if( it->second.typeId == asTYPEID_DOUBLE && typeId == asTYPEID_INT64 )
{
*(asINT64*)value = asINT64(it->second.valueFlt);
return true;
}
}
// 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 true if the value was successfully retrieved
bool CScriptDictionary::Get(const string &key, void *value, int typeId) const
{
mapType::const_iterator it;
it = dict.find(key);
if( it != dict.end() )
{
// This logic is already implemented in the iterator wrapper,
// so defer to that function from here
return Iterator_GetValue(it, value, typeId);
}
return false;
}
bool CScriptDictionary::Get(const string &key, asINT64 &value) const
{
return Get(key, &value, asTYPEID_INT64);
}
bool CScriptDictionary::Get(const string &key, double &value) const
{
return Get(key, &value, asTYPEID_DOUBLE);
}
bool CScriptDictionary::Exists(const string &key) const
{
mapType::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());
}
void CScriptDictionary::Delete(const string &key)
{
mapType::iterator it;
it = dict.find(key);
if( it != dict.end() )
{
FreeValue(it->second);
dict.erase(it);
++modCount;
}
}
void CScriptDictionary::DeleteAll()
{
mapType::iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
FreeValue(it->second);
dict.clear();
}
void CScriptDictionary::DeleteNulls()
{
mapType::iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
{
if( it->second.typeId & asTYPEID_OBJHANDLE )
if( it->second.valueObj == 0 )
it = dict.erase(it);
}
++modCount;
}
void CScriptDictionary::FreeValue(valueStruct &value)
{
// If it is a handle or a ref counted object, call release
if( value.typeId & asTYPEID_MASK_OBJECT )
{
// Let the engine release the object
engine->ReleaseScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
value.valueObj = 0;
value.typeId = 0;
}
// For primitives, there's nothing to do
}
CScriptArray* CScriptDictionary::GetKeys() const
{
// TODO: optimize: The string array type should only be determined once.
// It should be recomputed when registering the dictionary class.
// Only problem is if multiple engines are used, as they may not
// share the same type id. Alternatively it can be stored in the
// user data for the dictionary type.
int stringArrayType = engine->GetTypeIdByDecl("array<string>");
asITypeInfo *ot = engine->GetTypeInfoById(stringArrayType);
// Create the array object
CScriptArray *array = new CScriptArray(dict.size(), ot);
long current = -1;
mapType::const_iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
{
current++;
*(string*)array->At(current) = it->first;
}
return array;
}
CScriptDictionary::Iterator CScriptDictionary::GetIterator() const {
return Iterator(this);
}
void CScriptDictionary::Delete(CScriptDictionary::Iterator& it) {
if( it.container != this ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Mismatched script container and iterator.");
return;
}
if( it.it == dict.end() ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Deleting invalid iterator.");
return;
}
it.it = dict.erase(it.it);
it.first = true;
++modCount;
it.modCount = modCount;
}
//--------------------------------------------------------------------------
// Iterator implementation
static const std::string errorString = "(error)";
CScriptDictionary::Iterator::Iterator() {
container = 0;
}
CScriptDictionary::Iterator::Iterator(const CScriptDictionary *container) {
this->container = container;
// Start the iteration
it = container->dict.begin();
first = true;
// Track the modification count of the dictionary
// so we can safely fail when the dictionary is altered
modCount = container->modCount;
// Keep a reference to the dictionary so it doesn't
// get destroyed from under us
container->AddRef();
}
CScriptDictionary::Iterator::~Iterator() {
// Release dictionary reference
if(container)
container->Release();
}
static void DefaultConstructIterator(void *memory) {
new(memory) CScriptDictionary::Iterator();
}
static void ConstructIterator(void *memory, const CScriptDictionary *container) {
new(memory) CScriptDictionary::Iterator(container);
}
static void DestructIterator(CScriptDictionary::Iterator &it) {
it.~Iterator();
}
const std::string &CScriptDictionary::Iterator::GetKey() {
if( !container || modCount != container->modCount || it == container->dict.end() ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Iterator not valid or dictionary changed.");
return errorString;
}
return it->first;
}
bool CScriptDictionary::Iterator::Iterate(void *value, int typeId) {
return Iterate(0, value, typeId);
}
bool CScriptDictionary::Iterator::Iterate(string* key, void *value, int typeId) {
if( !container ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Iterating on invalid iterator.");
return false;
}
if( modCount != container->modCount ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Dictionary changed during iteration.");
return false;
}
if( it == container->dict.end() )
return false;
if( first )
first = false;
else
++it;
if( it == container->dict.end() )
return false;
if( key )
*key = it->first;
if( container->Iterator_GetValue(it, value, typeId) )
{
return true;
}
else
{
// The caller can check IsValid to see if the iteration can still
// continue because the type was wrong, or whether it has really ended
return false;
}
}
bool CScriptDictionary::Iterator::IsValid() {
return container && modCount == container->modCount && it != container->dict.end();
}
CScriptDictionary::Iterator &CScriptDictionary::Iterator::operator =(const CScriptDictionary::Iterator &other) {
if(other.container)
other.container->AddRef();
if(container)
container->Release();
modCount = other.modCount;
container = other.container;
it = other.it;
first = other.first;
return *this;
}
//--------------------------------------------------------------------------
// Generic wrappers
void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen)
{
*(CScriptDictionary**)gen->GetAddressOfReturnLocation() = new CScriptDictionary(gen->GetEngine());
}
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();
string *key = *(string**)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();
string *key = *(string**)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
dict->Set(*key, *(asINT64*)ref);
}
void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen)
{
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
string *key = *(string**)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
dict->Set(*key, *(double*)ref);
}
void ScriptDictionaryGet_Generic(asIScriptGeneric *gen)
{
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
string *key = *(string**)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();
string *key = *(string**)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();
string *key = *(string**)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();
string *key = *(string**)gen->GetAddressOfArg(0);
bool ret = dict->Exists(*key);
*(bool*)gen->GetAddressOfReturnLocation() = ret;
}
void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen)
{
CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject();
string *key = *(string**)gen->GetAddressOfArg(0);
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();
}
//--------------------------------------------------------------------------
// 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)
{
int r;
//Register iterator type so we can use it later
r = engine->RegisterObjectType("dictionary_iterator", sizeof(CScriptDictionary::Iterator), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); 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_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 string&,void*,int),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, int64&in)", asMETHODPR(CScriptDictionary,Set,(const string&,asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, double&in)", asMETHODPR(CScriptDictionary,Set,(const string&,double&),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const string&,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", "void delete(const string &in)", asMETHODPR(CScriptDictionary, Delete, (const string&), void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "void delete(dictionary_iterator&)", asMETHODPR(CScriptDictionary, Delete, (CScriptDictionary::Iterator&), void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "void deleteNulls()", asMETHOD(CScriptDictionary,DeleteNulls), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "dictionary_iterator iterator()", asMETHOD(CScriptDictionary,GetIterator), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("dictionary", "array<string> @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), 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
// Register iterator methods
r = engine->RegisterObjectBehaviour("dictionary_iterator", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(DefaultConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("dictionary_iterator", asBEHAVE_CONSTRUCT, "void f(const dictionary &in)", asFUNCTION(ConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("dictionary_iterator", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
r = engine->RegisterObjectMethod("dictionary_iterator", "const string& get_key()", asMETHOD(CScriptDictionary::Iterator, GetKey), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("dictionary_iterator", "bool iterate(?&out)", asMETHODPR(CScriptDictionary::Iterator, Iterate, (void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("dictionary_iterator", "bool iterate(string &out, ?&out)", asMETHODPR(CScriptDictionary::Iterator, Iterate, (string*,void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("dictionary_iterator", "bool get_valid()", asMETHOD(CScriptDictionary::Iterator, IsValid), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("dictionary_iterator", "dictionary_iterator& opAssign(const dictionary_iterator &in)", asMETHOD(CScriptDictionary::Iterator, operator=), asCALL_THISCALL); assert( r>= 0 );
}
void RegisterScriptDictionary_Generic(asIScriptEngine *engine)
{
int r;
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_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, ?&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, 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, 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", "void 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<string> @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_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 );
}
END_AS_NAMESPACE
+329
View File
@@ -0,0 +1,329 @@
#include "scripthandle.h"
#include <new>
#include <assert.h>
#include <string.h>
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<obj>(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 RegisterScriptHandle_Native(asIScriptEngine *engine)
{
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 | asGetTypeTraits<CScriptHandle>()); assert( r >= 0 );
#else
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | 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->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<CScriptHandle*>(gen->GetObject());
new(self) CScriptHandle();
}
void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen)
{
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(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<CScriptHandle*>(gen->GetObject());
Construct(self, ref, typeId);
}
void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen)
{
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
self->~CScriptHandle();
}
void CScriptHandle_Cast_Generic(asIScriptGeneric *gen)
{
void **ref = reinterpret_cast<void**>(gen->GetArgAddress(0));
int typeId = gen->GetArgTypeId(0);
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(gen->GetObject());
self->Cast(ref, typeId);
}
void CScriptHandle_Assign_Generic(asIScriptGeneric *gen)
{
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(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<CScriptHandle*>(gen->GetObject());
self->Assign(ref, typeId);
gen->SetReturnAddress(self);
}
void CScriptHandle_Equals_Generic(asIScriptGeneric *gen)
{
CScriptHandle *other = reinterpret_cast<CScriptHandle*>(gen->GetArgAddress(0));
CScriptHandle *self = reinterpret_cast<CScriptHandle*>(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<CScriptHandle*>(gen->GetObject());
gen->SetReturnByte(self->Equals(ref, typeId));
}
void RegisterScriptHandle_Generic(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | 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->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
+937
View File
@@ -0,0 +1,937 @@
#include <string.h>
#include "scripthelper.h"
#include <assert.h>
#include <stdio.h>
#include <fstream>
#include <set>
#include <stdlib.h>
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, &paramTypeId, &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, &paramTypeId, &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 )
{
func->Release();
if( !ctx ) execCtx->Release();
return r;
}
// 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<void**>(ref) == 0 );
*reinterpret_cast<void**>(ref) = *reinterpret_cast<void**>(execCtx->GetAddressOfReturnValue());
engine->AddRefScriptObject(*reinterpret_cast<void**>(ref), engine->GetTypeInfoById(refTypeId));
}
else if( refTypeId & asTYPEID_MASK_OBJECT )
{
// Expect the pointer to point to a valid object
assert( *reinterpret_cast<void**>(ref) != 0 );
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(currNamespace.c_str());
// 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<asITypeInfo*> 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() << "\"\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() << "\"\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) << "\"\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<asITypeInfo*>::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() << "\"\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";
}
engine->SetDefaultNamespace("");
// Write string factory
strm << "\n// String factory\n";
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)
{
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() );
// 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<asEBehaviours>(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;
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);
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());
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<void*>(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);
r = engine->RegisterStringFactory(type.c_str(), asFUNCTION(0), asCALL_GENERIC);
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() << "\n";
text << "sect: " << 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() << " (" << 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();
}
END_AS_NAMESPACE
+743
View File
@@ -0,0 +1,743 @@
#include <assert.h>
#include <string.h>
#include "scriptmap.h"
#include "scriptarray.h"
#include "../source/as_scriptengine.h"
#include "../source/as_scriptobject.h"
BEGIN_AS_NAMESPACE
using namespace std;
extern bool IsHandleCompatibleWithObject(asCScriptEngine* engine, void *obj, int objTypeId, int handleTypeId);
//--------------------------------------------------------------------------
// CScriptMap implementation
CScriptMap::CScriptMap(asIScriptEngine *engine)
{
// We start with one reference
refCount.set(1);
gcFlag = false;
// Start at the zeroth modification
modCount = 0;
// 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.
this->engine = engine;
// Notify the garbage collector of this object
// TODO: The type id should be cached
engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("map"));
}
CScriptMap::~CScriptMap()
{
// Delete all keys and values
DeleteAll();
}
void CScriptMap::AddRef() const
{
// We need to clear the GC flag
gcFlag = false;
refCount.atomicInc();
}
void CScriptMap::Release() const
{
// We need to clear the GC flag
gcFlag = false;
if( refCount.atomicDec() == 0 )
delete this;
}
int CScriptMap::GetRefCount()
{
return refCount.get();
}
void CScriptMap::SetGCFlag()
{
gcFlag = true;
}
bool CScriptMap::GetGCFlag()
{
return gcFlag;
}
void CScriptMap::EnumReferences(asIScriptEngine *engine)
{
// Call the gc enum callback for each of the objects
mapType::iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
{
if( it->second.typeId & asTYPEID_MASK_OBJECT )
engine->GCEnumCallback(it->second.valueObj);
}
}
void CScriptMap::ReleaseAllReferences(asIScriptEngine * /*engine*/)
{
// We're being told to release all references in
// order to break circular references for dead objects
DeleteAll();
}
CScriptMap &CScriptMap::operator =(const CScriptMap &other)
{
// Clear everything we had before
DeleteAll();
// Do a shallow copy of the map
mapType::const_iterator it;
for( it = other.dict.begin(); it != other.dict.end(); it++ )
{
if( it->second.typeId & asTYPEID_OBJHANDLE )
Set(it->first, (void*)&it->second.valueObj, it->second.typeId);
else if( it->second.typeId & asTYPEID_MASK_OBJECT )
Set(it->first, (void*)it->second.valueObj, it->second.typeId);
else
Set(it->first, (void*)&it->second.valueInt, it->second.typeId);
}
return *this;
}
void CScriptMap::Set(asINT64 key, void *value, int typeId)
{
valueStruct valStruct = {{0},0};
valStruct.typeId = typeId;
if( typeId & asTYPEID_OBJHANDLE )
{
// We're receiving a reference to the handle, so we need to dereference it
valStruct.valueObj = *(void**)value;
engine->AddRefScriptObject(valStruct.valueObj, engine->GetTypeInfoById(typeId));
}
else if( typeId & asTYPEID_MASK_OBJECT )
{
// Create a copy of the object
valStruct.valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId));
}
else
{
// Copy the primitive value
// We receive a pointer to the value.
int size = engine->GetSizeOfPrimitiveType(typeId);
memcpy(&valStruct.valueInt, value, size);
}
mapType::iterator it;
it = dict.find(key);
if( it != dict.end() )
{
FreeValue(it->second);
// Insert the new value
it->second = valStruct;
}
else
{
dict.insert(mapType::value_type(key, valStruct));
++modCount;
}
}
// This overloaded method is implemented so that all integer and
// unsigned integers types will be stored in the map 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 CScriptMap::Set(asINT64 key, asINT64 &value)
{
Set(key, &value, asTYPEID_INT64);
}
// This overloaded method is implemented so that all floating point types
// will be stored in the map 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 CScriptMap::Set(asINT64 key, double &value)
{
Set(key, &value, asTYPEID_DOUBLE);
}
// This helper function exists to assist various map and iterator
// methods that want to retrieve a value from a standard iterator
bool CScriptMap::Iterator_GetValue(CScriptMap::mapType::const_iterator &it, 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( (it->second.typeId & asTYPEID_MASK_OBJECT) &&
IsHandleCompatibleWithObject((asCScriptEngine*)engine, it->second.valueObj, it->second.typeId, typeId) )
{
engine->AddRefScriptObject(it->second.valueObj, engine->GetTypeInfoById(it->second.typeId));
*(void**)value = it->second.valueObj;
return true;
}
}
else if( typeId & asTYPEID_MASK_OBJECT )
{
// Verify that the copy can be made
bool isCompatible = false;
if( it->second.typeId == typeId )
isCompatible = true;
// Copy the object into the given reference
if( isCompatible )
{
engine->AssignScriptObject(value, it->second.valueObj, engine->GetTypeInfoById(typeId));
return true;
}
}
else
{
if( it->second.typeId == typeId )
{
int size = engine->GetSizeOfPrimitiveType(typeId);
memcpy(value, &it->second.valueInt, size);
return true;
}
// We know all numbers are stored as either int64 or double, since we register overloaded functions for those
if( it->second.typeId == asTYPEID_INT64 && typeId == asTYPEID_DOUBLE )
{
*(double*)value = double(it->second.valueInt);
return true;
}
else if( it->second.typeId == asTYPEID_DOUBLE && typeId == asTYPEID_INT64 )
{
*(asINT64*)value = asINT64(it->second.valueFlt);
return true;
}
}
// 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 true if the value was successfully retrieved
bool CScriptMap::Get(asINT64 key, void *value, int typeId) const
{
mapType::const_iterator it;
it = dict.find(key);
if( it != dict.end() )
{
// This logic is already implemented in the iterator wrapper,
// so defer to that function from here
return Iterator_GetValue(it, value, typeId);
}
return false;
}
bool CScriptMap::Get(asINT64 key, asINT64 &value) const
{
return Get(key, &value, asTYPEID_INT64);
}
bool CScriptMap::Get(asINT64 key, double &value) const
{
return Get(key, &value, asTYPEID_DOUBLE);
}
bool CScriptMap::Exists(asINT64 key) const
{
mapType::const_iterator it;
it = dict.find(key);
if( it != dict.end() )
return true;
return false;
}
bool CScriptMap::IsEmpty() const
{
if( dict.size() == 0 )
return true;
return false;
}
asUINT CScriptMap::GetSize() const
{
return asUINT(dict.size());
}
void CScriptMap::Delete(asINT64 key)
{
mapType::iterator it;
it = dict.find(key);
if( it != dict.end() )
{
FreeValue(it->second);
dict.erase(it);
++modCount;
}
}
void CScriptMap::DeleteAll()
{
mapType::iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
FreeValue(it->second);
dict.clear();
}
void CScriptMap::DeleteNulls()
{
mapType::iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
{
if( it->second.typeId & asTYPEID_OBJHANDLE )
if( it->second.valueObj == 0 )
it = dict.erase(it);
}
++modCount;
}
void CScriptMap::FreeValue(valueStruct &value)
{
// If it is a handle or a ref counted object, call release
if( value.typeId & asTYPEID_MASK_OBJECT )
{
// Let the engine release the object
engine->ReleaseScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId));
value.valueObj = 0;
value.typeId = 0;
}
// For primitives, there's nothing to do
}
CScriptArray* CScriptMap::GetKeys() const
{
// TODO: optimize: The string array type should only be determined once.
// It should be recomputed when registering the map class.
// Only problem is if multiple engines are used, as they may not
// share the same type id. Alternatively it can be stored in the
// user data for the map type.
int stringArrayType = engine->GetTypeIdByDecl("array<int64>");
asITypeInfo *ot = engine->GetTypeInfoById(stringArrayType);
// Create the array object
CScriptArray *array = new CScriptArray(dict.size(), ot);
long current = -1;
mapType::const_iterator it;
for( it = dict.begin(); it != dict.end(); it++ )
{
current++;
*(asINT64*)array->At(current) = it->first;
}
return array;
}
CScriptMap::Iterator CScriptMap::GetIterator() const {
return Iterator(this);
}
void CScriptMap::Delete(CScriptMap::Iterator& it) {
if( it.container != this ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Mismatched script container and iterator.");
return;
}
if( it.it == dict.end() ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Deleting invalid iterator.");
return;
}
it.it = dict.erase(it.it);
it.first = true;
++modCount;
it.modCount = modCount;
}
//--------------------------------------------------------------------------
// Iterator implementation
CScriptMap::Iterator::Iterator() {
container = 0;
}
CScriptMap::Iterator::Iterator(const CScriptMap *container) {
this->container = container;
// Start the iteration
it = container->dict.begin();
first = true;
// Track the modification count of the map
// so we can safely fail when the map is altered
modCount = container->modCount;
// Keep a reference to the map so it doesn't
// get destroyed from under us
container->AddRef();
}
CScriptMap::Iterator::~Iterator() {
// Release map reference
if(container)
container->Release();
}
static void DefaultConstructIterator(void *memory) {
new(memory) CScriptMap::Iterator();
}
static void ConstructIterator(void *memory, const CScriptMap *container) {
new(memory) CScriptMap::Iterator(container);
}
static void DestructIterator(CScriptMap::Iterator &it) {
it.~Iterator();
}
asINT64 CScriptMap::Iterator::GetKey() {
if( !container || modCount != container->modCount || it == container->dict.end() ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Iterator not valid or map changed.");
return 0;
}
return it->first;
}
bool CScriptMap::Iterator::Iterate(void *value, int typeId) {
return Iterate(0, value, typeId);
}
bool CScriptMap::Iterator::Iterate(asINT64* key, void *value, int typeId) {
if( !container ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Iterating on invalid iterator.");
return false;
}
if( modCount != container->modCount ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Dictionary changed during iteration.");
return false;
}
if( it == container->dict.end() )
return false;
if( first )
first = false;
else
++it;
if( it == container->dict.end() )
return false;
if( key )
*key = it->first;
if( container->Iterator_GetValue(it, value, typeId) )
{
return true;
}
else
{
// The caller can check IsValid to see if the iteration can still
// continue because the type was wrong, or whether it has really ended
return false;
}
}
bool CScriptMap::Iterator::IsValid() {
if( !container || modCount != container->modCount ) {
asIScriptContext *ctx = asGetActiveContext();
if( ctx )
ctx->SetException("Map changed during iteration.");
}
return it != container->dict.end();
}
CScriptMap::Iterator &CScriptMap::Iterator::operator =(const CScriptMap::Iterator &other) {
if(other.container)
other.container->AddRef();
if(container)
container->Release();
modCount = other.modCount;
container = other.container;
first = other.first;
it = other.it;
return *this;
}
//--------------------------------------------------------------------------
// Generic wrappers
void ScriptMapFactory_Generic(asIScriptGeneric *gen)
{
*(CScriptMap**)gen->GetAddressOfReturnLocation() = new CScriptMap(gen->GetEngine());
}
void ScriptMapAddRef_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
dict->AddRef();
}
void ScriptMapRelease_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
dict->Release();
}
void ScriptMapAssign_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
CScriptMap *other = *(CScriptMap**)gen->GetAddressOfArg(0);
*dict = *other;
*(CScriptMap**)gen->GetAddressOfReturnLocation() = dict;
}
void ScriptMapSet_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
int typeId = gen->GetArgTypeId(1);
dict->Set(key, ref, typeId);
}
void ScriptMapSetInt_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
dict->Set(key, *(asINT64*)ref);
}
void ScriptMapSetFlt_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
dict->Set(key, *(double*)ref);
}
void ScriptMapGet_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
int typeId = gen->GetArgTypeId(1);
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(key, ref, typeId);
}
void ScriptMapGetInt_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(key, *(asINT64*)ref);
}
void ScriptMapGetFlt_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
void *ref = *(void**)gen->GetAddressOfArg(1);
*(bool*)gen->GetAddressOfReturnLocation() = dict->Get(key, *(double*)ref);
}
void ScriptMapExists_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
bool ret = dict->Exists(key);
*(bool*)gen->GetAddressOfReturnLocation() = ret;
}
void ScriptMapDelete_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
asINT64 key = *(asINT64*)gen->GetAddressOfArg(0);
dict->Delete(key);
}
void ScriptMapDeleteAll_Generic(asIScriptGeneric *gen)
{
CScriptMap *dict = (CScriptMap*)gen->GetObject();
dict->DeleteAll();
}
static void ScriptMapGetRefCount_Generic(asIScriptGeneric *gen)
{
CScriptMap *self = (CScriptMap*)gen->GetObject();
*(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount();
}
static void ScriptMapSetGCFlag_Generic(asIScriptGeneric *gen)
{
CScriptMap *self = (CScriptMap*)gen->GetObject();
self->SetGCFlag();
}
static void ScriptMapGetGCFlag_Generic(asIScriptGeneric *gen)
{
CScriptMap *self = (CScriptMap*)gen->GetObject();
*(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag();
}
static void ScriptMapEnumReferences_Generic(asIScriptGeneric *gen)
{
CScriptMap *self = (CScriptMap*)gen->GetObject();
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
self->EnumReferences(engine);
}
static void ScriptMapReleaseAllReferences_Generic(asIScriptGeneric *gen)
{
CScriptMap *self = (CScriptMap*)gen->GetObject();
asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0);
self->ReleaseAllReferences(engine);
}
static void CScriptMapGetKeys_Generic(asIScriptGeneric *gen)
{
CScriptMap *self = (CScriptMap*)gen->GetObject();
*(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys();
}
//--------------------------------------------------------------------------
// Register the type
void RegisterScriptMap(asIScriptEngine *engine)
{
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
RegisterScriptMap_Generic(engine);
else
RegisterScriptMap_Native(engine);
}
void RegisterScriptMap_Native(asIScriptEngine *engine)
{
int r;
//Register iterator type so we can use it later
r = engine->RegisterObjectType("map_iterator", sizeof(CScriptMap::Iterator), asOBJ_VALUE | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
r = engine->RegisterObjectType("map", sizeof(CScriptMap), 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("map", asBEHAVE_FACTORY, "map@ f()", asFUNCTION(ScriptMapFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptMap,AddRef), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptMap,Release), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "map &opAssign(const map &in)", asMETHODPR(CScriptMap, operator=, (const CScriptMap &), CScriptMap&), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void set(int64, const ?&in)", asMETHODPR(CScriptMap,Set,(asINT64,void*,int),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool get(int64, ?&out) const", asMETHODPR(CScriptMap,Get,(asINT64,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void set(int64, int64&in)", asMETHODPR(CScriptMap,Set,(asINT64,asINT64&),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool get(int64, int64&out) const", asMETHODPR(CScriptMap,Get,(asINT64,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void set(int64, double&in)", asMETHODPR(CScriptMap,Set,(asINT64,double&),void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool get(int64, double&out) const", asMETHODPR(CScriptMap,Get,(asINT64,double&) const,bool), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool exists(int64) const", asMETHOD(CScriptMap,Exists), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool isEmpty() const", asMETHOD(CScriptMap, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "uint getSize() const", asMETHOD(CScriptMap, GetSize), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void delete(int64)", asMETHODPR(CScriptMap, Delete, (asINT64), void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void delete(map_iterator&)", asMETHODPR(CScriptMap, Delete, (CScriptMap::Iterator&), void), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void deleteAll()", asMETHOD(CScriptMap,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void deleteNulls()", asMETHOD(CScriptMap,DeleteNulls), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "map_iterator iterator()", asMETHOD(CScriptMap,GetIterator), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "array<int64> @getKeys() const", asMETHOD(CScriptMap,GetKeys), asCALL_THISCALL); assert( r >= 0 );
// Register GC behaviours
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptMap,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptMap,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptMap,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptMap,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptMap,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
#if AS_USE_STLNAMES == 1
// Same as isEmpty
r = engine->RegisterObjectMethod("map", "bool empty() const", asMETHOD(CScriptMap, IsEmpty), asCALL_THISCALL); assert( r >= 0 );
// Same as getSize
r = engine->RegisterObjectMethod("map", "uint size() const", asMETHOD(CScriptMap, GetSize), asCALL_THISCALL); assert( r >= 0 );
// Same as delete
r = engine->RegisterObjectMethod("map", "void erase(asINT64 in)", asMETHOD(CScriptMap,Delete), asCALL_THISCALL); assert( r >= 0 );
// Same as deleteAll
r = engine->RegisterObjectMethod("map", "void clear()", asMETHOD(CScriptMap,DeleteAll), asCALL_THISCALL); assert( r >= 0 );
#endif
// Register iterator methods
r = engine->RegisterObjectBehaviour("map_iterator", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(DefaultConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("map_iterator", asBEHAVE_CONSTRUCT, "void f(const map &in)", asFUNCTION(ConstructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("map_iterator", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructIterator), asCALL_CDECL_OBJFIRST); assert( r>= 0 );
r = engine->RegisterObjectMethod("map_iterator", "int64 get_key()", asMETHOD(CScriptMap::Iterator, GetKey), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("map_iterator", "bool iterate(?&out)", asMETHODPR(CScriptMap::Iterator, Iterate, (void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("map_iterator", "bool iterate(int64 &out, ?&out)", asMETHODPR(CScriptMap::Iterator, Iterate, (asINT64*,void*,int), bool), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("map_iterator", "bool get_valid()", asMETHOD(CScriptMap::Iterator, IsValid), asCALL_THISCALL); assert( r>= 0 );
r = engine->RegisterObjectMethod("map_iterator", "map_iterator& opAssign(const map_iterator &in)", asMETHOD(CScriptMap::Iterator, operator=), asCALL_THISCALL); assert( r>= 0 );
}
void RegisterScriptMap_Generic(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectType("map", sizeof(CScriptMap), asOBJ_REF | asOBJ_GC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_FACTORY, "map@ f()", asFUNCTION(ScriptMapFactory_Generic), asCALL_GENERIC); assert( r>= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptMapAddRef_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptMapRelease_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "map &opAssign(const map &in)", asFUNCTION(ScriptMapAssign_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void set(int64, ?&in)", asFUNCTION(ScriptMapSet_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool get(int64, ?&out) const", asFUNCTION(ScriptMapGet_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void set(int64, int64&in)", asFUNCTION(ScriptMapSetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool get(int64, int64&out) const", asFUNCTION(ScriptMapGetInt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void set(int64, double&in)", asFUNCTION(ScriptMapSetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool get(int64, double&out) const", asFUNCTION(ScriptMapGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "bool exists(asINT64 in) const", asFUNCTION(ScriptMapExists_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void delete(asINT64 in)", asFUNCTION(ScriptMapDelete_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "void deleteAll()", asFUNCTION(ScriptMapDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("map", "array<int64> @getKeys() const", asFUNCTION(CScriptMapGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 );
// Register GC behaviours
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptMapGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptMapSetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptMapGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptMapEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectBehaviour("map", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptMapReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 );
}
END_AS_NAMESPACE
+357
View File
@@ -0,0 +1,357 @@
#include <assert.h>
#include <math.h>
#include <float.h>
#include <string.h>
#include "scriptmath.h"
#ifdef __BORLANDC__
#include <cmath>
// The C++Builder RTL doesn't pull the *f functions into the global namespace per default.
using namespace std;
#if __BORLANDC__ < 0x580
// C++Builder 6 and earlier don't come with any *f variants of the math functions at all.
inline float cosf (float arg) { return std::cos (arg); }
inline float sinf (float arg) { return std::sin (arg); }
inline float tanf (float arg) { return std::tan (arg); }
inline float atan2f (float y, float x) { return std::atan2 (y, x); }
inline float logf (float arg) { return std::log (arg); }
inline float powf (float x, float y) { return std::pow (x, y); }
inline float sqrtf (float arg) { return std::sqrt (arg); }
#endif
// C++Builder doesn't define most of the non-standard float-specific math functions with
// "*f" suffix; instead it provides overloads for the standard math functions which take
// "float" arguments.
inline float acosf (float arg) { return std::acos (arg); }
inline float asinf (float arg) { return std::asin (arg); }
inline float atanf (float arg) { return std::atan (arg); }
inline float coshf (float arg) { return std::cosh (arg); }
inline float sinhf (float arg) { return std::sinh (arg); }
inline float tanhf (float arg) { return std::tanh (arg); }
inline float log10f (float arg) { return std::log10 (arg); }
inline float ceilf (float arg) { return std::ceil (arg); }
inline float fabsf (float arg) { return std::fabs (arg); }
inline float floorf (float arg) { return std::floor (arg); }
// C++Builder doesn't define a non-standard "modff" function but rather an overload of "modf"
// for float arguments. However, BCC's float overload of fmod() is broken (QC #74816; fixed
// in C++Builder 2010).
inline float modff (float x, float *y)
{
double d;
float f = (float) modf((double) x, &d);
*y = (float) d;
return f;
}
#endif
BEGIN_AS_NAMESPACE
// Determine whether the float version should be registered, or the double version
#ifndef AS_USE_FLOAT
#if !defined(_WIN32_WCE) // WinCE doesn't have the float versions of the math functions
#define AS_USE_FLOAT 1
#endif
#endif
// The modf function doesn't seem very intuitive, so I'm writing this
// function that simply returns the fractional part of the float value
#if AS_USE_FLOAT
float fractionf(float v)
{
float intPart;
return modff(v, &intPart);
}
#else
double fraction(double v)
{
double intPart;
return modf(v, &intPart);
}
#endif
// As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of
// functions for converting float values to IEEE 754 formatted values etc. This also allow us to
// provide a platform agnostic representation to the script so the scripts don't have to worry
// about whether the CPU uses IEEE 754 floats or some other representation
float fpFromIEEE(asUINT raw)
{
// TODO: Identify CPU family to provide proper conversion
// if the CPU doesn't natively use IEEE style floats
return *reinterpret_cast<float*>(&raw);
}
asUINT fpToIEEE(float fp)
{
return *reinterpret_cast<asUINT*>(&fp);
}
double fpFromIEEE(asQWORD raw)
{
return *reinterpret_cast<double*>(&raw);
}
asQWORD fpToIEEE(double fp)
{
return *reinterpret_cast<asQWORD*>(&fp);
}
float _round(float v) {
return floorf(v + 0.5f);
}
double _round(double v) {
return floorl(v + 0.5);
}
// closeTo() is used to determine if the binary representation of two numbers are
// relatively close to each other. Numerical errors due to rounding errors build
// up over many operations, so it is almost impossible to get exact numbers and
// this is where closeTo() comes in.
//
// It shouldn't be used to determine if two numbers are mathematically close to
// each other.
//
// ref: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
// ref: http://www.gamedev.net/topic/653449-scriptmath-and-closeto/
bool closeTo(float a, float b, float epsilon)
{
// Equal numbers and infinity will return immediately
if( a == b ) return true;
// When very close to 0, we can use the absolute comparison
float diff = fabsf(a - b);
if( (a == 0 || b == 0) && (diff < epsilon) )
return true;
// Otherwise we need to use relative comparison to account for precision
return diff / (fabs(a) + fabs(b)) < epsilon;
}
bool closeTo(double a, double b, double epsilon)
{
if( a == b ) return true;
double diff = fabs(a - b);
if( (a == 0 || b == 0) && (diff < epsilon) )
return true;
return diff / (fabs(a) + fabs(b)) < epsilon;
}
void RegisterScriptMath_Native(asIScriptEngine *engine)
{
int r;
// Conversion between floating point and IEEE bits representations
r = engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 );
// Close to comparison with epsilon
r = engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 );
#if AS_USE_FLOAT
// Trigonometric functions
r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 );
// Hyberbolic functions
r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 );
// Exponential and logarithmic functions
r = engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 );
// Power functions
r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 );
// Nearest integer, absolute value, and remainder functions
r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float round(float)", asFUNCTIONPR(_round, (float), float), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 );
// Don't register modf because AngelScript already supports the % operator
#else
// double versions of the same
r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double round(double)", asFUNCTIONPR(_round, (double), double), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 );
#endif
}
#if AS_USE_FLOAT
// This macro creates simple generic wrappers for functions of type 'float func(float)'
#define GENERICff(x) \
void x##_generic(asIScriptGeneric *gen) \
{ \
float f = *(float*)gen->GetAddressOfArg(0); \
*(float*)gen->GetAddressOfReturnLocation() = x(f); \
}
GENERICff(cosf)
GENERICff(sinf)
GENERICff(tanf)
GENERICff(acosf)
GENERICff(asinf)
GENERICff(atanf)
GENERICff(coshf)
GENERICff(sinhf)
GENERICff(tanhf)
GENERICff(logf)
GENERICff(log10f)
GENERICff(sqrtf)
GENERICff(ceilf)
GENERICff(fabsf)
GENERICff(floorf)
GENERICff(fractionf)
void powf_generic(asIScriptGeneric *gen)
{
float f1 = *(float*)gen->GetAddressOfArg(0);
float f2 = *(float*)gen->GetAddressOfArg(1);
*(float*)gen->GetAddressOfReturnLocation() = powf(f1, f2);
}
void atan2f_generic(asIScriptGeneric *gen)
{
float f1 = *(float*)gen->GetAddressOfArg(0);
float f2 = *(float*)gen->GetAddressOfArg(1);
*(float*)gen->GetAddressOfReturnLocation() = atan2f(f1, f2);
}
#else
// This macro creates simple generic wrappers for functions of type 'double func(double)'
#define GENERICdd(x) \
void x##_generic(asIScriptGeneric *gen) \
{ \
double f = *(double*)gen->GetAddressOfArg(0); \
*(double*)gen->GetAddressOfReturnLocation() = x(f); \
}
GENERICdd(cos)
GENERICdd(sin)
GENERICdd(tan)
GENERICdd(acos)
GENERICdd(asin)
GENERICdd(atan)
GENERICdd(cosh)
GENERICdd(sinh)
GENERICdd(tanh)
GENERICdd(log)
GENERICdd(log10)
GENERICdd(sqrt)
GENERICdd(ceil)
GENERICdd(fabs)
GENERICdd(floor)
GENERICdd(fraction)
void pow_generic(asIScriptGeneric *gen)
{
double f1 = *(double*)gen->GetAddressOfArg(0);
double f2 = *(double*)gen->GetAddressOfArg(1);
*(double*)gen->GetAddressOfReturnLocation() = pow(f1, f2);
}
void atan2_generic(asIScriptGeneric *gen)
{
double f1 = *(double*)gen->GetAddressOfArg(0);
double f2 = *(double*)gen->GetAddressOfArg(1);
*(double*)gen->GetAddressOfReturnLocation() = atan2(f1, f2);
}
#endif
void RegisterScriptMath_Generic(asIScriptEngine *engine)
{
int r;
#if AS_USE_FLOAT
// Trigonometric functions
r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 );
// Hyberbolic functions
r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 );
// Exponential and logarithmic functions
r = engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 );
// Power functions
r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 );
// Nearest integer, absolute value, and remainder functions
r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 );
// Don't register modf because AngelScript already supports the % operator
#else
// double versions of the same
r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 );
#endif
}
void RegisterScriptMath(asIScriptEngine *engine)
{
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
RegisterScriptMath_Generic(engine);
else
RegisterScriptMath_Native(engine);
}
END_AS_NAMESPACE
+639
View File
@@ -0,0 +1,639 @@
#include <assert.h>
#include <sstream>
#include "scriptstdstring.h"
#include <string.h> // strstr
using namespace std;
BEGIN_AS_NAMESPACE
static void StringFactoryGeneric(asIScriptGeneric *gen) {
asUINT length = gen->GetArgDWord(0);
const char *s = (const char*)gen->GetArgAddress(1);
string str(s, length);
gen->SetReturnObject(&str);
}
static void ConstructStringGeneric(asIScriptGeneric * gen) {
new (gen->GetObject()) string();
}
static void CopyConstructStringGeneric(asIScriptGeneric * gen) {
string * a = static_cast<string *>(gen->GetArgObject(0));
new (gen->GetObject()) string(*a);
}
static void DestructStringGeneric(asIScriptGeneric * gen) {
string * ptr = static_cast<string *>(gen->GetObject());
ptr->~string();
}
static void AssignStringGeneric(asIScriptGeneric *gen) {
string * a = static_cast<string *>(gen->GetArgObject(0));
string * self = static_cast<string *>(gen->GetObject());
*self = *a;
gen->SetReturnAddress(self);
}
static void AddAssignStringGeneric(asIScriptGeneric *gen) {
string * a = static_cast<string *>(gen->GetArgObject(0));
string * self = static_cast<string *>(gen->GetObject());
*self += *a;
gen->SetReturnAddress(self);
}
static void StringEqualsGeneric(asIScriptGeneric * gen) {
string * a = static_cast<string *>(gen->GetObject());
string * b = static_cast<string *>(gen->GetArgAddress(0));
*(bool*)gen->GetAddressOfReturnLocation() = (*a == *b);
}
static void StringCmpGeneric(asIScriptGeneric * gen) {
string * a = static_cast<string *>(gen->GetObject());
string * b = static_cast<string *>(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<string *>(gen->GetObject());
string * b = static_cast<string *>(gen->GetArgAddress(0));
string ret_val = *a + *b;
gen->SetReturnObject(&ret_val);
}
static void StringLengthGeneric(asIScriptGeneric * gen) {
string * self = static_cast<string *>(gen->GetObject());
*static_cast<asUINT *>(gen->GetAddressOfReturnLocation()) = (asUINT)self->length();
}
static void StringResizeGeneric(asIScriptGeneric * gen) {
string * self = static_cast<string *>(gen->GetObject());
self->resize(*static_cast<asUINT *>(gen->GetAddressOfArg(0)));
}
static void StringCharAtGeneric(asIScriptGeneric * gen) {
unsigned int index = gen->GetArgDWord(0);
string * self = static_cast<string *>(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)
{
int *a = static_cast<int*>(gen->GetAddressOfArg(0));
string *self = static_cast<string*>(gen->GetObject());
std::stringstream sstr;
sstr << *a;
*self = sstr.str();
gen->SetReturnAddress(self);
}
static void AssignUInt2StringGeneric(asIScriptGeneric *gen)
{
unsigned int *a = static_cast<unsigned int*>(gen->GetAddressOfArg(0));
string *self = static_cast<string*>(gen->GetObject());
std::stringstream sstr;
sstr << *a;
*self = sstr.str();
gen->SetReturnAddress(self);
}
static void AssignDouble2StringGeneric(asIScriptGeneric *gen)
{
double *a = static_cast<double*>(gen->GetAddressOfArg(0));
string *self = static_cast<string*>(gen->GetObject());
std::stringstream sstr;
sstr << *a;
*self = sstr.str();
gen->SetReturnAddress(self);
}
static void AssignBool2StringGeneric(asIScriptGeneric *gen)
{
bool *a = static_cast<bool*>(gen->GetAddressOfArg(0));
string *self = static_cast<string*>(gen->GetObject());
std::stringstream sstr;
sstr << (*a ? "true" : "false");
*self = sstr.str();
gen->SetReturnAddress(self);
}
static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) {
double * a = static_cast<double *>(gen->GetAddressOfArg(0));
string * self = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << *a;
*self += sstr.str();
gen->SetReturnAddress(self);
}
static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) {
int * a = static_cast<int *>(gen->GetAddressOfArg(0));
string * self = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << *a;
*self += sstr.str();
gen->SetReturnAddress(self);
}
static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) {
unsigned int * a = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
string * self = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << *a;
*self += sstr.str();
gen->SetReturnAddress(self);
}
static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) {
bool * a = static_cast<bool *>(gen->GetAddressOfArg(0));
string * self = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << (*a ? "true" : "false");
*self += sstr.str();
gen->SetReturnAddress(self);
}
static void AddString2DoubleGeneric(asIScriptGeneric * gen) {
string * a = static_cast<string *>(gen->GetObject());
double * b = static_cast<double *>(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<string *>(gen->GetObject());
int * b = static_cast<int *>(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<string *>(gen->GetObject());
unsigned int * b = static_cast<unsigned int *>(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<string *>(gen->GetObject());
bool * b = static_cast<bool *>(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<double *>(gen->GetAddressOfArg(0));
string * b = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << *a << *b;
std::string ret_val = sstr.str();
gen->SetReturnObject(&ret_val);
}
static void AddInt2StringGeneric(asIScriptGeneric * gen) {
int* a = static_cast<int *>(gen->GetAddressOfArg(0));
string * b = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << *a << *b;
std::string ret_val = sstr.str();
gen->SetReturnObject(&ret_val);
}
static void AddUInt2StringGeneric(asIScriptGeneric * gen) {
unsigned int* a = static_cast<unsigned int *>(gen->GetAddressOfArg(0));
string * b = static_cast<string *>(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<bool *>(gen->GetAddressOfArg(0));
string * b = static_cast<string *>(gen->GetObject());
std::stringstream sstr;
sstr << (*a ? "true" : "false") << *b;
std::string ret_val = sstr.str();
gen->SetReturnObject(&ret_val);
}
// 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 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);
// Check for out-of-bounds
string ret;
if( start < str->length() && count != 0 )
ret = str->substr(start, count);
// Return the substring
new(gen->GetAddressOfReturnLocation()) string(ret);
}
void RegisterStdString_Generic(asIScriptEngine *engine)
{
int r;
// Register the string type
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
// Register the string factory
r = engine->RegisterStringFactory("string", asFUNCTION(StringFactoryGeneric), asCALL_GENERIC); assert( r >= 0 );
// 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
r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), 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(int)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string opAdd(int) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string opAdd_r(int) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string &opAssign(uint)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string opAdd(uint) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint) 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 );
}
static string StringFactory(asUINT length, const char *s)
{
return string(s, length);
}
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 &AssignUIntToString(unsigned int i, string &dest)
{
ostringstream stream;
stream << i;
dest = stream.str();
return dest;
}
static string &AddAssignUIntToString(unsigned int i, string &dest)
{
ostringstream stream;
stream << i;
dest += stream.str();
return dest;
}
static string AddStringUInt(const string &str, unsigned int i)
{
ostringstream stream;
stream << i;
return str + stream.str();
}
static string AddStringUInt64(const string &str, unsigned long long i)
{
ostringstream stream;
stream << i;
return str + stream.str();
}
static string AddIntString(int i, const string &str)
{
ostringstream stream;
stream << i;
return stream.str() + str;
}
static string AddInt64String(long long i, const string &str)
{
ostringstream stream;
stream << i;
return stream.str() + str;
}
static string &AssignIntToString(int i, string &dest)
{
ostringstream stream;
stream << i;
dest = stream.str();
return dest;
}
static string &AddAssignIntToString(int i, string &dest)
{
ostringstream stream;
stream << i;
dest += stream.str();
return dest;
}
static string AddStringInt(const string &str, int i)
{
ostringstream stream;
stream << i;
return str + stream.str();
}
static string AddStringInt64(const string &str, long long i)
{
ostringstream stream;
stream << i;
return str + stream.str();
}
static string AddUIntString(unsigned int i, const string &str)
{
ostringstream stream;
stream << i;
return stream.str() + str;
}
static string AddUInt64String(unsigned long long 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 &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 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;
}
static bool StringEq(const string &a, const string &b) {
return a == b;
}
// 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, 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);
}
// 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);
}
void RegisterStdString_Native(asIScriptEngine *engine)
{
int r;
// Register the string type
r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
// Register the string factory
r = engine->RegisterStringFactory("string", asFUNCTION(StringFactory), asCALL_CDECL); assert( r >= 0 );
// 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 );
r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEq), 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 );
// Register the object methods
r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "uint get_length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), 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[] directory, 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(int)", asFUNCTION(AssignIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int)", asFUNCTION(AddAssignIntToString), 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(uint)", asFUNCTION(AssignUIntToString), asCALL_CDECL_OBJLAST); assert( r >= 0 );
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint)", asFUNCTION(AddAssignUIntToString), 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 );
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), 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 );
// TODO: Implement the following
// findFirstOf
// findLastOf
// findFirstNotOf
// findLastNotOf
// parseInt
// parseFloat
// formatInt - maybe as string::string(int64 value, const string &in format)
// formatFloat
// replace - replaces a text found in the string
// replaceRange - replaces a range of bytes in the string
// trim
// multiply/times - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----"
}
void RegisterStdString(asIScriptEngine * engine)
{
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY"))
RegisterStdString_Generic(engine);
else
RegisterStdString_Native(engine);
}
END_AS_NAMESPACE
@@ -0,0 +1,113 @@
#include <assert.h>
#include "scriptstdstring.h"
#include "scriptarray.h"
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<string>@ array = str.split("|");
//
// The resulting array has the following elements:
//
// {"A", "B", "", "D"}
//
// AngelScript signature:
// array<string>@ string::split(const string &in delim) const
static void StringSplit_Generic(asIScriptGeneric *gen)
{
// 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->GetTypeInfoById(engine->GetTypeIdByDecl("array<string>"));
// Create the array object
CScriptArray *array = new CScriptArray(0, arrayType);
// Get the arguments
string *str = (string*)gen->GetObject();
string *delim = *(string**)gen->GetAddressOfArg(0);
// 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 the array by handle
*(CScriptArray**)gen->GetAddressOfReturnLocation() = array;
}
// 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<string> array = {"A", "B", "", "D"};
// string str = join(array, "|");
//
// The resulting string is:
//
// "A|B||D"
//
// AngelScript signature:
// string join(const array<string> &in array, const string &in delim)
static void StringJoin_Generic(asIScriptGeneric *gen)
{
// Get the arguments
CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0);
string *delim = *(string**)gen->GetAddressOfArg(1);
// 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 the string
new(gen->GetAddressOfReturnLocation()) string(str);
}
// This is where the utility functions are registered.
// The string type must have been registered first.
void RegisterStdStringUtils(asIScriptEngine *engine)
{
int r;
r = engine->RegisterObjectMethod("string", "array<string>@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string join(const array<string> &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0);
}
END_AS_NAMESPACE