| OLD | NEW |
| (Empty) | |
| 1 /* Copyright 2013 Google Inc. All Rights Reserved. |
| 2 |
| 3 Distributed under MIT license. |
| 4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT |
| 5 */ |
| 6 |
| 7 // Sliding window over the input data. |
| 8 |
| 9 #ifndef BROTLI_ENC_RINGBUFFER_H_ |
| 10 #define BROTLI_ENC_RINGBUFFER_H_ |
| 11 |
| 12 #include <cstdlib> /* free, realloc */ |
| 13 |
| 14 #include "./port.h" |
| 15 #include "./types.h" |
| 16 |
| 17 namespace brotli { |
| 18 |
| 19 // A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of |
| 20 // data in a circular manner: writing a byte writes it to: |
| 21 // `position() % (1 << window_bits)'. |
| 22 // For convenience, the RingBuffer array contains another copy of the |
| 23 // first `1 << tail_bits' bytes: |
| 24 // buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits), |
| 25 // and another copy of the last two bytes: |
| 26 // buffer_[-1] == buffer_[(1 << window_bits) - 1] and |
| 27 // buffer_[-2] == buffer_[(1 << window_bits) - 2]. |
| 28 class RingBuffer { |
| 29 public: |
| 30 RingBuffer(int window_bits, int tail_bits) |
| 31 : size_(1u << window_bits), |
| 32 mask_((1u << window_bits) - 1), |
| 33 tail_size_(1u << tail_bits), |
| 34 total_size_(size_ + tail_size_), |
| 35 cur_size_(0), |
| 36 pos_(0), |
| 37 data_(0), |
| 38 buffer_(0) {} |
| 39 |
| 40 ~RingBuffer(void) { |
| 41 free(data_); |
| 42 } |
| 43 |
| 44 // Allocates or re-allocates data_ to the given length + plus some slack |
| 45 // region before and after. Fills the slack regions with zeros. |
| 46 inline void InitBuffer(const uint32_t buflen) { |
| 47 static const size_t kSlackForEightByteHashingEverywhere = 7; |
| 48 cur_size_ = buflen; |
| 49 data_ = static_cast<uint8_t*>(realloc( |
| 50 data_, 2 + buflen + kSlackForEightByteHashingEverywhere)); |
| 51 buffer_ = data_ + 2; |
| 52 buffer_[-2] = buffer_[-1] = 0; |
| 53 for (size_t i = 0; i < kSlackForEightByteHashingEverywhere; ++i) { |
| 54 buffer_[cur_size_ + i] = 0; |
| 55 } |
| 56 } |
| 57 |
| 58 // Push bytes into the ring buffer. |
| 59 void Write(const uint8_t *bytes, size_t n) { |
| 60 if (pos_ == 0 && n < tail_size_) { |
| 61 // Special case for the first write: to process the first block, we don't |
| 62 // need to allocate the whole ringbuffer and we don't need the tail |
| 63 // either. However, we do this memory usage optimization only if the |
| 64 // first write is less than the tail size, which is also the input block |
| 65 // size, otherwise it is likely that other blocks will follow and we |
| 66 // will need to reallocate to the full size anyway. |
| 67 pos_ = static_cast<uint32_t>(n); |
| 68 InitBuffer(pos_); |
| 69 memcpy(buffer_, bytes, n); |
| 70 return; |
| 71 } |
| 72 if (cur_size_ < total_size_) { |
| 73 // Lazily allocate the full buffer. |
| 74 InitBuffer(total_size_); |
| 75 // Initialize the last two bytes to zero, so that we don't have to worry |
| 76 // later when we copy the last two bytes to the first two positions. |
| 77 buffer_[size_ - 2] = 0; |
| 78 buffer_[size_ - 1] = 0; |
| 79 } |
| 80 const size_t masked_pos = pos_ & mask_; |
| 81 // The length of the writes is limited so that we do not need to worry |
| 82 // about a write |
| 83 WriteTail(bytes, n); |
| 84 if (PREDICT_TRUE(masked_pos + n <= size_)) { |
| 85 // A single write fits. |
| 86 memcpy(&buffer_[masked_pos], bytes, n); |
| 87 } else { |
| 88 // Split into two writes. |
| 89 // Copy into the end of the buffer, including the tail buffer. |
| 90 memcpy(&buffer_[masked_pos], bytes, |
| 91 std::min(n, total_size_ - masked_pos)); |
| 92 // Copy into the beginning of the buffer |
| 93 memcpy(&buffer_[0], bytes + (size_ - masked_pos), |
| 94 n - (size_ - masked_pos)); |
| 95 } |
| 96 buffer_[-2] = buffer_[size_ - 2]; |
| 97 buffer_[-1] = buffer_[size_ - 1]; |
| 98 pos_ += static_cast<uint32_t>(n); |
| 99 if (pos_ > (1u << 30)) { /* Wrap, but preserve not-a-first-lap feature. */ |
| 100 pos_ = (pos_ & ((1u << 30) - 1)) | (1u << 30); |
| 101 } |
| 102 } |
| 103 |
| 104 void Reset(void) { |
| 105 pos_ = 0; |
| 106 } |
| 107 |
| 108 // Logical cursor position in the ring buffer. |
| 109 uint32_t position(void) const { return pos_; } |
| 110 |
| 111 // Bit mask for getting the physical position for a logical position. |
| 112 uint32_t mask(void) const { return mask_; } |
| 113 |
| 114 uint8_t *start(void) { return &buffer_[0]; } |
| 115 const uint8_t *start(void) const { return &buffer_[0]; } |
| 116 |
| 117 private: |
| 118 void WriteTail(const uint8_t *bytes, size_t n) { |
| 119 const size_t masked_pos = pos_ & mask_; |
| 120 if (PREDICT_FALSE(masked_pos < tail_size_)) { |
| 121 // Just fill the tail buffer with the beginning data. |
| 122 const size_t p = size_ + masked_pos; |
| 123 memcpy(&buffer_[p], bytes, std::min(n, tail_size_ - masked_pos)); |
| 124 } |
| 125 } |
| 126 |
| 127 // Size of the ringbuffer is (1 << window_bits) + tail_size_. |
| 128 const uint32_t size_; |
| 129 const uint32_t mask_; |
| 130 const uint32_t tail_size_; |
| 131 const uint32_t total_size_; |
| 132 |
| 133 uint32_t cur_size_; |
| 134 // Position to write in the ring buffer. |
| 135 uint32_t pos_; |
| 136 // The actual ring buffer containing the copy of the last two bytes, the data, |
| 137 // and the copy of the beginning as a tail. |
| 138 uint8_t *data_; |
| 139 // The start of the ringbuffer. |
| 140 uint8_t *buffer_; |
| 141 }; |
| 142 |
| 143 } // namespace brotli |
| 144 |
| 145 #endif // BROTLI_ENC_RINGBUFFER_H_ |
| OLD | NEW |