1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-25 01:03:01 +00:00

(trunk libT) avoid about 75% of the strdup/malloc/frees in benc by using a union of char* and a small string buffer, and using the buffer if the string is small enough

This commit is contained in:
Charles Kerr 2009-06-01 22:15:50 +00:00
parent 7f85090587
commit 9bfec90e43
2 changed files with 70 additions and 43 deletions

View file

@ -358,9 +358,30 @@ tr_bencLoad( const void * buf_in,
**** ****
***/ ***/
/* returns true if the given string length would fit in our string buffer */
static TR_INLINE int
stringFitsInBuffer( const tr_benc * val, int len )
{
return len < (int)sizeof( val->val.s.str.buf );
}
/* returns true if the benc's string was malloced.
* this occurs when the string is too long for our string buffer */
static TR_INLINE int
stringIsAlloced( const tr_benc * val )
{
return !stringFitsInBuffer( val, val->val.s.len );
}
/* returns a const pointer to the benc's string */
static TR_INLINE const char*
getStr( const tr_benc* val )
{
return stringIsAlloced(val) ? val->val.s.str.ptr : val->val.s.str.buf;
}
static int static int
dictIndexOf( const tr_benc * val, dictIndexOf( const tr_benc * val, const char * key )
const char * key )
{ {
if( tr_bencIsDict( val ) ) if( tr_bencIsDict( val ) )
{ {
@ -370,10 +391,9 @@ dictIndexOf( const tr_benc * val,
for( i = 0; ( i + 1 ) < val->val.l.count; i += 2 ) for( i = 0; ( i + 1 ) < val->val.l.count; i += 2 )
{ {
const tr_benc * child = val->val.l.vals + i; const tr_benc * child = val->val.l.vals + i;
if( ( child->type == TR_TYPE_STR ) if( ( child->type == TR_TYPE_STR )
&& ( child->val.s.i == len ) && ( child->val.s.len == len )
&& !memcmp( child->val.s.s, key, len ) ) && !memcmp( getStr(child), key, len ) )
return i; return i;
} }
} }
@ -444,7 +464,7 @@ tr_bencGetStr( const tr_benc * val,
const int success = tr_bencIsString( val ); const int success = tr_bencIsString( val );
if( success ) if( success )
*setme = val->val.s.s; *setme = getStr( val );
return success; return success;
} }
@ -452,6 +472,7 @@ tr_bencGetStr( const tr_benc * val,
tr_bool tr_bool
tr_bencGetBool( const tr_benc * val, tr_bool * setme ) tr_bencGetBool( const tr_benc * val, tr_bool * setme )
{ {
const char * str;
tr_bool success = FALSE; tr_bool success = FALSE;
if(( success = tr_bencIsBool( val ))) if(( success = tr_bencIsBool( val )))
@ -461,9 +482,9 @@ tr_bencGetBool( const tr_benc * val, tr_bool * setme )
if(( success = ( val->val.i==0 || val->val.i==1 ) )) if(( success = ( val->val.i==0 || val->val.i==1 ) ))
*setme = val->val.i!=0; *setme = val->val.i!=0;
if( !success && tr_bencIsString( val ) ) if( !success && tr_bencGetStr( val, &str ) )
if(( success = ( !strcmp(val->val.s.s,"true") || !strcmp(val->val.s.s,"false")))) if(( success = ( !strcmp(str,"true") || !strcmp(str,"false"))))
*setme = !strcmp(val->val.s.s,"true"); *setme = !strcmp(str,"true");
return success; return success;
} }
@ -488,10 +509,10 @@ tr_bencGetReal( const tr_benc * val, double * setme )
/* the json spec requires a '.' decimal point regardless of locale */ /* the json spec requires a '.' decimal point regardless of locale */
tr_strlcpy( locale, setlocale( LC_NUMERIC, NULL ), sizeof( locale ) ); tr_strlcpy( locale, setlocale( LC_NUMERIC, NULL ), sizeof( locale ) );
setlocale( LC_NUMERIC, "POSIX" ); setlocale( LC_NUMERIC, "POSIX" );
d = strtod( val->val.s.s, &endptr ); d = strtod( getStr(val), &endptr );
setlocale( LC_NUMERIC, locale ); setlocale( LC_NUMERIC, locale );
if(( success = ( val->val.s.s != endptr ) && !*endptr )) if(( success = ( getStr(val) != endptr ) && !*endptr ))
*setme = d; *setme = d;
} }
@ -545,8 +566,8 @@ tr_bencDictFindRaw( tr_benc * dict,
const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child ); const tr_bool found = tr_bencDictFindType( dict, key, TR_TYPE_STR, &child );
if( found ) { if( found ) {
*setme_raw = (uint8_t*) child->val.s.s; *setme_raw = (uint8_t*) getStr(child);
*setme_len = child->val.s.i; *setme_len = child->val.s.len;
} }
return found; return found;
@ -557,30 +578,31 @@ tr_bencDictFindRaw( tr_benc * dict,
***/ ***/
void void
tr_bencInitRaw( tr_benc * val, tr_bencInitRaw( tr_benc * val, const void * src, size_t byteCount )
const void * src,
size_t byteCount )
{ {
tr_bencInit( val, TR_TYPE_STR ); tr_bencInit( val, TR_TYPE_STR );
val->val.s.i = byteCount;
val->val.s.s = tr_memdup( src, byteCount ); if( stringFitsInBuffer( val, val->val.s.len = byteCount ))
memcpy( val->val.s.str.buf, src, byteCount );
else
val->val.s.str.ptr = tr_memdup( src, byteCount );
} }
void void
tr_bencInitStr( tr_benc * val, tr_bencInitStr( tr_benc * val, const void * str, int len )
const void * str,
int len )
{ {
tr_bencInit( val, TR_TYPE_STR ); tr_bencInit( val, TR_TYPE_STR );
val->val.s.s = tr_strndup( str, len ); if( str == NULL )
len = 0;
if( val->val.s.s == NULL )
val->val.s.i = 0;
else if( len < 0 ) else if( len < 0 )
val->val.s.i = strlen( val->val.s.s ); len = strlen( str );
else
val->val.s.i = len; if( stringFitsInBuffer( val, val->val.s.len = len )) {
memcpy( val->val.s.str.buf, str, len );
val->val.s.str.buf[len] = '\0';
} else
val->val.s.str.ptr = tr_strndup( str, len );
} }
void void
@ -764,9 +786,10 @@ tr_bencDictAddStr( tr_benc * dict, const char * key, const char * val )
/* see if it already exists, and if so, try to reuse it */ /* see if it already exists, and if so, try to reuse it */
if(( child = tr_bencDictFind( dict, key ))) { if(( child = tr_bencDictFind( dict, key ))) {
if( tr_bencIsString( child ) ) if( tr_bencIsString( child ) ) {
tr_free( child->val.s.s ); if( stringIsAlloced( child ) )
else { tr_free( child->val.s.str.ptr );
} else {
tr_bencDictRemove( dict, key ); tr_bencDictRemove( dict, key );
child = NULL; child = NULL;
} }
@ -885,7 +908,7 @@ nodeNewDict( const tr_benc * val )
indices = tr_new( struct KeyIndex, nKeys ); indices = tr_new( struct KeyIndex, nKeys );
for( i = j = 0; i < ( nKeys * 2 ); i += 2, ++j ) for( i = j = 0; i < ( nKeys * 2 ); i += 2, ++j )
{ {
indices[j].key = val->val.l.vals[i].val.s.s; indices[j].key = getStr(&val->val.l.vals[i]);
indices[j].index = i; indices[j].index = i;
} }
qsort( indices, j, sizeof( struct KeyIndex ), compareKeyIndex ); qsort( indices, j, sizeof( struct KeyIndex ), compareKeyIndex );
@ -1081,8 +1104,8 @@ saveRealFunc( const tr_benc * val, void * evbuf )
static void static void
saveStringFunc( const tr_benc * val, void * evbuf ) saveStringFunc( const tr_benc * val, void * evbuf )
{ {
evbuffer_add_printf( evbuf, "%lu:", (unsigned long)val->val.s.i ); evbuffer_add_printf( evbuf, "%lu:", (unsigned long)val->val.s.len );
evbuffer_add( evbuf, val->val.s.s, val->val.s.i ); evbuffer_add( evbuf, getStr(val), val->val.s.len );
} }
static void static void
@ -1141,7 +1164,8 @@ static void
freeStringFunc( const tr_benc * val, freeStringFunc( const tr_benc * val,
void * freeme ) void * freeme )
{ {
tr_ptrArrayAppend( freeme, val->val.s.s ); if( stringIsAlloced( val ) )
tr_ptrArrayAppend( freeme, val->val.s.str.ptr );
} }
static void static void
@ -1302,10 +1326,10 @@ static void
jsonStringFunc( const tr_benc * val, void * vdata ) jsonStringFunc( const tr_benc * val, void * vdata )
{ {
struct jsonWalk * data = vdata; struct jsonWalk * data = vdata;
const unsigned char * it = (const unsigned char *) val->val.s.s; const unsigned char * it = (const unsigned char *) getStr(val);
const unsigned char * end = it + val->val.s.i; const unsigned char * end = it + val->val.s.len;
evbuffer_expand( data->out, val->val.s.i + 2 ); evbuffer_expand( data->out, val->val.s.len + 2 );
evbuffer_add( data->out, "\"", 1 ); evbuffer_add( data->out, "\"", 1 );
for( ; it!=end; ++it ) for( ; it!=end; ++it )

View file

@ -49,8 +49,6 @@ enum
* it's included in the header for inlining and composition */ * it's included in the header for inlining and composition */
typedef struct tr_benc typedef struct tr_benc
{ {
char type;
union union
{ {
uint8_t b; /* bool type */ uint8_t b; /* bool type */
@ -61,17 +59,22 @@ typedef struct tr_benc
struct /* string type */ struct /* string type */
{ {
size_t i; /* the string length */ size_t len; /* the string length */
char * s; /* the string */ union {
char buf[16]; /* a local buffer */
char * ptr; /* alloc'ed string */
} str;
} s; } s;
struct /* list & dict types */ struct /* list & dict types */
{ {
struct tr_benc * vals; /* nodes */
size_t alloc; /* nodes allocated */ size_t alloc; /* nodes allocated */
size_t count; /* nodes used */ size_t count; /* nodes used */
struct tr_benc * vals; /* nodes */
} l; } l;
} val; } val;
char type;
} tr_benc; } tr_benc;
/*** /***