| // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/tools/huffman_trie/trie/trie_bit_buffer.h" |
| |
| #include "base/logging.h" |
| #include "net/tools/huffman_trie/bit_writer.h" |
| |
| namespace net { |
| |
| namespace huffman_trie { |
| |
| TrieBitBuffer::TrieBitBuffer() = default; |
| |
| TrieBitBuffer::~TrieBitBuffer() = default; |
| |
| void TrieBitBuffer::WriteBit(uint8_t bit) { |
| current_byte_ |= bit << (7 - used_); |
| used_++; |
| |
| if (used_ == 8) { |
| Flush(); |
| } |
| } |
| |
| void TrieBitBuffer::WriteBits(uint32_t bits, uint8_t number_of_bits) { |
| DCHECK(number_of_bits <= 32); |
| for (uint8_t i = 1; i <= number_of_bits; i++) { |
| uint8_t bit = 1 & (bits >> (number_of_bits - i)); |
| WriteBit(bit); |
| } |
| } |
| |
| void TrieBitBuffer::WritePosition(uint32_t position, int32_t* last_position) { |
| if (*last_position != -1) { |
| int32_t delta = position - *last_position; |
| DCHECK(delta > 0) << "delta position is not positive."; |
| |
| uint8_t number_of_bits = BitLength(delta); |
| DCHECK(number_of_bits <= 7 + 15) << "positive position delta too large."; |
| |
| if (number_of_bits <= 7) { |
| WriteBits(0, 1); |
| WriteBits(delta, 7); |
| } else { |
| WriteBits(1, 1); |
| WriteBits(number_of_bits - 8, 4); |
| WriteBits(delta, number_of_bits); |
| } |
| |
| *last_position = position; |
| return; |
| } |
| |
| if (used_ != 0) { |
| Flush(); |
| } |
| |
| AppendPositionElement(position); |
| |
| *last_position = position; |
| } |
| |
| uint8_t TrieBitBuffer::BitLength(uint32_t input) const { |
| uint8_t number_of_bits = 0; |
| while (input != 0) { |
| number_of_bits++; |
| input >>= 1; |
| } |
| return number_of_bits; |
| } |
| |
| void TrieBitBuffer::WriteChar(uint8_t byte, |
| const HuffmanRepresentationTable& table, |
| HuffmanBuilder* huffman_builder) { |
| HuffmanRepresentationTable::const_iterator item; |
| item = table.find(byte); |
| DCHECK(item != table.end()); |
| if (huffman_builder) { |
| huffman_builder->RecordUsage(byte); |
| } |
| WriteBits(item->second.bits, item->second.number_of_bits); |
| } |
| |
| void TrieBitBuffer::AppendBitsElement(uint8_t bits, uint8_t number_of_bits) { |
| BitsOrPosition element; |
| element.bits = current_byte_; |
| element.number_of_bits = used_; |
| elements_.push_back(element); |
| } |
| |
| void TrieBitBuffer::AppendPositionElement(uint32_t position) { |
| BitsOrPosition element; |
| element.position = position; |
| element.number_of_bits = 0; |
| elements_.push_back(element); |
| } |
| |
| uint32_t TrieBitBuffer::WriteToBitWriter(BitWriter* writer) { |
| Flush(); |
| |
| uint32_t old_position = writer->position(); |
| for (auto const& element : elements_) { |
| if (element.number_of_bits) { |
| writer->WriteBits(element.bits >> (8 - element.number_of_bits), |
| element.number_of_bits); |
| } else { |
| uint32_t current = old_position; |
| uint32_t target = element.position; |
| DCHECK(target < current) << "Reference is not backwards"; |
| uint32_t delta = current - target; |
| uint8_t delta_number_of_bits = BitLength(delta); |
| DCHECK(delta_number_of_bits < 32) << "Delta to large"; |
| writer->WriteBits(delta_number_of_bits, 5); |
| writer->WriteBits(delta, delta_number_of_bits); |
| } |
| } |
| return old_position; |
| } |
| |
| void TrieBitBuffer::Flush() { |
| if (used_) { |
| AppendBitsElement(current_byte_, used_); |
| |
| used_ = 0; |
| current_byte_ = 0; |
| } |
| } |
| |
| } // namespace huffman_trie |
| |
| } // namespace net |