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:
parent
7f85090587
commit
9bfec90e43
2 changed files with 70 additions and 43 deletions
|
@ -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 )
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
Loading…
Reference in a new issue