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