xref: /third_party/node/deps/brotli/c/enc/ringbuffer.h (revision 1cb0ef41)
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