106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
// 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.
|
|
type moveToFrontDecoder struct {
|
|
// Rather than actually keep the list in memory, the symbols are stored
|
|
// as a circular, double linked list with the symbol indexed by head
|
|
// at the front of the list.
|
|
symbols []byte
|
|
next []uint8
|
|
prev []uint8
|
|
head uint8
|
|
}
|
|
|
|
// newMTFDecoder creates a move-to-front decoder with an explicit initial list
|
|
// of symbols.
|
|
func newMTFDecoder(symbols []byte) *moveToFrontDecoder {
|
|
if len(symbols) > 256 {
|
|
panic("too many symbols")
|
|
}
|
|
|
|
m := &moveToFrontDecoder{
|
|
symbols: symbols,
|
|
next: make([]uint8, len(symbols)),
|
|
prev: make([]uint8, len(symbols)),
|
|
}
|
|
|
|
m.threadLinkedList()
|
|
return m
|
|
}
|
|
|
|
// newMTFDecoderWithRange creates a move-to-front decoder with an initial
|
|
// symbol list of 0...n-1.
|
|
func newMTFDecoderWithRange(n int) *moveToFrontDecoder {
|
|
if n > 256 {
|
|
panic("newMTFDecoderWithRange: cannot have > 256 symbols")
|
|
}
|
|
|
|
m := &moveToFrontDecoder{
|
|
symbols: make([]uint8, n),
|
|
next: make([]uint8, n),
|
|
prev: make([]uint8, n),
|
|
}
|
|
|
|
for i := 0; i < n; i++ {
|
|
m.symbols[i] = byte(i)
|
|
}
|
|
|
|
m.threadLinkedList()
|
|
return m
|
|
}
|
|
|
|
// threadLinkedList creates the initial linked-list pointers.
|
|
func (m *moveToFrontDecoder) threadLinkedList() {
|
|
if len(m.symbols) == 0 {
|
|
return
|
|
}
|
|
|
|
m.prev[0] = uint8(len(m.symbols) - 1)
|
|
|
|
for i := 0; i < len(m.symbols)-1; i++ {
|
|
m.next[i] = uint8(i + 1)
|
|
m.prev[i+1] = uint8(i)
|
|
}
|
|
|
|
m.next[len(m.symbols)-1] = 0
|
|
}
|
|
|
|
func (m *moveToFrontDecoder) Decode(n int) (b byte) {
|
|
// Most of the time, n will be zero so it's worth dealing with this
|
|
// simple case.
|
|
if n == 0 {
|
|
return m.symbols[m.head]
|
|
}
|
|
|
|
i := m.head
|
|
for j := 0; j < n; j++ {
|
|
i = m.next[i]
|
|
}
|
|
b = m.symbols[i]
|
|
|
|
m.next[m.prev[i]] = m.next[i]
|
|
m.prev[m.next[i]] = m.prev[i]
|
|
m.next[i] = m.head
|
|
m.prev[i] = m.prev[m.head]
|
|
m.next[m.prev[m.head]] = i
|
|
m.prev[m.head] = i
|
|
m.head = i
|
|
|
|
return
|
|
}
|
|
|
|
// First returns the symbol at the front of the list.
|
|
func (m *moveToFrontDecoder) First() byte {
|
|
return m.symbols[m.head]
|
|
}
|