faster string cat

This commit is contained in:
Alberto Demichelis
2024-11-03 12:20:33 +01:00
parent 7e64d7b257
commit 95569768ed
5 changed files with 71 additions and 5 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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<size;i++){
SQObjectPtr &obj=_stack[i];
if(stackbase==i)scprintf(_SC(">"));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;