11cb0ef41Sopenharmony_ci/* Copyright 2013 Google Inc. All Rights Reserved. 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci Distributed under MIT license. 41cb0ef41Sopenharmony_ci See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 51cb0ef41Sopenharmony_ci*/ 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci/* Sliding window over the input data. */ 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#ifndef BROTLI_ENC_RINGBUFFER_H_ 101cb0ef41Sopenharmony_ci#define BROTLI_ENC_RINGBUFFER_H_ 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#include <string.h> /* memcpy */ 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci#include "../common/platform.h" 151cb0ef41Sopenharmony_ci#include <brotli/types.h> 161cb0ef41Sopenharmony_ci#include "./memory.h" 171cb0ef41Sopenharmony_ci#include "./quality.h" 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus) 201cb0ef41Sopenharmony_ciextern "C" { 211cb0ef41Sopenharmony_ci#endif 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci/* A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of 241cb0ef41Sopenharmony_ci data in a circular manner: writing a byte writes it to: 251cb0ef41Sopenharmony_ci `position() % (1 << window_bits)'. 261cb0ef41Sopenharmony_ci For convenience, the RingBuffer array contains another copy of the 271cb0ef41Sopenharmony_ci first `1 << tail_bits' bytes: 281cb0ef41Sopenharmony_ci buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits), 291cb0ef41Sopenharmony_ci and another copy of the last two bytes: 301cb0ef41Sopenharmony_ci buffer_[-1] == buffer_[(1 << window_bits) - 1] and 311cb0ef41Sopenharmony_ci buffer_[-2] == buffer_[(1 << window_bits) - 2]. */ 321cb0ef41Sopenharmony_citypedef struct RingBuffer { 331cb0ef41Sopenharmony_ci /* Size of the ring-buffer is (1 << window_bits) + tail_size_. */ 341cb0ef41Sopenharmony_ci const uint32_t size_; 351cb0ef41Sopenharmony_ci const uint32_t mask_; 361cb0ef41Sopenharmony_ci const uint32_t tail_size_; 371cb0ef41Sopenharmony_ci const uint32_t total_size_; 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci uint32_t cur_size_; 401cb0ef41Sopenharmony_ci /* Position to write in the ring buffer. */ 411cb0ef41Sopenharmony_ci uint32_t pos_; 421cb0ef41Sopenharmony_ci /* The actual ring buffer containing the copy of the last two bytes, the data, 431cb0ef41Sopenharmony_ci and the copy of the beginning as a tail. */ 441cb0ef41Sopenharmony_ci uint8_t* data_; 451cb0ef41Sopenharmony_ci /* The start of the ring-buffer. */ 461cb0ef41Sopenharmony_ci uint8_t* buffer_; 471cb0ef41Sopenharmony_ci} RingBuffer; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_cistatic BROTLI_INLINE void RingBufferInit(RingBuffer* rb) { 501cb0ef41Sopenharmony_ci rb->cur_size_ = 0; 511cb0ef41Sopenharmony_ci rb->pos_ = 0; 521cb0ef41Sopenharmony_ci rb->data_ = 0; 531cb0ef41Sopenharmony_ci rb->buffer_ = 0; 541cb0ef41Sopenharmony_ci} 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_cistatic BROTLI_INLINE void RingBufferSetup( 571cb0ef41Sopenharmony_ci const BrotliEncoderParams* params, RingBuffer* rb) { 581cb0ef41Sopenharmony_ci int window_bits = ComputeRbBits(params); 591cb0ef41Sopenharmony_ci int tail_bits = params->lgblock; 601cb0ef41Sopenharmony_ci *(uint32_t*)&rb->size_ = 1u << window_bits; 611cb0ef41Sopenharmony_ci *(uint32_t*)&rb->mask_ = (1u << window_bits) - 1; 621cb0ef41Sopenharmony_ci *(uint32_t*)&rb->tail_size_ = 1u << tail_bits; 631cb0ef41Sopenharmony_ci *(uint32_t*)&rb->total_size_ = rb->size_ + rb->tail_size_; 641cb0ef41Sopenharmony_ci} 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_cistatic BROTLI_INLINE void RingBufferFree(MemoryManager* m, RingBuffer* rb) { 671cb0ef41Sopenharmony_ci BROTLI_FREE(m, rb->data_); 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci/* Allocates or re-allocates data_ to the given length + plus some slack 711cb0ef41Sopenharmony_ci region before and after. Fills the slack regions with zeros. */ 721cb0ef41Sopenharmony_cistatic BROTLI_INLINE void RingBufferInitBuffer( 731cb0ef41Sopenharmony_ci MemoryManager* m, const uint32_t buflen, RingBuffer* rb) { 741cb0ef41Sopenharmony_ci static const size_t kSlackForEightByteHashingEverywhere = 7; 751cb0ef41Sopenharmony_ci uint8_t* new_data = BROTLI_ALLOC( 761cb0ef41Sopenharmony_ci m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere); 771cb0ef41Sopenharmony_ci size_t i; 781cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return; 791cb0ef41Sopenharmony_ci if (rb->data_) { 801cb0ef41Sopenharmony_ci memcpy(new_data, rb->data_, 811cb0ef41Sopenharmony_ci 2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere); 821cb0ef41Sopenharmony_ci BROTLI_FREE(m, rb->data_); 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci rb->data_ = new_data; 851cb0ef41Sopenharmony_ci rb->cur_size_ = buflen; 861cb0ef41Sopenharmony_ci rb->buffer_ = rb->data_ + 2; 871cb0ef41Sopenharmony_ci rb->buffer_[-2] = rb->buffer_[-1] = 0; 881cb0ef41Sopenharmony_ci for (i = 0; i < kSlackForEightByteHashingEverywhere; ++i) { 891cb0ef41Sopenharmony_ci rb->buffer_[rb->cur_size_ + i] = 0; 901cb0ef41Sopenharmony_ci } 911cb0ef41Sopenharmony_ci} 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_cistatic BROTLI_INLINE void RingBufferWriteTail( 941cb0ef41Sopenharmony_ci const uint8_t* bytes, size_t n, RingBuffer* rb) { 951cb0ef41Sopenharmony_ci const size_t masked_pos = rb->pos_ & rb->mask_; 961cb0ef41Sopenharmony_ci if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) { 971cb0ef41Sopenharmony_ci /* Just fill the tail buffer with the beginning data. */ 981cb0ef41Sopenharmony_ci const size_t p = rb->size_ + masked_pos; 991cb0ef41Sopenharmony_ci memcpy(&rb->buffer_[p], bytes, 1001cb0ef41Sopenharmony_ci BROTLI_MIN(size_t, n, rb->tail_size_ - masked_pos)); 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci} 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci/* Push bytes into the ring buffer. */ 1051cb0ef41Sopenharmony_cistatic BROTLI_INLINE void RingBufferWrite( 1061cb0ef41Sopenharmony_ci MemoryManager* m, const uint8_t* bytes, size_t n, RingBuffer* rb) { 1071cb0ef41Sopenharmony_ci if (rb->pos_ == 0 && n < rb->tail_size_) { 1081cb0ef41Sopenharmony_ci /* Special case for the first write: to process the first block, we don't 1091cb0ef41Sopenharmony_ci need to allocate the whole ring-buffer and we don't need the tail 1101cb0ef41Sopenharmony_ci either. However, we do this memory usage optimization only if the 1111cb0ef41Sopenharmony_ci first write is less than the tail size, which is also the input block 1121cb0ef41Sopenharmony_ci size, otherwise it is likely that other blocks will follow and we 1131cb0ef41Sopenharmony_ci will need to reallocate to the full size anyway. */ 1141cb0ef41Sopenharmony_ci rb->pos_ = (uint32_t)n; 1151cb0ef41Sopenharmony_ci RingBufferInitBuffer(m, rb->pos_, rb); 1161cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 1171cb0ef41Sopenharmony_ci memcpy(rb->buffer_, bytes, n); 1181cb0ef41Sopenharmony_ci return; 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci if (rb->cur_size_ < rb->total_size_) { 1211cb0ef41Sopenharmony_ci /* Lazily allocate the full buffer. */ 1221cb0ef41Sopenharmony_ci RingBufferInitBuffer(m, rb->total_size_, rb); 1231cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 1241cb0ef41Sopenharmony_ci /* Initialize the last two bytes to zero, so that we don't have to worry 1251cb0ef41Sopenharmony_ci later when we copy the last two bytes to the first two positions. */ 1261cb0ef41Sopenharmony_ci rb->buffer_[rb->size_ - 2] = 0; 1271cb0ef41Sopenharmony_ci rb->buffer_[rb->size_ - 1] = 0; 1281cb0ef41Sopenharmony_ci /* Initialize tail; might be touched by "best_len++" optimization when 1291cb0ef41Sopenharmony_ci ring buffer is "full". */ 1301cb0ef41Sopenharmony_ci rb->buffer_[rb->size_] = 241; 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci { 1331cb0ef41Sopenharmony_ci const size_t masked_pos = rb->pos_ & rb->mask_; 1341cb0ef41Sopenharmony_ci /* The length of the writes is limited so that we do not need to worry 1351cb0ef41Sopenharmony_ci about a write */ 1361cb0ef41Sopenharmony_ci RingBufferWriteTail(bytes, n, rb); 1371cb0ef41Sopenharmony_ci if (BROTLI_PREDICT_TRUE(masked_pos + n <= rb->size_)) { 1381cb0ef41Sopenharmony_ci /* A single write fits. */ 1391cb0ef41Sopenharmony_ci memcpy(&rb->buffer_[masked_pos], bytes, n); 1401cb0ef41Sopenharmony_ci } else { 1411cb0ef41Sopenharmony_ci /* Split into two writes. 1421cb0ef41Sopenharmony_ci Copy into the end of the buffer, including the tail buffer. */ 1431cb0ef41Sopenharmony_ci memcpy(&rb->buffer_[masked_pos], bytes, 1441cb0ef41Sopenharmony_ci BROTLI_MIN(size_t, n, rb->total_size_ - masked_pos)); 1451cb0ef41Sopenharmony_ci /* Copy into the beginning of the buffer */ 1461cb0ef41Sopenharmony_ci memcpy(&rb->buffer_[0], bytes + (rb->size_ - masked_pos), 1471cb0ef41Sopenharmony_ci n - (rb->size_ - masked_pos)); 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci { 1511cb0ef41Sopenharmony_ci BROTLI_BOOL not_first_lap = (rb->pos_ & (1u << 31)) != 0; 1521cb0ef41Sopenharmony_ci uint32_t rb_pos_mask = (1u << 31) - 1; 1531cb0ef41Sopenharmony_ci rb->buffer_[-2] = rb->buffer_[rb->size_ - 2]; 1541cb0ef41Sopenharmony_ci rb->buffer_[-1] = rb->buffer_[rb->size_ - 1]; 1551cb0ef41Sopenharmony_ci rb->pos_ = (rb->pos_ & rb_pos_mask) + (uint32_t)(n & rb_pos_mask); 1561cb0ef41Sopenharmony_ci if (not_first_lap) { 1571cb0ef41Sopenharmony_ci /* Wrap, but preserve not-a-first-lap feature. */ 1581cb0ef41Sopenharmony_ci rb->pos_ |= 1u << 31; 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus) 1641cb0ef41Sopenharmony_ci} /* extern "C" */ 1651cb0ef41Sopenharmony_ci#endif 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci#endif /* BROTLI_ENC_RINGBUFFER_H_ */ 168