diff --git a/squirrel/sqobject.cpp b/squirrel/sqobject.cpp index 7d7f297..909e6e9 100644 --- a/squirrel/sqobject.cpp +++ b/squirrel/sqobject.cpp @@ -52,6 +52,12 @@ SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) return str; } +SQString* SQString::Concat(SQSharedState* ss, const SQChar* a, SQInteger alen, const SQChar* b, SQInteger blen) +{ + SQString* str = ss->_stringtable->Concat(a, alen, b, blen); + return str; +} + void SQString::Release() { REMOVE_STRING(_sharedstate,this); diff --git a/squirrel/sqstate.cpp b/squirrel/sqstate.cpp index c89bdc4..f066cef 100644 --- a/squirrel/sqstate.cpp +++ b/squirrel/sqstate.cpp @@ -577,6 +577,41 @@ void SQStringTable::AllocNodes(SQInteger size) memset(_strings,0,sizeof(SQString*)*_numofslots); } +SQString* SQStringTable::Concat(const SQChar* a, SQInteger alen, const SQChar* b, SQInteger blen) +{ + SQHash newhash = ::_hashstr2(a, alen, b, blen); + SQHash h = newhash & (_numofslots - 1); + SQString* s; + SQInteger len = alen + blen; + for (s = _strings[h]; s; s = s->_next) { + if (s->_len == len) { + if ((!memcmp(a, s->_val, sq_rsl(alen))) + && (!memcmp(b, &s->_val[alen], sq_rsl(blen)))) { + return s; //found + } + } + } + // + SQString* t = (SQString*)SQ_MALLOC(sq_rsl(len) + sizeof(SQString)); + new (t) SQString; + t->_sharedstate = _sharedstate; + memcpy(t->_val, a, sq_rsl(alen)); + memcpy(&t->_val[alen], b, sq_rsl(blen)); + t->_val[len] = _SC('\0'); + t->_len = len; + t->_hash = newhash; + t->_next = _strings[h]; + _strings[h] = t; + _slotused++; +#ifdef _DEBUG + SQHash old_newhash = ::_hashstr(t->_val, t->_len); + assert(old_newhash == newhash); +#endif + if (_slotused > _numofslots) /* too crowded? */ + Resize(_numofslots * 2); + return t; +} + SQString *SQStringTable::Add(const SQChar *news,SQInteger len) { if(len<0) diff --git a/squirrel/sqstate.h b/squirrel/sqstate.h index 2cdc8da..d1e2483 100644 --- a/squirrel/sqstate.h +++ b/squirrel/sqstate.h @@ -14,6 +14,7 @@ struct SQStringTable SQStringTable(SQSharedState*ss); ~SQStringTable(); SQString *Add(const SQChar *,SQInteger len); + SQString* Concat(const SQChar* a, SQInteger alen, const SQChar* b, SQInteger blen); void Remove(SQString *); private: void Resize(SQInteger size); diff --git a/squirrel/sqstring.h b/squirrel/sqstring.h index 0099f3b..56af2d2 100644 --- a/squirrel/sqstring.h +++ b/squirrel/sqstring.h @@ -12,12 +12,33 @@ inline SQHash _hashstr (const SQChar *s, size_t l) return h; } +inline SQHash _hashstr2(const SQChar* as, size_t al, const SQChar* bs, size_t bl) +{ + size_t l = al + bl; + SQHash h = (SQHash)l; /* seed */ + SQInteger step = (SQInteger)((l >> 5) + 1); /* if string is too long, don't hash all its chars */ + SQInteger l1 = (SQInteger)l; + for (; l1 >= step; l1 -= step) { + SQInteger idx = l1 - 1 - al; + if (idx < 0) { + break; + } + h = h ^ ((h << 5) + (h >> 2) + ((unsigned short)bs[idx])); + } + for (; l1 >= step; l1 -= step) { + SQInteger idx = l1 - 1; + h = h ^ ((h << 5) + (h >> 2) + ((unsigned short)as[idx])); + } + return h; +} + struct SQString : public SQRefCounted { SQString(){} ~SQString(){} public: static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 ); + static SQString* Concat(SQSharedState* ss, const SQChar* a, SQInteger alen, const SQChar* b, SQInteger blen); SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); void Release(); SQSharedState *_sharedstate; diff --git a/squirrel/sqvm.cpp b/squirrel/sqvm.cpp index c70166d..25249f6 100644 --- a/squirrel/sqvm.cpp +++ b/squirrel/sqvm.cpp @@ -322,17 +322,20 @@ bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) return true; } - bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) { SQObjectPtr a, b; if(!ToString(str, a)) return false; if(!ToString(obj, b)) return false; SQInteger l = _string(a)->_len , ol = _string(b)->_len; - SQChar *s = _sp(sq_rsl(l + ol + 1)); +#ifdef SQ_NO_FAST_STRINGCAT + SQChar* s = _sp(sq_rsl(l + ol + 1)); memcpy(s, _stringval(a), sq_rsl(l)); memcpy(s + l, _stringval(b), sq_rsl(ol)); dest = SQString::Create(_ss(this), _spval, l + ol); +#else + dest = SQString::Concat(_ss(this),_stringval(a),l,_stringval(b),ol); +#endif return true; } @@ -1779,11 +1782,11 @@ void SQVM::dumpstack(SQInteger stackbase,bool dumpall) for(SQInteger i=0;i"));else scprintf(_SC(" ")); - scprintf(_SC("[" _PRINT_INT_FMT "]:"),n); + scprintf(_SC("[") _PRINT_INT_FMT _SC("]:"),n); switch(sq_type(obj)){ case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break; - case OT_INTEGER: scprintf(_SC("INTEGER " _PRINT_INT_FMT),_integer(obj));break; - case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break; + case OT_INTEGER: scprintf(_SC("INTEGER ") _PRINT_INT_FMT,_integer(obj));break; + case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?_SC("true"):_SC("false"));break; case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break; case OT_NULL: scprintf(_SC("NULL")); break; case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;