Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
2.8 KiB
107 lines
2.8 KiB
// Copyright 2015, Joe Tsai. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE.md file. |
|
|
|
// Package internal is a collection of common compression algorithms. |
|
// |
|
// For performance reasons, these packages lack strong error checking and |
|
// require that the caller to ensure that strict invariants are kept. |
|
package internal |
|
|
|
var ( |
|
// IdentityLUT returns the input key itself. |
|
IdentityLUT = func() (lut [256]byte) { |
|
for i := range lut { |
|
lut[i] = uint8(i) |
|
} |
|
return lut |
|
}() |
|
|
|
// ReverseLUT returns the input key with its bits reversed. |
|
ReverseLUT = func() (lut [256]byte) { |
|
for i := range lut { |
|
b := uint8(i) |
|
b = (b&0xaa)>>1 | (b&0x55)<<1 |
|
b = (b&0xcc)>>2 | (b&0x33)<<2 |
|
b = (b&0xf0)>>4 | (b&0x0f)<<4 |
|
lut[i] = b |
|
} |
|
return lut |
|
}() |
|
) |
|
|
|
// ReverseUint32 reverses all bits of v. |
|
func ReverseUint32(v uint32) (x uint32) { |
|
x |= uint32(ReverseLUT[byte(v>>0)]) << 24 |
|
x |= uint32(ReverseLUT[byte(v>>8)]) << 16 |
|
x |= uint32(ReverseLUT[byte(v>>16)]) << 8 |
|
x |= uint32(ReverseLUT[byte(v>>24)]) << 0 |
|
return x |
|
} |
|
|
|
// ReverseUint32N reverses the lower n bits of v. |
|
func ReverseUint32N(v uint32, n uint) (x uint32) { |
|
return ReverseUint32(v << (32 - n)) |
|
} |
|
|
|
// ReverseUint64 reverses all bits of v. |
|
func ReverseUint64(v uint64) (x uint64) { |
|
x |= uint64(ReverseLUT[byte(v>>0)]) << 56 |
|
x |= uint64(ReverseLUT[byte(v>>8)]) << 48 |
|
x |= uint64(ReverseLUT[byte(v>>16)]) << 40 |
|
x |= uint64(ReverseLUT[byte(v>>24)]) << 32 |
|
x |= uint64(ReverseLUT[byte(v>>32)]) << 24 |
|
x |= uint64(ReverseLUT[byte(v>>40)]) << 16 |
|
x |= uint64(ReverseLUT[byte(v>>48)]) << 8 |
|
x |= uint64(ReverseLUT[byte(v>>56)]) << 0 |
|
return x |
|
} |
|
|
|
// ReverseUint64N reverses the lower n bits of v. |
|
func ReverseUint64N(v uint64, n uint) (x uint64) { |
|
return ReverseUint64(v << (64 - n)) |
|
} |
|
|
|
// MoveToFront is a data structure that allows for more efficient move-to-front |
|
// transformations. This specific implementation assumes that the alphabet is |
|
// densely packed within 0..255. |
|
type MoveToFront struct { |
|
dict [256]uint8 // Mapping from indexes to values |
|
tail int // Number of tail bytes that are already ordered |
|
} |
|
|
|
func (m *MoveToFront) Encode(vals []uint8) { |
|
copy(m.dict[:], IdentityLUT[:256-m.tail]) // Reset dict to be identity |
|
|
|
var max int |
|
for i, val := range vals { |
|
var idx uint8 // Reverse lookup idx in dict |
|
for di, dv := range m.dict { |
|
if dv == val { |
|
idx = uint8(di) |
|
break |
|
} |
|
} |
|
vals[i] = idx |
|
|
|
max |= int(idx) |
|
copy(m.dict[1:], m.dict[:idx]) |
|
m.dict[0] = val |
|
} |
|
m.tail = 256 - max - 1 |
|
} |
|
|
|
func (m *MoveToFront) Decode(idxs []uint8) { |
|
copy(m.dict[:], IdentityLUT[:256-m.tail]) // Reset dict to be identity |
|
|
|
var max int |
|
for i, idx := range idxs { |
|
val := m.dict[idx] // Forward lookup val in dict |
|
idxs[i] = val |
|
|
|
max |= int(idx) |
|
copy(m.dict[1:], m.dict[:idx]) |
|
m.dict[0] = val |
|
} |
|
m.tail = 256 - max - 1 |
|
}
|
|
|