text: // 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 "core/bit_coder.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 varialble-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;
    }
  
   public:
    // 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_; }
    BitEncoder *bit_encoder() { return bit_encoder_.get(); }
  
   private:
    // 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_
  