summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2021-04-18 17:31:36 +0100
committerMichael Drake <tlsa@netsurf-browser.org>2021-04-18 17:31:36 +0100
commit0aeb0afe342d035ab32bac1d89b185f25d7acf32 (patch)
tree2ad5f8c900af9a7c9ff31397f79d614c3ad598c1
parent2cff6fc0dc2f57816a73a37501e017cd252457f8 (diff)
downloadlibnsgif-0aeb0afe342d035ab32bac1d89b185f25d7acf32.tar.gz
libnsgif-0aeb0afe342d035ab32bac1d89b185f25d7acf32.tar.bz2
lzw: Always read three bytes on fast path to avoid swtich.
-rw-r--r--src/lzw.c28
1 files changed, 13 insertions, 15 deletions
diff --git a/src/lzw.c b/src/lzw.c
index a3034f8..4b521b6 100644
--- a/src/lzw.c
+++ b/src/lzw.c
@@ -41,7 +41,7 @@ struct lzw_read_ctx {
uint32_t data_sb_next; /**< Offset to sub-block size */
const uint8_t *sb_data; /**< Pointer to current sub-block in data */
- uint32_t sb_bit; /**< Current bit offset in sub-block */
+ size_t sb_bit; /**< Current bit offset in sub-block */
uint32_t sb_bit_count; /**< Bit count in sub-block */
};
@@ -165,29 +165,25 @@ static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
*/
static inline lzw_result lzw__read_code(
struct lzw_read_ctx *restrict ctx,
- uint8_t code_size,
+ uint32_t code_size,
uint32_t *restrict code_out)
{
uint32_t code = 0;
- uint8_t current_bit = ctx->sb_bit & 0x7;
- uint8_t byte_advance = (current_bit + code_size) >> 3;
+ uint32_t current_bit = ctx->sb_bit & 0x7;
- assert(byte_advance <= 2);
-
- if (ctx->sb_bit + code_size <= ctx->sb_bit_count) {
- /* Fast path: code fully inside this sub-block */
+ if (ctx->sb_bit + 24 <= ctx->sb_bit_count) {
+ /* Fast path: read three bytes from this sub-block */
const uint8_t *data = ctx->sb_data + (ctx->sb_bit >> 3);
- switch (byte_advance) {
- case 2: code |= data[2] << 16; /* Fall through */
- case 1: code |= data[1] << 8; /* Fall through */
- case 0: code |= data[0] << 0;
- }
+ code |= *data++ << 0;
+ code |= *data++ << 8;
+ code |= *data << 16;
ctx->sb_bit += code_size;
} else {
/* Slow path: code spans sub-blocks */
+ uint8_t byte_advance = (current_bit + code_size) >> 3;
uint8_t byte = 0;
- uint8_t bits_remaining_0 = (code_size < (8 - current_bit)) ?
- code_size : (8 - current_bit);
+ uint8_t bits_remaining_0 = (code_size < (8u - current_bit)) ?
+ code_size : (8u - current_bit);
uint8_t bits_remaining_1 = code_size - bits_remaining_0;
uint8_t bits_used[3] = {
[0] = bits_remaining_0,
@@ -195,6 +191,8 @@ static inline lzw_result lzw__read_code(
[2] = bits_remaining_1 - 8,
};
+ assert(byte_advance <= 2);
+
while (true) {
const uint8_t *data = ctx->sb_data;
lzw_result res;