2011-03-17 00:05:44 +01:00
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package bzip2
|
|
|
|
|
|
|
|
// moveToFrontDecoder implements a move-to-front list. Such a list is an
|
|
|
|
// efficient way to transform a string with repeating elements into one with
|
|
|
|
// many small valued numbers, which is suitable for entropy encoding. It works
|
|
|
|
// by starting with an initial list of symbols and references symbols by their
|
|
|
|
// index into that list. When a symbol is referenced, it's moved to the front
|
|
|
|
// of the list. Thus, a repeated symbol ends up being encoded with many zeros,
|
|
|
|
// as the symbol will be at the front of the list after the first access.
|
2015-01-15 01:27:56 +01:00
|
|
|
type moveToFrontDecoder []byte
|
2011-03-17 00:05:44 +01:00
|
|
|
|
|
|
|
// newMTFDecoder creates a move-to-front decoder with an explicit initial list
|
|
|
|
// of symbols.
|
2015-01-15 01:27:56 +01:00
|
|
|
func newMTFDecoder(symbols []byte) moveToFrontDecoder {
|
2011-03-17 00:05:44 +01:00
|
|
|
if len(symbols) > 256 {
|
|
|
|
panic("too many symbols")
|
|
|
|
}
|
2015-01-15 01:27:56 +01:00
|
|
|
return moveToFrontDecoder(symbols)
|
2011-03-17 00:05:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// newMTFDecoderWithRange creates a move-to-front decoder with an initial
|
|
|
|
// symbol list of 0...n-1.
|
2015-01-15 01:27:56 +01:00
|
|
|
func newMTFDecoderWithRange(n int) moveToFrontDecoder {
|
2011-03-17 00:05:44 +01:00
|
|
|
if n > 256 {
|
|
|
|
panic("newMTFDecoderWithRange: cannot have > 256 symbols")
|
|
|
|
}
|
|
|
|
|
2015-01-15 01:27:56 +01:00
|
|
|
m := make([]byte, n)
|
2011-03-17 00:05:44 +01:00
|
|
|
for i := 0; i < n; i++ {
|
2015-01-15 01:27:56 +01:00
|
|
|
m[i] = byte(i)
|
2011-03-17 00:05:44 +01:00
|
|
|
}
|
2015-01-15 01:27:56 +01:00
|
|
|
return moveToFrontDecoder(m)
|
2011-03-17 00:05:44 +01:00
|
|
|
}
|
|
|
|
|
2015-01-15 01:27:56 +01:00
|
|
|
func (m moveToFrontDecoder) Decode(n int) (b byte) {
|
|
|
|
// Implement move-to-front with a simple copy. This approach
|
|
|
|
// beats more sophisticated approaches in benchmarking, probably
|
|
|
|
// because it has high locality of reference inside of a
|
|
|
|
// single cache line (most move-to-front operations have n < 64).
|
|
|
|
b = m[n]
|
|
|
|
copy(m[1:], m[:n])
|
|
|
|
m[0] = b
|
2011-03-17 00:05:44 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// First returns the symbol at the front of the list.
|
2015-01-15 01:27:56 +01:00
|
|
|
func (m moveToFrontDecoder) First() byte {
|
|
|
|
return m[0]
|
2011-03-17 00:05:44 +01:00
|
|
|
}
|