Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: third_party/brotli/enc/ringbuffer.h

Issue 2537133002: Update brotli to v1.0.0-snapshot. (Closed)
Patch Set: Fixed typo Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/brotli/enc/quality.h ('k') | third_party/brotli/enc/static_dict.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* Copyright 2013 Google Inc. All Rights Reserved. 1 /* Copyright 2013 Google Inc. All Rights Reserved.
2 2
3 Distributed under MIT license. 3 Distributed under MIT license.
4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5 */ 5 */
6 6
7 // Sliding window over the input data. 7 /* Sliding window over the input data. */
8 8
9 #ifndef BROTLI_ENC_RINGBUFFER_H_ 9 #ifndef BROTLI_ENC_RINGBUFFER_H_
10 #define BROTLI_ENC_RINGBUFFER_H_ 10 #define BROTLI_ENC_RINGBUFFER_H_
11 11
12 #include <cstdlib> /* free, realloc */ 12 #include <string.h> /* memcpy */
13 13
14 #include <brotli/types.h>
15 #include "./memory.h"
14 #include "./port.h" 16 #include "./port.h"
15 #include "./types.h" 17 #include "./quality.h"
16 18
17 namespace brotli { 19 #if defined(__cplusplus) || defined(c_plusplus)
20 extern "C" {
21 #endif
18 22
19 // A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of 23 /* A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of
20 // data in a circular manner: writing a byte writes it to: 24 data in a circular manner: writing a byte writes it to:
21 // `position() % (1 << window_bits)'. 25 `position() % (1 << window_bits)'.
22 // For convenience, the RingBuffer array contains another copy of the 26 For convenience, the RingBuffer array contains another copy of the
23 // first `1 << tail_bits' bytes: 27 first `1 << tail_bits' bytes:
24 // buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits), 28 buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),
25 // and another copy of the last two bytes: 29 and another copy of the last two bytes:
26 // buffer_[-1] == buffer_[(1 << window_bits) - 1] and 30 buffer_[-1] == buffer_[(1 << window_bits) - 1] and
27 // buffer_[-2] == buffer_[(1 << window_bits) - 2]. 31 buffer_[-2] == buffer_[(1 << window_bits) - 2]. */
28 class RingBuffer { 32 typedef struct RingBuffer {
29 public: 33 /* Size of the ring-buffer is (1 << window_bits) + tail_size_. */
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_; 34 const uint32_t size_;
129 const uint32_t mask_; 35 const uint32_t mask_;
130 const uint32_t tail_size_; 36 const uint32_t tail_size_;
131 const uint32_t total_size_; 37 const uint32_t total_size_;
132 38
133 uint32_t cur_size_; 39 uint32_t cur_size_;
134 // Position to write in the ring buffer. 40 /* Position to write in the ring buffer. */
135 uint32_t pos_; 41 uint32_t pos_;
136 // The actual ring buffer containing the copy of the last two bytes, the data, 42 /* The actual ring buffer containing the copy of the last two bytes, the data,
137 // and the copy of the beginning as a tail. 43 and the copy of the beginning as a tail. */
138 uint8_t *data_; 44 uint8_t *data_;
139 // The start of the ringbuffer. 45 /* The start of the ring-buffer. */
140 uint8_t *buffer_; 46 uint8_t *buffer_;
141 }; 47 } RingBuffer;
142 48
143 } // namespace brotli 49 static BROTLI_INLINE void RingBufferInit(RingBuffer* rb) {
50 rb->cur_size_ = 0;
51 rb->pos_ = 0;
52 rb->data_ = 0;
53 rb->buffer_ = 0;
54 }
144 55
145 #endif // BROTLI_ENC_RINGBUFFER_H_ 56 static BROTLI_INLINE void RingBufferSetup(
57 const BrotliEncoderParams* params, RingBuffer* rb) {
58 int window_bits = ComputeRbBits(params);
59 int tail_bits = params->lgblock;
60 *(uint32_t*)&rb->size_ = 1u << window_bits;
61 *(uint32_t*)&rb->mask_ = (1u << window_bits) - 1;
62 *(uint32_t*)&rb->tail_size_ = 1u << tail_bits;
63 *(uint32_t*)&rb->total_size_ = rb->size_ + rb->tail_size_;
64 }
65
66 static BROTLI_INLINE void RingBufferFree(MemoryManager* m, RingBuffer* rb) {
67 BROTLI_FREE(m, rb->data_);
68 }
69
70 /* Allocates or re-allocates data_ to the given length + plus some slack
71 region before and after. Fills the slack regions with zeros. */
72 static BROTLI_INLINE void RingBufferInitBuffer(
73 MemoryManager* m, const uint32_t buflen, RingBuffer* rb) {
74 static const size_t kSlackForEightByteHashingEverywhere = 7;
75 uint8_t* new_data = BROTLI_ALLOC(
76 m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
77 size_t i;
78 if (BROTLI_IS_OOM(m)) return;
79 if (rb->data_) {
80 memcpy(new_data, rb->data_,
81 2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
82 BROTLI_FREE(m, rb->data_);
83 }
84 rb->data_ = new_data;
85 rb->cur_size_ = buflen;
86 rb->buffer_ = rb->data_ + 2;
87 rb->buffer_[-2] = rb->buffer_[-1] = 0;
88 for (i = 0; i < kSlackForEightByteHashingEverywhere; ++i) {
89 rb->buffer_[rb->cur_size_ + i] = 0;
90 }
91 }
92
93 static BROTLI_INLINE void RingBufferWriteTail(
94 const uint8_t *bytes, size_t n, RingBuffer* rb) {
95 const size_t masked_pos = rb->pos_ & rb->mask_;
96 if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) {
97 /* Just fill the tail buffer with the beginning data. */
98 const size_t p = rb->size_ + masked_pos;
99 memcpy(&rb->buffer_[p], bytes,
100 BROTLI_MIN(size_t, n, rb->tail_size_ - masked_pos));
101 }
102 }
103
104 /* Push bytes into the ring buffer. */
105 static BROTLI_INLINE void RingBufferWrite(
106 MemoryManager* m, const uint8_t *bytes, size_t n, RingBuffer* rb) {
107 if (rb->pos_ == 0 && n < rb->tail_size_) {
108 /* Special case for the first write: to process the first block, we don't
109 need to allocate the whole ring-buffer and we don't need the tail
110 either. However, we do this memory usage optimization only if the
111 first write is less than the tail size, which is also the input block
112 size, otherwise it is likely that other blocks will follow and we
113 will need to reallocate to the full size anyway. */
114 rb->pos_ = (uint32_t)n;
115 RingBufferInitBuffer(m, rb->pos_, rb);
116 if (BROTLI_IS_OOM(m)) return;
117 memcpy(rb->buffer_, bytes, n);
118 return;
119 }
120 if (rb->cur_size_ < rb->total_size_) {
121 /* Lazily allocate the full buffer. */
122 RingBufferInitBuffer(m, rb->total_size_, rb);
123 if (BROTLI_IS_OOM(m)) return;
124 /* Initialize the last two bytes to zero, so that we don't have to worry
125 later when we copy the last two bytes to the first two positions. */
126 rb->buffer_[rb->size_ - 2] = 0;
127 rb->buffer_[rb->size_ - 1] = 0;
128 }
129 {
130 const size_t masked_pos = rb->pos_ & rb->mask_;
131 /* The length of the writes is limited so that we do not need to worry
132 about a write */
133 RingBufferWriteTail(bytes, n, rb);
134 if (BROTLI_PREDICT_TRUE(masked_pos + n <= rb->size_)) {
135 /* A single write fits. */
136 memcpy(&rb->buffer_[masked_pos], bytes, n);
137 } else {
138 /* Split into two writes.
139 Copy into the end of the buffer, including the tail buffer. */
140 memcpy(&rb->buffer_[masked_pos], bytes,
141 BROTLI_MIN(size_t, n, rb->total_size_ - masked_pos));
142 /* Copy into the beginning of the buffer */
143 memcpy(&rb->buffer_[0], bytes + (rb->size_ - masked_pos),
144 n - (rb->size_ - masked_pos));
145 }
146 }
147 rb->buffer_[-2] = rb->buffer_[rb->size_ - 2];
148 rb->buffer_[-1] = rb->buffer_[rb->size_ - 1];
149 rb->pos_ += (uint32_t)n;
150 if (rb->pos_ > (1u << 30)) {
151 /* Wrap, but preserve not-a-first-lap feature. */
152 rb->pos_ = (rb->pos_ & ((1u << 30) - 1)) | (1u << 30);
153 }
154 }
155
156 #if defined(__cplusplus) || defined(c_plusplus)
157 } /* extern "C" */
158 #endif
159
160 #endif /* BROTLI_ENC_RINGBUFFER_H_ */
OLDNEW
« no previous file with comments | « third_party/brotli/enc/quality.h ('k') | third_party/brotli/enc/static_dict.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698