1 // Copyright 2016 The Draco Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 #ifndef DRACO_CORE_ENCODER_BUFFER_H_ 16 #define DRACO_CORE_ENCODER_BUFFER_H_ 17 18 #include <memory> 19 #include <vector> 20 21 #include "draco/core/bit_utils.h" 22 #include "draco/core/macros.h" 23 24 namespace draco { 25 26 // Class representing a buffer that can be used for either for byte-aligned 27 // encoding of arbitrary data structures or for encoding of variable-length 28 // bit data. 29 class EncoderBuffer { 30 public: 31 EncoderBuffer(); 32 void Clear(); 33 void Resize(int64_t nbytes); 34 35 // Start encoding a bit sequence. A maximum size of the sequence needs to 36 // be known upfront. 37 // If encode_size is true, the size of encoded bit sequence is stored before 38 // the sequence. Decoder can then use this size to skip over the bit sequence 39 // if needed. 40 // Returns false on error. 41 bool StartBitEncoding(int64_t required_bits, bool encode_size); 42 43 // End the encoding of the bit sequence and return to the default byte-aligned 44 // encoding. 45 void EndBitEncoding(); 46 47 // Encode up to 32 bits into the buffer. Can be called only in between 48 // StartBitEncoding and EndBitEncoding. Otherwise returns false. EncodeLeastSignificantBits32(int nbits,uint32_t value)49 bool EncodeLeastSignificantBits32(int nbits, uint32_t value) { 50 if (!bit_encoder_active()) { 51 return false; 52 } 53 bit_encoder_->PutBits(value, nbits); 54 return true; 55 } 56 // Encode an arbitrary data type. 57 // Can be used only when we are not encoding a bit-sequence. 58 // Returns false when the value couldn't be encoded. 59 template <typename T> Encode(const T & data)60 bool Encode(const T &data) { 61 if (bit_encoder_active()) { 62 return false; 63 } 64 const uint8_t *src_data = reinterpret_cast<const uint8_t *>(&data); 65 buffer_.insert(buffer_.end(), src_data, src_data + sizeof(T)); 66 return true; 67 } Encode(const void * data,size_t data_size)68 bool Encode(const void *data, size_t data_size) { 69 if (bit_encoder_active()) { 70 return false; 71 } 72 const uint8_t *src_data = reinterpret_cast<const uint8_t *>(data); 73 buffer_.insert(buffer_.end(), src_data, src_data + data_size); 74 return true; 75 } 76 bit_encoder_active()77 bool bit_encoder_active() const { return bit_encoder_reserved_bytes_ > 0; } data()78 const char *data() const { return buffer_.data(); } size()79 size_t size() const { return buffer_.size(); } buffer()80 std::vector<char> *buffer() { return &buffer_; } 81 82 private: 83 // Internal helper class to encode bits to a bit buffer. 84 class BitEncoder { 85 public: 86 // |data| is the buffer to write the bits into. BitEncoder(char * data)87 explicit BitEncoder(char *data) : bit_buffer_(data), bit_offset_(0) {} 88 89 // Write |nbits| of |data| into the bit buffer. PutBits(uint32_t data,int32_t nbits)90 void PutBits(uint32_t data, int32_t nbits) { 91 DRACO_DCHECK_GE(nbits, 0); 92 DRACO_DCHECK_LE(nbits, 32); 93 for (int32_t bit = 0; bit < nbits; ++bit) { 94 PutBit((data >> bit) & 1); 95 } 96 } 97 98 // Return number of bits encoded so far. Bits()99 uint64_t Bits() const { return static_cast<uint64_t>(bit_offset_); } 100 101 // TODO(fgalligan): Remove this function once we know we do not need the 102 // old API anymore. 103 // This is a function of an old API, that currently does nothing. Flush(int)104 void Flush(int /* left_over_bit_value */) {} 105 106 // Return the number of bits required to store the given number BitsRequired(uint32_t x)107 static uint32_t BitsRequired(uint32_t x) { 108 return static_cast<uint32_t>(MostSignificantBit(x)); 109 } 110 111 private: PutBit(uint8_t value)112 void PutBit(uint8_t value) { 113 const int byte_size = 8; 114 const uint64_t off = static_cast<uint64_t>(bit_offset_); 115 const uint64_t byte_offset = off / byte_size; 116 const int bit_shift = off % byte_size; 117 118 // TODO(fgalligan): Check performance if we add a branch and only do one 119 // memory write if bit_shift is 7. Also try using a temporary variable to 120 // hold the bits before writing to the buffer. 121 122 bit_buffer_[byte_offset] &= ~(1 << bit_shift); 123 bit_buffer_[byte_offset] |= value << bit_shift; 124 bit_offset_++; 125 } 126 127 char *bit_buffer_; 128 size_t bit_offset_; 129 }; 130 friend class BufferBitCodingTest; 131 // All data is stored in this vector. 132 std::vector<char> buffer_; 133 134 // Bit encoder is used when encoding variable-length bit data. 135 // TODO(ostava): Currently encoder needs to be recreated each time 136 // StartBitEncoding method is called. This is not necessary if BitEncoder 137 // supported reset function which can easily added but let's leave that for 138 // later. 139 std::unique_ptr<BitEncoder> bit_encoder_; 140 141 // The number of bytes reserved for bit encoder. 142 // Values > 0 indicate we are in the bit encoding mode. 143 int64_t bit_encoder_reserved_bytes_; 144 145 // Flag used indicating that we need to store the length of the currently 146 // processed bit sequence. 147 bool encode_bit_sequence_size_; 148 }; 149 150 } // namespace draco 151 152 #endif // DRACO_CORE_ENCODER_BUFFER_H_ 153