aboutsummaryrefslogtreecommitdiff
path: root/src/decoder/integer_sequence_codec.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/decoder/integer_sequence_codec.h')
-rw-r--r--src/decoder/integer_sequence_codec.h169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/decoder/integer_sequence_codec.h b/src/decoder/integer_sequence_codec.h
new file mode 100644
index 0000000..a815e09
--- /dev/null
+++ b/src/decoder/integer_sequence_codec.h
@@ -0,0 +1,169 @@
+// Copyright 2018 Google LLC
+//
+// 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
+//
+// https://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 ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_
+#define ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_
+
+#include "src/base/bit_stream.h"
+#include "src/base/uint128.h"
+
+#include <array>
+#include <string>
+#include <vector>
+
+namespace astc_codec {
+
+// The maximum number of bits that we would need to encode an ISE value. The
+// ASTC specification does not give a maximum number, however unquantized color
+// values have a maximum range of 255, meaning that we can't feasibly have more
+// than eight bits per value.
+constexpr int kLog2MaxRangeForBits = 8;
+
+// Ranges can take any of the the forms 2^k, 3*2^k, or 5*2^k for k up to
+// kLog2MaxRangeForBits. Hence we have three types of ranges. Since the
+// maximum encoded value is 255, k won't go larger than 8. We don't have quints
+// that accompany [6, 8]-bits, as (5 * 2^6 = 320 > 255) and we don't have trits
+// that accompany [7, 8]-bits, as (3 * 2^7 = 384 > 255). But we do have trits
+// and quints that accompany no bits. Hence we have a total of
+// 3 * kLog2MaxRangeForBits - 3 - 2 + 2 total ranges.
+constexpr int kNumPossibleRanges = 3 * kLog2MaxRangeForBits - 3;
+
+// Returns an iterator through the available ASTC ranges.
+std::array<int, kNumPossibleRanges>::const_iterator ISERangeBegin();
+std::array<int, kNumPossibleRanges>::const_iterator ISERangeEnd();
+
+// Base class for ASTC integer sequence encoders and decoders. These codecs
+// operate on sequences of integers and produce bit patterns that pack the
+// integers based on the encoding scheme specified in the ASTC specification
+// Section C.2.12. The resulting bit pattern is a sequence of encoded blocks.
+// All blocks in a sequence are one of the following encodings:
+//
+// (1 -- bit encoding) one encoded value of the form 2^k
+// (2 -- trit encoding) five encoded values of the form 3*2^k
+// (3 -- quint encoding) three encoded values of the form 5*2^k
+//
+// The layouts of each block are designed such that the blocks can be truncated
+// during encoding in order to support variable length input sequences (i.e. a
+// sequence of values that are encoded using trit encoded blocks does not
+// need to have a multiple-of-five length).
+class IntegerSequenceCodec {
+ public:
+ // Returns the number of trits, quints, and bits needed to encode values in
+ // [0, range]. This is used to determine the layout of ISE encoded bit
+ // streams. The returned array holds the number of trits, quints, and bits
+ // respectively. range is expected to be within the interval [1, 5242879]
+ static void GetCountsForRange(int range, int* trits, int* quints, int* bits);
+
+ // Returns the number of bits needed to encode the given number of values with
+ // respect to the number of trits, quints, and bits specified in ise_counts
+ // (in that order). It is expected that either trits or quints can be
+ // nonzero, but not both, and neither can be larger than one. Anything else is
+ // undefined.
+ static int GetBitCount(int num_vals, int trits, int quints, int bits);
+
+ // Convenience function that returns the number of bits needed to encoded
+ // num_vals within the range [0, range] (inclusive).
+ static inline int GetBitCountForRange(int num_vals, int range) {
+ int trits, quints, bits;
+ GetCountsForRange(range, &trits, &quints, &bits);
+ return GetBitCount(num_vals, trits, quints, bits);
+ }
+
+ protected:
+ explicit IntegerSequenceCodec(int range);
+ IntegerSequenceCodec(int trits, int quints, int bits);
+
+ // The encoding mode -- since having trits and quints are mutually exclusive,
+ // we can store the encoding we decide on in this enum.
+ enum EncodingMode {
+ kTritEncoding = 0,
+ kQuintEncoding,
+ kBitEncoding,
+ };
+
+ EncodingMode encoding_;
+ int bits_;
+
+ // Returns the number of values stored in a single ISE block. Since quints and
+ // trits are packed three/five to a bit pattern (respectively), each sequence
+ // is chunked into blocks in order to encode it. For only bit-encodings, the
+ // block size is one.
+ int NumValsPerBlock() const;
+
+ // Returns the size of a single ISE block in bits (see NumValsPerBlock).
+ int EncodedBlockSize() const;
+
+ private:
+ // Determines the encoding mode.
+ void InitializeWithCounts(int trits, int quints, int bits);
+};
+
+// The integer sequence decoder. The decoder only remembers the given encoding
+// but each invocation of Decode operates independently on the input bits.
+class IntegerSequenceDecoder : public IntegerSequenceCodec {
+ public:
+ // Creates a decoder that decodes values within [0, range] (inclusive).
+ explicit IntegerSequenceDecoder(int range)
+ : IntegerSequenceCodec(range) { }
+
+ // Creates a decoder based on the number of trits, quints, and bits expected
+ // in the bit stream passed to Decode.
+ IntegerSequenceDecoder(int trits, int quints, int bits)
+ : IntegerSequenceCodec(trits, quints, bits) { }
+
+ // Decodes num_vals from the bit_src. The number of bits read is dependent
+ // on the number of bits required to encode num_vals based on the calculation
+ // provided in Section C.2.22 of the ASTC specification. The return value
+ // always contains exactly num_vals.
+ std::vector<int> Decode(int num_vals,
+ base::BitStream<base::UInt128>* bit_src) const;
+};
+
+// The integer sequence encoder. The encoder accepts values one by one and
+// places them into a temporary array that it holds. When needed the user
+// may call Encode to produce an encoded bit stream of the associated values.
+class IntegerSequenceEncoder : public IntegerSequenceCodec {
+ public:
+ // Creates an encoder that encodes values within [0, range] (inclusive).
+ explicit IntegerSequenceEncoder(int range)
+ : IntegerSequenceCodec(range) { }
+
+ // Creates an encoder based on the number of trits, quints, and bits for
+ // the bit stream produced by Encode.
+ IntegerSequenceEncoder(int trits, int quints, int bits)
+ : IntegerSequenceCodec(trits, quints, bits) { }
+
+ // Adds a value to the encoding sequence.
+ void AddValue(int val) {
+ // Make sure it's within bounds
+ assert(encoding_ != EncodingMode::kTritEncoding || val < 3 * (1 << bits_));
+ assert(encoding_ != EncodingMode::kQuintEncoding || val < 5 * (1 << bits_));
+ assert(encoding_ != EncodingMode::kBitEncoding || val < (1 << bits_));
+ vals_.push_back(val);
+ }
+
+ // Writes the encoding for vals_ to the bit_sink. Multiple calls to Encode
+ // will produce the same result.
+ void Encode(base::BitStream<base::UInt128>* bit_sink) const;
+
+ // Removes all of the previously added values to the encoder.
+ void Reset() { vals_.clear(); }
+
+ private:
+ std::vector<int> vals_;
+};
+
+} // namespace astc_codec
+
+#endif // ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_