mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
44 lines
1.4 KiB
Swift
44 lines
1.4 KiB
Swift
// Copyright (c) 2026 Timofey Solomko
|
|
// Licensed under MIT License
|
|
//
|
|
// See LICENSE for license information
|
|
|
|
import Foundation
|
|
|
|
struct Code {
|
|
|
|
/// Number of bits used for `code`.
|
|
let bits: Int
|
|
let code: Int
|
|
let symbol: Int
|
|
|
|
/// `lengths` don't have to be sorted, but there must not be any 0 code lengths.
|
|
static func huffmanCodes(from lengths: [CodeLength]) -> (codes: [Code], maxBits: Int) {
|
|
// Sort `lengths` array to calculate canonical Huffman code.
|
|
let sortedLengths = lengths.sorted()
|
|
|
|
// Calculate maximum amount of leaves possible in a tree.
|
|
let maxBits = sortedLengths.last!.codeLength
|
|
var codes = [Code]()
|
|
codes.reserveCapacity(sortedLengths.count)
|
|
|
|
var loopBits = -1
|
|
var symbol = -1
|
|
for length in sortedLengths {
|
|
precondition(length.codeLength > 0, "Code length must not be 0 during HuffmanTree construction.")
|
|
symbol += 1
|
|
// We sometimes need to make symbol to have length.bits bit length.
|
|
let bits = length.codeLength
|
|
if bits != loopBits {
|
|
symbol <<= (bits - loopBits)
|
|
loopBits = bits
|
|
}
|
|
// Then we need to reverse bit order of the symbol.
|
|
let code = symbol.reversed(bits: loopBits)
|
|
codes.append(Code(bits: length.codeLength, code: code, symbol: length.symbol))
|
|
}
|
|
return (codes, maxBits)
|
|
}
|
|
|
|
}
|