Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
//////////////////////////////////////////////////////////////////////////////////// \file range_encoder.h/// \brief Range Encoder///// Authors: Igor Pavlov// Lasse Collin//// This file has been put into the public domain.// You can do whatever you want with this file./////////////////////////////////////////////////////////////////////////////////#ifndef LZMA_RANGE_ENCODER_H#define LZMA_RANGE_ENCODER_H#include "range_common.h"#include "price.h"/// Maximum number of symbols that can be put pending into lzma_range_encoder/// structure between calls to lzma_rc_encode(). For LZMA, 52+5 is enough/// (match with big distance and length followed by range encoder flush).#define RC_SYMBOLS_MAX 58typedef struct {uint64_t low;uint64_t cache_size;uint32_t range;uint8_t cache;/// Number of symbols in the tablessize_t count;/// rc_encode()'s position in the tablessize_t pos;/// Symbols to encodeenum {RC_BIT_0,RC_BIT_1,RC_DIRECT_0,RC_DIRECT_1,RC_FLUSH,} symbols[RC_SYMBOLS_MAX];/// Probabilities associated with RC_BIT_0 or RC_BIT_1probability *probs[RC_SYMBOLS_MAX];} lzma_range_encoder;static inline voidrc_reset(lzma_range_encoder *rc){rc->low = 0;rc->cache_size = 1;rc->range = UINT32_MAX;rc->cache = 0;rc->count = 0;rc->pos = 0;}static inline voidrc_bit(lzma_range_encoder *rc, probability *prob, uint32_t bit){rc->symbols[rc->count] = bit;rc->probs[rc->count] = prob;++rc->count;}static inline voidrc_bittree(lzma_range_encoder *rc, probability *probs,uint32_t bit_count, uint32_t symbol){uint32_t model_index = 1;do {const uint32_t bit = (symbol >> --bit_count) & 1;rc_bit(rc, &probs[model_index], bit);model_index = (model_index << 1) + bit;} while (bit_count != 0);}static inline voidrc_bittree_reverse(lzma_range_encoder *rc, probability *probs,uint32_t bit_count, uint32_t symbol){uint32_t model_index = 1;do {const uint32_t bit = symbol & 1;symbol >>= 1;rc_bit(rc, &probs[model_index], bit);model_index = (model_index << 1) + bit;} while (--bit_count != 0);}static inline voidrc_direct(lzma_range_encoder *rc,uint32_t value, uint32_t bit_count){do {rc->symbols[rc->count++]= RC_DIRECT_0 + ((value >> --bit_count) & 1);} while (bit_count != 0);}static inline voidrc_flush(lzma_range_encoder *rc){for (size_t i = 0; i < 5; ++i)rc->symbols[rc->count++] = RC_FLUSH;}static inline boolrc_shift_low(lzma_range_encoder *rc,uint8_t *out, size_t *out_pos, size_t out_size){if ((uint32_t)(rc->low) < (uint32_t)(0xFF000000)|| (uint32_t)(rc->low >> 32) != 0) {do {if (*out_pos == out_size)return true;out[*out_pos] = rc->cache + (uint8_t)(rc->low >> 32);++*out_pos;rc->cache = 0xFF;} while (--rc->cache_size != 0);rc->cache = (rc->low >> 24) & 0xFF;}++rc->cache_size;rc->low = (rc->low & 0x00FFFFFF) << RC_SHIFT_BITS;return false;}static inline boolrc_encode(lzma_range_encoder *rc,uint8_t *out, size_t *out_pos, size_t out_size){assert(rc->count <= RC_SYMBOLS_MAX);while (rc->pos < rc->count) {// Normalizeif (rc->range < RC_TOP_VALUE) {if (rc_shift_low(rc, out, out_pos, out_size))return true;rc->range <<= RC_SHIFT_BITS;}// Encode a bitswitch (rc->symbols[rc->pos]) {case RC_BIT_0: {probability prob = *rc->probs[rc->pos];rc->range = (rc->range >> RC_BIT_MODEL_TOTAL_BITS)* prob;prob += (RC_BIT_MODEL_TOTAL - prob) >> RC_MOVE_BITS;*rc->probs[rc->pos] = prob;break;}case RC_BIT_1: {probability prob = *rc->probs[rc->pos];const uint32_t bound = prob * (rc->range>> RC_BIT_MODEL_TOTAL_BITS);rc->low += bound;rc->range -= bound;prob -= prob >> RC_MOVE_BITS;*rc->probs[rc->pos] = prob;break;}case RC_DIRECT_0:rc->range >>= 1;break;case RC_DIRECT_1:rc->range >>= 1;rc->low += rc->range;break;case RC_FLUSH:// Prevent further normalizations.rc->range = UINT32_MAX;// Flush the last five bytes (see rc_flush()).do {if (rc_shift_low(rc, out, out_pos, out_size))return true;} while (++rc->pos < rc->count);// Reset the range encoder so we are ready to continue// encoding if we weren't finishing the stream.rc_reset(rc);return false;default:assert(0);break;}++rc->pos;}rc->count = 0;rc->pos = 0;return false;}static inline uint64_trc_pending(const lzma_range_encoder *rc){return rc->cache_size + 5 - 1;}#endif