mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
Update some AS stuff
This commit is contained in:
parent
4f600e3d6f
commit
26d514baea
8 changed files with 598 additions and 112 deletions
|
|
@ -244,6 +244,30 @@ static bool ScriptArrayTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollec
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
asUINT CScriptArray_opForBegin(const CScriptArray*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CScriptArray_opForEnd(asUINT iter, const CScriptArray*arr)
|
||||
{
|
||||
if (arr == 0 || arr->GetSize() <= iter)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
asUINT CScriptArray_opForNext(asUINT iter, const CScriptArray*)
|
||||
{
|
||||
return iter + 1;
|
||||
}
|
||||
|
||||
asUINT CScriptArray_opForValue1(asUINT iter, const CScriptArray*)
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
|
||||
// Registers the template array type
|
||||
void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray)
|
||||
{
|
||||
|
|
@ -289,6 +313,13 @@ static void RegisterScriptArray_Native(asIScriptEngine *engine)
|
|||
r = engine->RegisterObjectMethod("array<T>", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("array<T>", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
// Support for foreach
|
||||
r = engine->RegisterObjectMethod("array<T>", "uint opForBegin() const", asFUNCTIONPR(CScriptArray_opForBegin, (const CScriptArray *), asUINT), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "bool opForEnd(uint) const", asFUNCTIONPR(CScriptArray_opForEnd, (asUINT, const CScriptArray*), bool), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "uint opForNext(uint) const", asFUNCTIONPR(CScriptArray_opForNext, (asUINT, const CScriptArray*), asUINT), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "const T &opForValue0(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "uint opForValue1(uint index) const", asFUNCTIONPR(CScriptArray_opForValue1, (asUINT, const CScriptArray*), asUINT), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
// The assignment operator
|
||||
r = engine->RegisterObjectMethod("array<T>", "array<T> &opAssign(const array<T>&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
|
|
@ -2203,6 +2234,26 @@ static void ScriptArrayReleaseAllHandles_Generic(asIScriptGeneric *gen)
|
|||
self->ReleaseAllHandles(engine);
|
||||
}
|
||||
|
||||
static void ScriptArray_opForBegin_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
*reinterpret_cast<asUINT*>(gen->GetAddressOfReturnLocation()) = CScriptArray_opForBegin(reinterpret_cast<CScriptArray*>(gen->GetObject()));
|
||||
}
|
||||
|
||||
static void ScriptArray_opForEnd_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
*reinterpret_cast<bool*>(gen->GetAddressOfReturnLocation()) = CScriptArray_opForEnd(gen->GetArgDWord(0), reinterpret_cast<CScriptArray*>(gen->GetObject()));
|
||||
}
|
||||
|
||||
static void ScriptArray_opForNext_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
*reinterpret_cast<asUINT*>(gen->GetAddressOfReturnLocation()) = CScriptArray_opForNext(gen->GetArgDWord(0), reinterpret_cast<CScriptArray*>(gen->GetObject()));
|
||||
}
|
||||
|
||||
static void ScriptArray_opForValue1_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
*reinterpret_cast<asUINT*>(gen->GetAddressOfReturnLocation()) = CScriptArray_opForValue1(gen->GetArgDWord(0), reinterpret_cast<CScriptArray*>(gen->GetObject()));
|
||||
}
|
||||
|
||||
static void RegisterScriptArray_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r = 0;
|
||||
|
|
@ -2221,7 +2272,14 @@ static void RegisterScriptArray_Generic(asIScriptEngine *engine)
|
|||
r = engine->RegisterObjectBehaviour("array<T>", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("array<T>", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("array<T>", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("array<T>", "array<T> &opAssign(const array<T>&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterObjectMethod("array<T>", "uint opForBegin() const", asFUNCTION(ScriptArray_opForBegin_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "bool opForEnd(uint) const", asFUNCTION(ScriptArray_opForEnd_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "uint opForNext(uint) const", asFUNCTION(ScriptArray_opForNext_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "const T &opForValue0(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("array<T>", "uint opForValue1(uint index) const", asFUNCTION(ScriptArray_opForValue1_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectMethod("array<T>", "array<T> &opAssign(const array<T>&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectMethod("array<T>", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("array<T>", "void insertAt(uint index, const array<T>& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
|
|
|||
|
|
@ -152,9 +152,11 @@ void CScriptBuilder::ClearAll()
|
|||
currentNamespace = "";
|
||||
|
||||
foundDeclarations.clear();
|
||||
|
||||
typeMetadataMap.clear();
|
||||
funcMetadataMap.clear();
|
||||
varMetadataMap.clear();
|
||||
classMetadataMap.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -395,16 +397,26 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
|
|||
// Check if namespace so the metadata for members can be gathered
|
||||
if( token == "namespace" )
|
||||
{
|
||||
// Get the identifier after "namespace"
|
||||
// Get the scope after "namespace". It can be composed of multiple nested namespaces, e.g. A::B::C
|
||||
// Keep track of the number of nested namespace scopes are declared for each block
|
||||
int nestedNamespaces = 0;
|
||||
do
|
||||
{
|
||||
pos += len;
|
||||
t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len);
|
||||
} while(t == asTC_COMMENT || t == asTC_WHITESPACE);
|
||||
do
|
||||
{
|
||||
pos += len;
|
||||
t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_COMMENT || t == asTC_WHITESPACE);
|
||||
|
||||
if( currentNamespace != "" )
|
||||
currentNamespace += "::";
|
||||
currentNamespace += modifiedScript.substr(pos,len);
|
||||
if (t == asTC_IDENTIFIER)
|
||||
{
|
||||
if (currentNamespace != "")
|
||||
currentNamespace += "::";
|
||||
currentNamespace += modifiedScript.substr(pos, len);
|
||||
nestedNamespaces++;
|
||||
}
|
||||
} while (t == asTC_IDENTIFIER || (t == asTC_KEYWORD && modifiedScript.substr(pos, len) == "::"));
|
||||
currentNamespaceStack.push_back(nestedNamespaces);
|
||||
|
||||
// Search until first { is encountered
|
||||
while( pos < modifiedScript.length() )
|
||||
|
|
@ -428,14 +440,20 @@ int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length
|
|||
// Check if end of namespace
|
||||
if( currentNamespace != "" && token == "}" )
|
||||
{
|
||||
size_t found = currentNamespace.rfind( "::" );
|
||||
if( found != string::npos )
|
||||
assert(currentNamespaceStack.size() > 0);
|
||||
int nestedNamespaces = currentNamespaceStack[currentNamespaceStack.size()-1];
|
||||
currentNamespaceStack.pop_back();
|
||||
while (nestedNamespaces-- > 0)
|
||||
{
|
||||
currentNamespace.erase( found );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentNamespace = "";
|
||||
size_t found = currentNamespace.rfind("::");
|
||||
if (found != string::npos)
|
||||
{
|
||||
currentNamespace.erase(found);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentNamespace = "";
|
||||
}
|
||||
}
|
||||
pos += len;
|
||||
continue;
|
||||
|
|
@ -1043,7 +1061,9 @@ int CScriptBuilder::ExtractDeclaration(int pos, string &name, string &declaratio
|
|||
}
|
||||
else if( t == asTC_IDENTIFIER )
|
||||
{
|
||||
name = token;
|
||||
// If a parenthesis is already found then the name is already known so it must not be overwritten
|
||||
if( !hasParenthesis )
|
||||
name = token;
|
||||
}
|
||||
|
||||
// Skip trailing decorators
|
||||
|
|
|
|||
|
|
@ -163,8 +163,9 @@ protected:
|
|||
std::string nameSpace;
|
||||
};
|
||||
std::vector<SMetadataDecl> foundDeclarations;
|
||||
std::string currentClass;
|
||||
std::string currentNamespace;
|
||||
std::string currentClass;
|
||||
std::string currentNamespace;
|
||||
std::vector<int> currentNamespaceStack;
|
||||
|
||||
// Storage of metadata for global declarations
|
||||
std::map<int, std::vector<std::string> > typeMetadataMap;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ void CScriptDictionary::Init(asIScriptEngine *e)
|
|||
// We start with one reference
|
||||
refCount = 1;
|
||||
gcFlag = false;
|
||||
iterGuard = 0;
|
||||
|
||||
// Keep a reference to the engine for as long as we live
|
||||
// We don't increment the reference counter, because the
|
||||
|
|
@ -310,8 +311,11 @@ void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId)
|
|||
{
|
||||
dictMap_t::iterator it;
|
||||
it = dict.find(key);
|
||||
if( it == dict.end() )
|
||||
if (it == dict.end())
|
||||
{
|
||||
it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first;
|
||||
iterGuard++;
|
||||
}
|
||||
|
||||
it->second.Set(engine, value, typeId);
|
||||
}
|
||||
|
|
@ -402,6 +406,7 @@ bool CScriptDictionary::Delete(const dictKey_t &key)
|
|||
{
|
||||
it->second.FreeValue(engine);
|
||||
dict.erase(it);
|
||||
iterGuard++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -415,6 +420,7 @@ void CScriptDictionary::DeleteAll()
|
|||
it->second.FreeValue(engine);
|
||||
|
||||
dict.clear();
|
||||
iterGuard++;
|
||||
}
|
||||
|
||||
CScriptArray* CScriptDictionary::GetKeys() const
|
||||
|
|
@ -1055,6 +1061,192 @@ static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen)
|
|||
self->FreeValue(gen->GetEngine());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Foreach support
|
||||
CScriptDictionary::CScriptDictIter::CScriptDictIter(const CScriptDictionary* dict) : iter(dict->begin()), refCount(1), iterGuard(dict->iterGuard) {}
|
||||
CScriptDictionary::CScriptDictIter::~CScriptDictIter() {}
|
||||
|
||||
void CScriptDictionary::CScriptDictIter::AddRef() const
|
||||
{
|
||||
asAtomicInc(refCount);
|
||||
}
|
||||
|
||||
void CScriptDictionary::CScriptDictIter::Release() const
|
||||
{
|
||||
if (asAtomicDec(refCount) == 0)
|
||||
{
|
||||
this->~CScriptDictIter();
|
||||
asFreeMem(const_cast<CScriptDictIter*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
CScriptDictionary::CScriptDictIter* CScriptDictionary::opForBegin() const
|
||||
{
|
||||
// Use the custom memory routine from AngelScript to allow application to better control how much memory is used
|
||||
CScriptDictionary::CScriptDictIter* iter = (CScriptDictionary::CScriptDictIter*)asAllocMem(sizeof(CScriptDictionary::CScriptDictIter));
|
||||
new(iter) CScriptDictionary::CScriptDictIter(this);
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::opForEnd(const CScriptDictionary::CScriptDictIter& iter) const
|
||||
{
|
||||
if (iter.iterGuard != iterGuard)
|
||||
return true;
|
||||
|
||||
if (iter.iter == end())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CScriptDictionary::CScriptDictIter* CScriptDictionary::opForNext(CScriptDictionary::CScriptDictIter& iter) const
|
||||
{
|
||||
if (iter.iterGuard != iterGuard)
|
||||
iter.iter = end();
|
||||
else
|
||||
++iter.iter;
|
||||
return &iter;
|
||||
}
|
||||
|
||||
const CScriptDictValue& CScriptDictionary::opForValue0(const CScriptDictionary::CScriptDictIter& iter) const
|
||||
{
|
||||
return iter.iter.m_it->second;
|
||||
}
|
||||
|
||||
const dictKey_t& CScriptDictionary::opForValue1(const CScriptDictionary::CScriptDictIter& iter) const
|
||||
{
|
||||
return iter.iter.m_it->first;
|
||||
}
|
||||
|
||||
void ScriptDictIterAddRef_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary::CScriptDictIter* iter = (CScriptDictionary::CScriptDictIter*)gen->GetObject();
|
||||
iter->AddRef();
|
||||
}
|
||||
|
||||
void ScriptDictIterRelease_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary::CScriptDictIter* iter = (CScriptDictionary::CScriptDictIter*)gen->GetObject();
|
||||
iter->Release();
|
||||
}
|
||||
|
||||
void ScriptDictionary_opForBegin_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary* dict = (CScriptDictionary*)gen->GetObject();
|
||||
*(CScriptDictionary::CScriptDictIter**)gen->GetAddressOfReturnLocation() = dict->opForBegin();
|
||||
}
|
||||
|
||||
void ScriptDictionary_opForEnd_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary* dict = (CScriptDictionary*)gen->GetObject();
|
||||
CScriptDictionary::CScriptDictIter* iter = *(CScriptDictionary::CScriptDictIter**)gen->GetAddressOfArg(0);
|
||||
*(bool*)gen->GetAddressOfReturnLocation() = dict->opForEnd(*iter);
|
||||
}
|
||||
|
||||
void ScriptDictionary_opForNext_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary* dict = (CScriptDictionary*)gen->GetObject();
|
||||
CScriptDictionary::CScriptDictIter* iter = *(CScriptDictionary::CScriptDictIter**)gen->GetAddressOfArg(0);
|
||||
*(CScriptDictionary::CScriptDictIter**)gen->GetAddressOfReturnLocation() = dict->opForNext(*iter);
|
||||
}
|
||||
|
||||
void ScriptDictionary_opForValue0_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary* dict = (CScriptDictionary*)gen->GetObject();
|
||||
CScriptDictionary::CScriptDictIter* iter = *(CScriptDictionary::CScriptDictIter**)gen->GetAddressOfArg(0);
|
||||
*reinterpret_cast<const CScriptDictValue**>(gen->GetAddressOfReturnLocation()) = &dict->opForValue0(*iter);
|
||||
}
|
||||
|
||||
void ScriptDictionary_opForValue1_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
CScriptDictionary* dict = (CScriptDictionary*)gen->GetObject();
|
||||
CScriptDictionary::CScriptDictIter* iter = *(CScriptDictionary::CScriptDictIter**)gen->GetAddressOfArg(0);
|
||||
*reinterpret_cast<const dictKey_t**>(gen->GetAddressOfReturnLocation()) = &dict->opForValue1(*iter);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Iterator implementation
|
||||
|
||||
CScriptDictionary::CIterator CScriptDictionary::begin() const
|
||||
{
|
||||
return CIterator(*this, dict.begin());
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator CScriptDictionary::end() const
|
||||
{
|
||||
return CIterator(*this, dict.end());
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t& key) const
|
||||
{
|
||||
return CIterator(*this, dict.find(key));
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator::CIterator(
|
||||
const CScriptDictionary& dict,
|
||||
dictMap_t::const_iterator it)
|
||||
: m_it(it), m_dict(dict)
|
||||
{
|
||||
}
|
||||
|
||||
void CScriptDictionary::CIterator::operator++()
|
||||
{
|
||||
++m_it;
|
||||
}
|
||||
|
||||
void CScriptDictionary::CIterator::operator++(int)
|
||||
{
|
||||
++m_it;
|
||||
|
||||
// Normally the post increment would return a copy of the object with the original state,
|
||||
// but it is rarely used so we skip this extra copy to avoid unnecessary overhead
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator& CScriptDictionary::CIterator::operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::operator==(const CIterator& other) const
|
||||
{
|
||||
return m_it == other.m_it;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::operator!=(const CIterator& other) const
|
||||
{
|
||||
return m_it != other.m_it;
|
||||
}
|
||||
|
||||
const dictKey_t& CScriptDictionary::CIterator::GetKey() const
|
||||
{
|
||||
return m_it->first;
|
||||
}
|
||||
|
||||
int CScriptDictionary::CIterator::GetTypeId() const
|
||||
{
|
||||
return m_it->second.m_typeId;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::GetValue(asINT64& value) const
|
||||
{
|
||||
return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::GetValue(double& value) const
|
||||
{
|
||||
return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::GetValue(void* value, int typeId) const
|
||||
{
|
||||
return m_it->second.Get(m_dict.engine, value, typeId);
|
||||
}
|
||||
|
||||
const void* CScriptDictionary::CIterator::GetAddressOfValue() const
|
||||
{
|
||||
return m_it->second.GetAddressOfValue();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Register the type
|
||||
|
||||
|
|
@ -1130,6 +1322,19 @@ void RegisterScriptDictionary_Native(asIScriptEngine *engine)
|
|||
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 );
|
||||
|
||||
// Support foreach
|
||||
r = engine->RegisterObjectType("dictionaryIter", 0, asOBJ_REF); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("dictionaryIter", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary::CScriptDictIter, AddRef), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("dictionaryIter", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary::CScriptDictIter, Release), asCALL_THISCALL); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionaryIter @opForBegin() const", asMETHODPR(CScriptDictionary, opForBegin, () const, CScriptDictionary::CScriptDictIter *), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool opForEnd(dictionaryIter @+) const", asMETHODPR(CScriptDictionary, opForEnd, (const CScriptDictionary::CScriptDictIter&) const, bool), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionaryIter @+ opForNext(dictionaryIter @+) const", asMETHODPR(CScriptDictionary, opForNext, (CScriptDictionary::CScriptDictIter&) const, CScriptDictionary::CScriptDictIter*), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opForValue0(dictionaryIter @+) const", asMETHODPR(CScriptDictionary, opForValue0, (const CScriptDictionary::CScriptDictIter&) const, const CScriptDictValue &), asCALL_THISCALL); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "const string &opForValue1(dictionaryIter @+) const", asMETHODPR(CScriptDictionary, opForValue1, (const CScriptDictionary::CScriptDictIter&) const, const dictKey_t&), 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 );
|
||||
|
|
@ -1208,92 +1413,21 @@ void RegisterScriptDictionary_Generic(asIScriptEngine *engine)
|
|||
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 );
|
||||
|
||||
// Support foreach
|
||||
r = engine->RegisterObjectType("dictionaryIter", 0, asOBJ_REF); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("dictionaryIter", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictIterAddRef_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectBehaviour("dictionaryIter", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictIterRelease_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionaryIter @opForBegin() const", asFUNCTION(ScriptDictionary_opForBegin_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "bool opForEnd(dictionaryIter @+) const", asFUNCTION(ScriptDictionary_opForEnd_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "dictionaryIter @+ opForNext(dictionaryIter @+) const", asFUNCTION(ScriptDictionary_opForNext_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opForValue0(dictionaryIter @+) const", asFUNCTION(ScriptDictionary_opForValue0_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("dictionary", "const string &opForValue1(dictionaryIter @+) const", asFUNCTION(ScriptDictionary_opForValue1_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
// Cache some things the dictionary will need at runtime
|
||||
SDictionaryCache::Setup(engine);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Iterator implementation
|
||||
|
||||
CScriptDictionary::CIterator CScriptDictionary::begin() const
|
||||
{
|
||||
return CIterator(*this, dict.begin());
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator CScriptDictionary::end() const
|
||||
{
|
||||
return CIterator(*this, dict.end());
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const
|
||||
{
|
||||
return CIterator(*this, dict.find(key));
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator::CIterator(
|
||||
const CScriptDictionary &dict,
|
||||
dictMap_t::const_iterator it)
|
||||
: m_it(it), m_dict(dict)
|
||||
{}
|
||||
|
||||
void CScriptDictionary::CIterator::operator++()
|
||||
{
|
||||
++m_it;
|
||||
}
|
||||
|
||||
void CScriptDictionary::CIterator::operator++(int)
|
||||
{
|
||||
++m_it;
|
||||
|
||||
// Normally the post increment would return a copy of the object with the original state,
|
||||
// but it is rarely used so we skip this extra copy to avoid unnecessary overhead
|
||||
}
|
||||
|
||||
CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::operator==(const CIterator &other) const
|
||||
{
|
||||
return m_it == other.m_it;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const
|
||||
{
|
||||
return m_it != other.m_it;
|
||||
}
|
||||
|
||||
const dictKey_t &CScriptDictionary::CIterator::GetKey() const
|
||||
{
|
||||
return m_it->first;
|
||||
}
|
||||
|
||||
int CScriptDictionary::CIterator::GetTypeId() const
|
||||
{
|
||||
return m_it->second.m_typeId;
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const
|
||||
{
|
||||
return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::GetValue(double &value) const
|
||||
{
|
||||
return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE);
|
||||
}
|
||||
|
||||
bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const
|
||||
{
|
||||
return m_it->second.Get(m_dict.engine, value, typeId);
|
||||
}
|
||||
|
||||
const void *CScriptDictionary::CIterator::GetAddressOfValue() const
|
||||
{
|
||||
return m_it->second.GetAddressOfValue();
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,31 @@ public:
|
|||
CIterator end() const;
|
||||
CIterator find(const dictKey_t &key) const;
|
||||
|
||||
// Iterator to support foreach in script
|
||||
class CScriptDictIter
|
||||
{
|
||||
public:
|
||||
// Reference counting
|
||||
void AddRef() const;
|
||||
void Release() const;
|
||||
|
||||
protected:
|
||||
friend class CScriptDictionary;
|
||||
|
||||
CIterator iter;
|
||||
mutable int refCount;
|
||||
asUINT iterGuard;
|
||||
|
||||
CScriptDictIter(const CScriptDictionary* dict);
|
||||
~CScriptDictIter();
|
||||
};
|
||||
|
||||
CScriptDictIter* opForBegin() const;
|
||||
bool opForEnd(const CScriptDictIter &iter) const;
|
||||
CScriptDictIter* opForNext(CScriptDictIter& iter) const;
|
||||
const CScriptDictValue& opForValue0(const CScriptDictIter& iter) const;
|
||||
const dictKey_t& opForValue1(const CScriptDictIter& iter) const;
|
||||
|
||||
// Garbage collections behaviours
|
||||
int GetRefCount();
|
||||
void SetGCFlag();
|
||||
|
|
@ -221,6 +246,7 @@ protected:
|
|||
mutable int refCount;
|
||||
mutable bool gcFlag;
|
||||
dictMap_t dict;
|
||||
asUINT iterGuard;
|
||||
};
|
||||
|
||||
// This function will determine the configuration of the engine
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace satdump
|
|||
{
|
||||
RegisterStdString(engine);
|
||||
RegisterScriptArray(engine, true);
|
||||
RegisterStdStringUtils(engine);
|
||||
RegisterScriptDictionary(engine);
|
||||
|
||||
registerLogger(engine);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef __psp2__
|
||||
#include <locale.h> // setlocale()
|
||||
#endif
|
||||
#include <regex>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -374,6 +376,51 @@ static int StringFindFirst(const string &sub, asUINT start, const string &str)
|
|||
return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start));
|
||||
}
|
||||
|
||||
// This function returns the index of the first position that matches the regular expression
|
||||
//
|
||||
// AngelScript signature:
|
||||
// int string::regexFind(const string &in regex, uint start = 0, uint &out lengthOfMatch = void)
|
||||
static int StringRegexFind(const string& rex, asUINT start, asUINT& outLengthOfMatch, const string& str)
|
||||
{
|
||||
if (start >= str.length())
|
||||
{
|
||||
outLengthOfMatch = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: If possible add support for matching utf8 characters
|
||||
// However on with MSVC it doesn't seem that std::regex works with utf8
|
||||
// This works with MSVC, but I don't want to have to convert the string to UTF-16 first because the position and length will not work
|
||||
// https://www.regular-expressions.info/stdregex.html
|
||||
//
|
||||
// std::wregex pattern(L"[[:alpha:]]+");
|
||||
// bool result = std::regex_match(std::wstring(L"abcdéfg"), pattern);
|
||||
//
|
||||
// The solution from stack overflow doesn't work with MSVC
|
||||
// https://stackoverflow.com/questions/11254232/do-c11-regular-expressions-work-with-utf-8-strings
|
||||
//
|
||||
// std::locale old;
|
||||
// std::locale::global(std::locale("en_US.UTF-8"));
|
||||
// std::regex pattern("[[:alpha:]]+", std::regex_constants::extended);
|
||||
// bool result = std::regex_match(std::string(u8"abcdéfg"), pattern);
|
||||
//
|
||||
// I've tried setting the manifest to use utf8 code page but it also doesn't work with MSVC
|
||||
// https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page
|
||||
|
||||
std::regex pattern(rex, std::regex_constants::ECMAScript | std::regex_constants::collate);
|
||||
std::cmatch match;
|
||||
bool result = std::regex_search(str.c_str() + start, str.c_str()+str.length(), match, pattern);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
outLengthOfMatch = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
outLengthOfMatch = (asUINT)match[0].length();
|
||||
return (int)match.prefix().length();
|
||||
}
|
||||
|
||||
// This function returns the index of the first position where the one of the bytes in substring
|
||||
// exists in the input string. If the characters in the substring doesn't exist in the input
|
||||
// string -1 is returned.
|
||||
|
|
@ -590,6 +637,169 @@ static string formatFloat(double value, const string &options, asUINT width, asU
|
|||
return buf;
|
||||
}
|
||||
|
||||
// TODO: variadic: review
|
||||
static void StringFormat(asIScriptGeneric* gen)
|
||||
{
|
||||
const string& fmt = *(string*)gen->GetArgAddress(0);
|
||||
string result;
|
||||
|
||||
asUINT defaultArgIdx = 1; // Skip the first argument which is the fmt
|
||||
for (asUINT i = 0; i < fmt.size(); ++i)
|
||||
{
|
||||
char ch = fmt[i];
|
||||
if (ch == '{')
|
||||
{
|
||||
if (i + 1 >= (asUINT)fmt.size())
|
||||
{
|
||||
asGetActiveContext()->SetException("Invalid format string");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fmt[i + 1] == '{')
|
||||
{
|
||||
i += 1;
|
||||
result += '{';
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Parse optional argument index to support for relocating argument
|
||||
// e.g. "{1} {0}".format("there", "hello") == "hello there"
|
||||
asUINT argIdx = defaultArgIdx++;
|
||||
if (argIdx >= (asUINT)gen->GetArgCount())
|
||||
{
|
||||
asGetActiveContext()->SetException("Index out of range");
|
||||
return;
|
||||
}
|
||||
int typeId = gen->GetArgTypeId(argIdx);
|
||||
void* ref = gen->GetArgAddress(argIdx);
|
||||
|
||||
switch (typeId)
|
||||
{
|
||||
case asTYPEID_BOOL:
|
||||
result += *(bool*)ref ? "true" : "false";
|
||||
break;
|
||||
|
||||
#define AS_STRING_FORMAT_IMPL(tid, type) \
|
||||
case tid: result += to_string(*(type*)ref); break
|
||||
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_INT8, int8_t);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_INT16, int16_t);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_INT32, int32_t);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_INT64, int64_t);
|
||||
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_UINT8, uint8_t);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_UINT16, uint16_t);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_UINT32, uint32_t);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_UINT64, uint64_t);
|
||||
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_FLOAT, float);
|
||||
AS_STRING_FORMAT_IMPL(asTYPEID_DOUBLE, double);
|
||||
|
||||
default:
|
||||
if (typeId & ~asTYPEID_MASK_SEQNBR)
|
||||
{
|
||||
asIScriptEngine* engine = gen->GetEngine();
|
||||
int stringTypeId = engine->GetStringFactory();
|
||||
if (typeId == stringTypeId)
|
||||
{
|
||||
result += *(string*)ref;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Better explanation
|
||||
asGetActiveContext()->SetException("Unformattable");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else // enums
|
||||
{
|
||||
// TODO: Format enum name
|
||||
result += to_string(*(int*)ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ch == '}')
|
||||
{
|
||||
if (i + 1 < (asUINT)fmt.size() && fmt[i + 1] == '}')
|
||||
{
|
||||
i += 1;
|
||||
result += '}';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ordinary character
|
||||
result += ch;
|
||||
}
|
||||
}
|
||||
|
||||
new(gen->GetAddressOfReturnLocation()) string(std::move(result));
|
||||
}
|
||||
|
||||
// TODO: variadic: review
|
||||
static void StringScan(asIScriptGeneric* gen)
|
||||
{
|
||||
asIScriptEngine* engine = gen->GetEngine();
|
||||
|
||||
stringstream ss(*(string*)gen->GetArgObject(0));
|
||||
asUINT scanned = 0;
|
||||
|
||||
for (asUINT i = 1; i < (asUINT)gen->GetArgCount(); ++i)
|
||||
{
|
||||
int typeId = gen->GetArgTypeId(i);
|
||||
if (!(typeId & ~asTYPEID_MASK_SEQNBR))
|
||||
{
|
||||
#define AS_STRING_SCAN_IMPL(tid, type) \
|
||||
case tid:\
|
||||
do {\
|
||||
type val;\
|
||||
ss >> val;\
|
||||
if(!ss) goto end_scan;\
|
||||
void* ref = gen->GetArgAddress(i); \
|
||||
*(type*)ref = val;\
|
||||
} while(0); \
|
||||
break
|
||||
|
||||
switch (typeId)
|
||||
{
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_BOOL, bool);
|
||||
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_INT16, int16_t);
|
||||
default: // enum
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_INT32, int32_t);
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_INT64, int64_t);
|
||||
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_UINT8, uint8_t);
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_UINT16, uint16_t);
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_UINT32, uint32_t);
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_UINT64, uint64_t);
|
||||
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_FLOAT, float);
|
||||
AS_STRING_SCAN_IMPL(asTYPEID_DOUBLE, double);
|
||||
}
|
||||
}
|
||||
else if (typeId == engine->GetStringFactory())
|
||||
{
|
||||
string val;
|
||||
ss >> val;
|
||||
if (!ss) goto end_scan;
|
||||
|
||||
void* ref = gen->GetArgAddress(i);
|
||||
*(string*)ref = std::move(val);
|
||||
}
|
||||
else // Invalid type
|
||||
{
|
||||
goto end_scan;
|
||||
}
|
||||
|
||||
++scanned;
|
||||
}
|
||||
|
||||
end_scan:
|
||||
gen->SetReturnDWord(scanned);
|
||||
}
|
||||
|
||||
// AngelScript signature:
|
||||
// int64 parseInt(const string &in val, uint base = 10, uint &out byteCount = 0)
|
||||
static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount)
|
||||
|
|
@ -697,21 +907,41 @@ double parseFloat(const string &val, asUINT *byteCount)
|
|||
{
|
||||
char *end;
|
||||
|
||||
// Set the locale to C so that we are guaranteed to parse the float value correctly
|
||||
#if defined(_WIN32)
|
||||
// WinCE doesn't have setlocale. Some quick testing on my current platform
|
||||
// still manages to parse the numbers such as "3.14" even if the decimal for the
|
||||
// locale is ",".
|
||||
#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__)
|
||||
// Set the locale to C so that we are guaranteed to parse the float value correctly
|
||||
char *tmp = setlocale(LC_NUMERIC, 0);
|
||||
#if !defined(_WIN32_WCE)
|
||||
// On Windows setlocale is made threadsafe by turning on thread local setlocale
|
||||
// ref: https://learn.microsoft.com/en-us/cpp/parallel/multithreading-and-locales?view=msvc-170&redirectedfrom=MSDN
|
||||
int oldConfig = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
char* tmp = setlocale(LC_NUMERIC, 0);
|
||||
string orig = tmp ? tmp : "C";
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
#endif
|
||||
#else
|
||||
#if !defined(ANDROID) && !defined(__psp2__)
|
||||
// On Linux and other similar systems the threadsafe option is uselocale
|
||||
// ref: https://stackoverflow.com/questions/4057319/is-setlocale-thread-safe-function
|
||||
locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
|
||||
locale_t orig_locale = uselocale(locale);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
double res = strtod(val.c_str(), &end);
|
||||
|
||||
#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__)
|
||||
// Restore the locale
|
||||
// Restore the original locale
|
||||
#if defined(_WIN32)
|
||||
#if !defined(_WIN32_WCE)
|
||||
setlocale(LC_NUMERIC, orig.c_str());
|
||||
_configthreadlocale(oldConfig);
|
||||
#endif
|
||||
#else
|
||||
#if !defined(ANDROID) && !defined(__psp2__)
|
||||
#endif
|
||||
uselocale(orig_locale);
|
||||
freelocale(locale);
|
||||
#endif
|
||||
|
||||
if( byteCount )
|
||||
|
|
@ -833,8 +1063,10 @@ void RegisterStdString_Native(asIScriptEngine *engine)
|
|||
r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("string", "int regexFind(const string &in regex, uint start = 0, uint &out lengthOfMatch = void) const", asFUNCTION(StringRegexFind), asCALL_CDECL_OBJLAST); assert(r >= 0);
|
||||
|
||||
|
||||
r = engine->RegisterGlobalFunction("uint scan(const string&in str, ?&out ...)", asFUNCTION(StringScan), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string format(const string&in fmt, const ?&in ...)", asFUNCTION(StringFormat), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0);
|
||||
|
|
@ -1281,6 +1513,18 @@ static void StringSubString_Generic(asIScriptGeneric *gen)
|
|||
new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str));
|
||||
}
|
||||
|
||||
// static int StringRegexFind(const string& rex, asUINT start, asUINT& outLengthOfMatch, const string& str)
|
||||
static void StringRegexFind_Generic(asIScriptGeneric* gen)
|
||||
{
|
||||
// Get the arguments
|
||||
string* str = (string*)gen->GetObject();
|
||||
string *rex = *(string**)gen->GetAddressOfArg(0);
|
||||
asUINT start = *(asUINT*)gen->GetAddressOfArg(1);
|
||||
asUINT* outLen = *(asUINT**)gen->GetAddressOfArg(2);
|
||||
|
||||
*(int*)(gen->GetAddressOfReturnLocation()) = StringRegexFind(*rex, start, *outLen, *str);
|
||||
}
|
||||
|
||||
void RegisterStdString_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r = 0;
|
||||
|
|
@ -1354,8 +1598,10 @@ void RegisterStdString_Generic(asIScriptEngine *engine)
|
|||
r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterObjectMethod("string", "int regexFind(const string &in regex, uint start = 0, uint &out lengthOfMatch = void) const", asFUNCTION(StringRegexFind_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
||||
|
||||
r = engine->RegisterGlobalFunction("uint scan(const string&in str, ?&out ...)", asFUNCTION(StringScan), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string format(const string&in fmt, const ?&in ...)", asFUNCTION(StringFormat), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ BEGIN_AS_NAMESPACE
|
|||
// for a specified delimiter. Example:
|
||||
//
|
||||
// string str = "A|B||D";
|
||||
// array<string>@ array = str.split("|");
|
||||
// array<string>@ arr = str.split("|");
|
||||
//
|
||||
// The resulting array has the following elements:
|
||||
//
|
||||
|
|
@ -70,15 +70,15 @@ static void StringSplit_Generic(asIScriptGeneric *gen)
|
|||
// delimiter and concatenates the array elements into one delimited string.
|
||||
// Example:
|
||||
//
|
||||
// array<string> array = {"A", "B", "", "D"};
|
||||
// string str = join(array, "|");
|
||||
// array<string> arr = {"A", "B", "", "D"};
|
||||
// string str = join(arr, "|");
|
||||
//
|
||||
// The resulting string is:
|
||||
//
|
||||
// "A|B||D"
|
||||
//
|
||||
// AngelScript signature:
|
||||
// string join(const array<string> &in array, const string &in delim)
|
||||
// string join(const array<string> &in arr, const string &in delim)
|
||||
static string StringJoin(const CScriptArray &array, const string &delim)
|
||||
{
|
||||
// Create the new string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue