Welcome to mirror list, hosted at ThFree Co, Russian Federation.

encoder_buffer.h « core « draco « src « draco « draco « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b153a629792fe37f00de8a03e63ad2491660d37c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2016 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_CORE_ENCODER_BUFFER_H_
#define DRACO_CORE_ENCODER_BUFFER_H_

#include <memory>
#include <vector>

#include "draco/core/bit_utils.h"
#include "draco/core/macros.h"

namespace draco {

// Class representing a buffer that can be used for either for byte-aligned
// encoding of arbitrary data structures or for encoding of variable-length
// bit data.
class EncoderBuffer {
 public:
  EncoderBuffer();
  void Clear();
  void Resize(int64_t nbytes);

  // Start encoding a bit sequence. A maximum size of the sequence needs to
  // be known upfront.
  // If encode_size is true, the size of encoded bit sequence is stored before
  // the sequence. Decoder can then use this size to skip over the bit sequence
  // if needed.
  // Returns false on error.
  bool StartBitEncoding(int64_t required_bits, bool encode_size);

  // End the encoding of the bit sequence and return to the default byte-aligned
  // encoding.
  void EndBitEncoding();

  // Encode up to 32 bits into the buffer. Can be called only in between
  // StartBitEncoding and EndBitEncoding. Otherwise returns false.
  bool EncodeLeastSignificantBits32(int nbits, uint32_t value) {
    if (!bit_encoder_active()) {
      return false;
    }
    bit_encoder_->PutBits(value, nbits);
    return true;
  }
  // Encode an arbitrary data type.
  // Can be used only when we are not encoding a bit-sequence.
  // Returns false when the value couldn't be encoded.
  template <typename T>
  bool Encode(const T &data) {
    if (bit_encoder_active()) {
      return false;
    }
    const uint8_t *src_data = reinterpret_cast<const uint8_t *>(&data);
    buffer_.insert(buffer_.end(), src_data, src_data + sizeof(T));
    return true;
  }
  bool Encode(const void *data, size_t data_size) {
    if (bit_encoder_active()) {
      return false;
    }
    const uint8_t *src_data = reinterpret_cast<const uint8_t *>(data);
    buffer_.insert(buffer_.end(), src_data, src_data + data_size);
    return true;
  }

  bool bit_encoder_active() const { return bit_encoder_reserved_bytes_ > 0; }
  const char *data() const { return buffer_.data(); }
  size_t size() const { return buffer_.size(); }
  std::vector<char> *buffer() { return &buffer_; }

 private:
  // Internal helper class to encode bits to a bit buffer.
  class BitEncoder {
   public:
    // |data| is the buffer to write the bits into.
    explicit BitEncoder(char *data) : bit_buffer_(data), bit_offset_(0) {}

    // Write |nbits| of |data| into the bit buffer.
    void PutBits(uint32_t data, int32_t nbits) {
      DRACO_DCHECK_GE(nbits, 0);
      DRACO_DCHECK_LE(nbits, 32);
      for (int32_t bit = 0; bit < nbits; ++bit) {
        PutBit((data >> bit) & 1);
      }
    }

    // Return number of bits encoded so far.
    uint64_t Bits() const { return static_cast<uint64_t>(bit_offset_); }

    // TODO(fgalligan): Remove this function once we know we do not need the
    // old API anymore.
    // This is a function of an old API, that currently does nothing.
    void Flush(int /* left_over_bit_value */) {}

    // Return the number of bits required to store the given number
    static uint32_t BitsRequired(uint32_t x) {
      return static_cast<uint32_t>(MostSignificantBit(x));
    }

   private:
    void PutBit(uint8_t value) {
      const int byte_size = 8;
      const uint64_t off = static_cast<uint64_t>(bit_offset_);
      const uint64_t byte_offset = off / byte_size;
      const int bit_shift = off % byte_size;

      // TODO(fgalligan): Check performance if we add a branch and only do one
      // memory write if bit_shift is 7. Also try using a temporary variable to
      // hold the bits before writing to the buffer.

      bit_buffer_[byte_offset] &= ~(1 << bit_shift);
      bit_buffer_[byte_offset] |= value << bit_shift;
      bit_offset_++;
    }

    char *bit_buffer_;
    size_t bit_offset_;
  };
  friend class BufferBitCodingTest;
  // All data is stored in this vector.
  std::vector<char> buffer_;

  // Bit encoder is used when encoding variable-length bit data.
  // TODO(ostava): Currently encoder needs to be recreated each time
  // StartBitEncoding method is called. This is not necessary if BitEncoder
  // supported reset function which can easily added but let's leave that for
  // later.
  std::unique_ptr<BitEncoder> bit_encoder_;

  // The number of bytes reserved for bit encoder.
  // Values > 0 indicate we are in the bit encoding mode.
  int64_t bit_encoder_reserved_bytes_;

  // Flag used indicating that we need to store the length of the currently
  // processed bit sequence.
  bool encode_bit_sequence_size_;
};

}  // namespace draco

#endif  // DRACO_CORE_ENCODER_BUFFER_H_