Skip to content

Commit

Permalink
Unroll sscanf into strncmp and strtol
Browse files Browse the repository at this point in the history
  • Loading branch information
msg7086 committed Feb 7, 2025
1 parent 7dc8ba9 commit 721fe20
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 3 deletions.
9 changes: 6 additions & 3 deletions common/lwindex.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ extern "C"
#include <windows.h>
#endif

#include "lwindex_sscanf_unrolled.h"

typedef struct
{
lwlibav_extradata_handler_t exh;
Expand Down Expand Up @@ -3077,7 +3079,7 @@ static int parse_index
int64_t pos;
int64_t pts;
int64_t dts;
if( sscanf( buf, "Index=%d,POS=%" SCNd64 ",PTS=%" SCNd64 ",DTS=%" SCNd64 ",EDI=%d",
if( sscanf_unrolled1( buf, // "Index=%d,POS=%" SCNd64 ",PTS=%" SCNd64 ",DTS=%" SCNd64 ",EDI=%d",
&stream_index, &pos, &pts, &dts, &extradata_index ) != 5 )
goto fail_parsing;
if( !fgets( buf, sizeof(buf), index ) )
Expand Down Expand Up @@ -3109,7 +3111,7 @@ static int parse_index
int poc;
int repeat_pict;
int field_info;
if( sscanf( buf, "Key=%d,Pic=%d,POC=%d,Repeat=%d,Field=%d",
if( sscanf_unrolled2( buf, // "Key=%d,Pic=%d,POC=%d,Repeat=%d,Field=%d",
&key, &pict_type, &poc, &repeat_pict, &field_info ) != 5 )
goto fail_parsing;
if( vdhp->codec_id == AV_CODEC_ID_NONE )
Expand Down Expand Up @@ -3191,7 +3193,8 @@ static int parse_index
char *sample_fmt = stream_info[stream_index].fmt;
int bits_per_sample = stream_info[stream_index].bits_per_sample;
int frame_length;
if( sscanf( buf, "Length=%d", &frame_length ) != 1 )
if( sscanf_unrolled3( buf, // "Length=%d"
&frame_length ) != 1 )
goto fail_parsing;
if( adhp->codec_id == AV_CODEC_ID_NONE )
adhp->codec_id = (enum AVCodecID)codec_id;
Expand Down
166 changes: 166 additions & 0 deletions common/lwindex_sscanf_unrolled.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*****************************************************************************
* lwindex_sscanf_unrolled.h
*****************************************************************************
* Copyright (C) 2012-2025 L-SMASH Works project
*
* Authors: Xinyue Lu <[email protected]>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*****************************************************************************/

/* This file is available under an ISC license. */

#include <ctype.h>
#include <limits.h>

#define PARSE_OR_RETURN(buf, needle, out, type) \
if (strncmp(buf, needle, strlen(needle)) != 0) \
return 0; \
buf += strlen(needle); \
out = my_strto_##type(buf, &buf); \
parsed_count++;

#define CHECK_COMMA_OR_RETURN(p, parsed_count) \
if (*p != ',') \
return parsed_count; \
p++;

static inline int64_t my_strto_int64_t(const char *nptr, char **endptr) {
const char *s = nptr;
int64_t acc;
int c;
int neg = 0;

/* Process sign. */
if (*s == '-') {
neg = 1;
s++;
} else if (*s == '+')
s++;

acc = 0;
for (;;s++) {
c = *s;
if (isdigit(c))
c -= '0';
else
break;
if (c >= 10)
break;
if (acc > (LLONG_MAX - c) / 10) {
acc = LLONG_MAX;
errno = ERANGE;
return neg ? LLONG_MIN : LLONG_MAX;
}
acc *= 10;
acc += c;
}
if (endptr != NULL)
*endptr = (char *)s;
return (neg ? -acc : acc);
}

static inline int my_strto_int(const char *nptr, char **endptr) {
const char *s = nptr;
int acc;
int c;
int neg = 0;

/* Process sign. */
if (*s == '-') {
neg = 1;
s++;
} else if (*s == '+')
s++;

acc = 0;
for (;;s++) {
c = *s;
if (isdigit(c))
c -= '0';
else
break;
if (c >= 10)
break;
if (acc > (INT_MAX - c) / 10) {
acc = INT_MAX;
errno = ERANGE;
return neg ? INT_MIN : INT_MAX;
}
acc *= 10;
acc += c;
}
if (endptr != NULL)
*endptr = (char *)s;
return (neg ? -acc : acc);
}

/*
Unroll the following sscanf:
sscanf( buf, "Index=%d,POS=%" SCNd64 ",PTS=%" SCNd64 ",DTS=%" SCNd64 ",EDI=%d",
&stream_index, &pos, &pts, &dts, &extradata_index )
*/
static inline int sscanf_unrolled1( const char *buf, int *stream_index, int64_t *pos, int64_t *pts, int64_t *dts, int *extradata_index )
{
char *p = (char *)buf;
int parsed_count = 0;

PARSE_OR_RETURN(p, "Index=", *stream_index, int);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "POS=", *pos, int64_t);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "PTS=", *pts, int64_t);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "DTS=", *dts, int64_t);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "EDI=", *extradata_index, int);

return parsed_count;
}

/*
Unroll the following sscanf:
sscanf( buf, "Key=%d,Pic=%d,POC=%d,Repeat=%d,Field=%d",
&key, &pict_type, &poc, &repeat_pict, &field_info )
*/
static inline int sscanf_unrolled2( const char *buf, int *key, int *pict_type, int *poc, int *repeat_pict, int *field_info )
{
char *p = (char *)buf;
int parsed_count = 0;

PARSE_OR_RETURN(p, "Key=", *key, int);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "Pic=", *pict_type, int);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "POC=", *poc, int);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "Repeat=", *repeat_pict, int);
CHECK_COMMA_OR_RETURN(p, parsed_count);
PARSE_OR_RETURN(p, "Field=", *field_info, int);

return parsed_count;
}

/*
Unroll the following sscanf:
sscanf( buf, "Length=%d", &frame_length )
*/
static inline int sscanf_unrolled3( const char *buf, int *frame_length )
{
char *p = (char *)buf;
int parsed_count = 0;

PARSE_OR_RETURN(p, "Length=", *frame_length, int);

return parsed_count;
}

0 comments on commit 721fe20

Please sign in to comment.