126fa459cSmrg/* Copyright 2013 Google Inc. All Rights Reserved. 226fa459cSmrg 326fa459cSmrg Distributed under MIT license. 426fa459cSmrg See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 526fa459cSmrg*/ 626fa459cSmrg 726fa459cSmrg/* Sliding window over the input data. */ 826fa459cSmrg 926fa459cSmrg#ifndef BROTLI_ENC_RINGBUFFER_H_ 1026fa459cSmrg#define BROTLI_ENC_RINGBUFFER_H_ 1126fa459cSmrg 1226fa459cSmrg#include <string.h> /* memcpy */ 1326fa459cSmrg 1426fa459cSmrg#include "../common/platform.h" 1526fa459cSmrg#include <brotli/types.h> 1626fa459cSmrg#include "./memory.h" 1726fa459cSmrg#include "./quality.h" 1826fa459cSmrg 1926fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus) 2026fa459cSmrgextern "C" { 2126fa459cSmrg#endif 2226fa459cSmrg 2326fa459cSmrg/* A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of 2426fa459cSmrg data in a circular manner: writing a byte writes it to: 2526fa459cSmrg `position() % (1 << window_bits)'. 2626fa459cSmrg For convenience, the RingBuffer array contains another copy of the 2726fa459cSmrg first `1 << tail_bits' bytes: 2826fa459cSmrg buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits), 2926fa459cSmrg and another copy of the last two bytes: 3026fa459cSmrg buffer_[-1] == buffer_[(1 << window_bits) - 1] and 3126fa459cSmrg buffer_[-2] == buffer_[(1 << window_bits) - 2]. */ 3226fa459cSmrgtypedef struct RingBuffer { 3326fa459cSmrg /* Size of the ring-buffer is (1 << window_bits) + tail_size_. */ 3426fa459cSmrg const uint32_t size_; 3526fa459cSmrg const uint32_t mask_; 3626fa459cSmrg const uint32_t tail_size_; 3726fa459cSmrg const uint32_t total_size_; 3826fa459cSmrg 3926fa459cSmrg uint32_t cur_size_; 4026fa459cSmrg /* Position to write in the ring buffer. */ 4126fa459cSmrg uint32_t pos_; 4226fa459cSmrg /* The actual ring buffer containing the copy of the last two bytes, the data, 4326fa459cSmrg and the copy of the beginning as a tail. */ 4426fa459cSmrg uint8_t* data_; 4526fa459cSmrg /* The start of the ring-buffer. */ 4626fa459cSmrg uint8_t* buffer_; 4726fa459cSmrg} RingBuffer; 4826fa459cSmrg 4926fa459cSmrgstatic BROTLI_INLINE void RingBufferInit(RingBuffer* rb) { 5026fa459cSmrg rb->cur_size_ = 0; 5126fa459cSmrg rb->pos_ = 0; 5226fa459cSmrg rb->data_ = 0; 5326fa459cSmrg rb->buffer_ = 0; 5426fa459cSmrg} 5526fa459cSmrg 5626fa459cSmrgstatic BROTLI_INLINE void RingBufferSetup( 5726fa459cSmrg const BrotliEncoderParams* params, RingBuffer* rb) { 5826fa459cSmrg int window_bits = ComputeRbBits(params); 5926fa459cSmrg int tail_bits = params->lgblock; 6026fa459cSmrg *(uint32_t*)&rb->size_ = 1u << window_bits; 6126fa459cSmrg *(uint32_t*)&rb->mask_ = (1u << window_bits) - 1; 6226fa459cSmrg *(uint32_t*)&rb->tail_size_ = 1u << tail_bits; 6326fa459cSmrg *(uint32_t*)&rb->total_size_ = rb->size_ + rb->tail_size_; 6426fa459cSmrg} 6526fa459cSmrg 6626fa459cSmrgstatic BROTLI_INLINE void RingBufferFree(MemoryManager* m, RingBuffer* rb) { 6726fa459cSmrg BROTLI_FREE(m, rb->data_); 6826fa459cSmrg} 6926fa459cSmrg 7026fa459cSmrg/* Allocates or re-allocates data_ to the given length + plus some slack 7126fa459cSmrg region before and after. Fills the slack regions with zeros. */ 7226fa459cSmrgstatic BROTLI_INLINE void RingBufferInitBuffer( 7326fa459cSmrg MemoryManager* m, const uint32_t buflen, RingBuffer* rb) { 7426fa459cSmrg static const size_t kSlackForEightByteHashingEverywhere = 7; 7526fa459cSmrg uint8_t* new_data = BROTLI_ALLOC( 7626fa459cSmrg m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere); 7726fa459cSmrg size_t i; 7826fa459cSmrg if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return; 7926fa459cSmrg if (rb->data_) { 8026fa459cSmrg memcpy(new_data, rb->data_, 8126fa459cSmrg 2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere); 8226fa459cSmrg BROTLI_FREE(m, rb->data_); 8326fa459cSmrg } 8426fa459cSmrg rb->data_ = new_data; 8526fa459cSmrg rb->cur_size_ = buflen; 8626fa459cSmrg rb->buffer_ = rb->data_ + 2; 8726fa459cSmrg rb->buffer_[-2] = rb->buffer_[-1] = 0; 8826fa459cSmrg for (i = 0; i < kSlackForEightByteHashingEverywhere; ++i) { 8926fa459cSmrg rb->buffer_[rb->cur_size_ + i] = 0; 9026fa459cSmrg } 9126fa459cSmrg} 9226fa459cSmrg 9326fa459cSmrgstatic BROTLI_INLINE void RingBufferWriteTail( 9426fa459cSmrg const uint8_t* bytes, size_t n, RingBuffer* rb) { 9526fa459cSmrg const size_t masked_pos = rb->pos_ & rb->mask_; 9626fa459cSmrg if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) { 9726fa459cSmrg /* Just fill the tail buffer with the beginning data. */ 9826fa459cSmrg const size_t p = rb->size_ + masked_pos; 9926fa459cSmrg memcpy(&rb->buffer_[p], bytes, 10026fa459cSmrg BROTLI_MIN(size_t, n, rb->tail_size_ - masked_pos)); 10126fa459cSmrg } 10226fa459cSmrg} 10326fa459cSmrg 10426fa459cSmrg/* Push bytes into the ring buffer. */ 10526fa459cSmrgstatic BROTLI_INLINE void RingBufferWrite( 10626fa459cSmrg MemoryManager* m, const uint8_t* bytes, size_t n, RingBuffer* rb) { 10726fa459cSmrg if (rb->pos_ == 0 && n < rb->tail_size_) { 10826fa459cSmrg /* Special case for the first write: to process the first block, we don't 10926fa459cSmrg need to allocate the whole ring-buffer and we don't need the tail 11026fa459cSmrg either. However, we do this memory usage optimization only if the 11126fa459cSmrg first write is less than the tail size, which is also the input block 11226fa459cSmrg size, otherwise it is likely that other blocks will follow and we 11326fa459cSmrg will need to reallocate to the full size anyway. */ 11426fa459cSmrg rb->pos_ = (uint32_t)n; 11526fa459cSmrg RingBufferInitBuffer(m, rb->pos_, rb); 11626fa459cSmrg if (BROTLI_IS_OOM(m)) return; 11726fa459cSmrg memcpy(rb->buffer_, bytes, n); 11826fa459cSmrg return; 11926fa459cSmrg } 12026fa459cSmrg if (rb->cur_size_ < rb->total_size_) { 12126fa459cSmrg /* Lazily allocate the full buffer. */ 12226fa459cSmrg RingBufferInitBuffer(m, rb->total_size_, rb); 12326fa459cSmrg if (BROTLI_IS_OOM(m)) return; 12426fa459cSmrg /* Initialize the last two bytes to zero, so that we don't have to worry 12526fa459cSmrg later when we copy the last two bytes to the first two positions. */ 12626fa459cSmrg rb->buffer_[rb->size_ - 2] = 0; 12726fa459cSmrg rb->buffer_[rb->size_ - 1] = 0; 12826fa459cSmrg /* Initialize tail; might be touched by "best_len++" optimization when 12926fa459cSmrg ring buffer is "full". */ 13026fa459cSmrg rb->buffer_[rb->size_] = 241; 13126fa459cSmrg } 13226fa459cSmrg { 13326fa459cSmrg const size_t masked_pos = rb->pos_ & rb->mask_; 13426fa459cSmrg /* The length of the writes is limited so that we do not need to worry 13526fa459cSmrg about a write */ 13626fa459cSmrg RingBufferWriteTail(bytes, n, rb); 13726fa459cSmrg if (BROTLI_PREDICT_TRUE(masked_pos + n <= rb->size_)) { 13826fa459cSmrg /* A single write fits. */ 13926fa459cSmrg memcpy(&rb->buffer_[masked_pos], bytes, n); 14026fa459cSmrg } else { 14126fa459cSmrg /* Split into two writes. 14226fa459cSmrg Copy into the end of the buffer, including the tail buffer. */ 14326fa459cSmrg memcpy(&rb->buffer_[masked_pos], bytes, 14426fa459cSmrg BROTLI_MIN(size_t, n, rb->total_size_ - masked_pos)); 14526fa459cSmrg /* Copy into the beginning of the buffer */ 14626fa459cSmrg memcpy(&rb->buffer_[0], bytes + (rb->size_ - masked_pos), 14726fa459cSmrg n - (rb->size_ - masked_pos)); 14826fa459cSmrg } 14926fa459cSmrg } 15026fa459cSmrg { 15126fa459cSmrg BROTLI_BOOL not_first_lap = (rb->pos_ & (1u << 31)) != 0; 15226fa459cSmrg uint32_t rb_pos_mask = (1u << 31) - 1; 15326fa459cSmrg rb->buffer_[-2] = rb->buffer_[rb->size_ - 2]; 15426fa459cSmrg rb->buffer_[-1] = rb->buffer_[rb->size_ - 1]; 15526fa459cSmrg rb->pos_ = (rb->pos_ & rb_pos_mask) + (uint32_t)(n & rb_pos_mask); 15626fa459cSmrg if (not_first_lap) { 15726fa459cSmrg /* Wrap, but preserve not-a-first-lap feature. */ 15826fa459cSmrg rb->pos_ |= 1u << 31; 15926fa459cSmrg } 16026fa459cSmrg } 16126fa459cSmrg} 16226fa459cSmrg 16326fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus) 16426fa459cSmrg} /* extern "C" */ 16526fa459cSmrg#endif 16626fa459cSmrg 16726fa459cSmrg#endif /* BROTLI_ENC_RINGBUFFER_H_ */ 168