winamp/Src/external_dependencies/openmpt-trunk/include/ancient/src/HuffmanDecoder.hpp

229 lines
4.3 KiB
C++

/* Copyright (C) Teemu Suutari */
#ifndef HUFFMANDECODER_HPP
#define HUFFMANDECODER_HPP
#include <cstddef>
#include <cstdint>
#include <vector>
#include <utility>
// For exception
#include "Decompressor.hpp"
#include "common/MemoryBuffer.hpp"
namespace ancient::internal
{
template<typename T>
struct HuffmanCode
{
uint32_t length;
uint32_t code;
T value;
};
template<typename T> class OptionalHuffmanDecoder;
template<typename T>
class HuffmanDecoder
{
friend class OptionalHuffmanDecoder<T>;
private:
struct Node
{
uint32_t sub[2];
T value;
Node(uint32_t _sub0,uint32_t _sub1,T _value) :
sub{_sub0,_sub1},
value(_value)
{
// nothing needed
}
Node(Node &&source) :
sub{source.sub[0],source.sub[1]},
value(source.value)
{
// nothing needed
}
Node& operator=(Node &&source)
{
if (this!=&source)
{
sub[0]=source.sub[0];
sub[1]=source.sub[1];
value=source.value;
}
return *this;
}
};
public:
HuffmanDecoder()
{
// nothing needed
}
template<typename ...Args>
HuffmanDecoder(const Args&& ...args) :
HuffmanDecoder()
{
const HuffmanCode<T> list[sizeof...(args)]={args...};
for (auto &item : list)
insert(item);
}
~HuffmanDecoder()
{
}
void reset()
{
_table.clear();
}
template<typename F>
const T &decode(F bitReader) const
{
if (!_table.size()) throw Decompressor::DecompressionError();
uint32_t i=0;
while (_table[i].sub[0] || _table[i].sub[1])
{
i=_table[i].sub[bitReader()?1:0];
if (!i) throw Decompressor::DecompressionError();
}
return _table[i].value;
}
void insert(const HuffmanCode<T> &code)
{
uint32_t i=0,length=uint32_t(_table.size());
for (int32_t currentBit=code.length;currentBit>=0;currentBit--)
{
uint32_t codeBit=(currentBit && ((code.code>>(currentBit-1U))&1U))?1U:0;
if (i!=length)
{
if (!currentBit || (!_table[i].sub[0] && !_table[i].sub[1])) throw Decompressor::DecompressionError();
uint32_t &tmp=_table[i].sub[codeBit];
if (!tmp) tmp=i=length;
else i=tmp;
} else {
_table.emplace_back((currentBit&&!codeBit)?length+1:0,(currentBit&&codeBit)?length+1:0,currentBit?T():code.value);
length++;
i++;
}
}
}
// create orderly Huffman table, as used by Deflate and Bzip2
void createOrderlyHuffmanTable(const uint8_t *bitLengths,uint32_t bitTableLength)
{
uint8_t minDepth=32,maxDepth=0;
// some optimization: more tables
uint16_t firstIndex[33],lastIndex[33];
MemoryBuffer nextIndexBuffer(bitTableLength*sizeof(uint16_t));
uint16_t *nextIndex=nextIndexBuffer.cast<uint16_t>();
for (uint32_t i=1;i<33;i++)
firstIndex[i]=0xffffU;
uint32_t realItems=0;
for (uint32_t i=0;i<bitTableLength;i++)
{
uint8_t length=bitLengths[i];
if (length>32) throw Decompressor::DecompressionError();
if (length)
{
if (length<minDepth) minDepth=length;
if (length>maxDepth) maxDepth=length;
if (firstIndex[length]==0xffffU)
{
firstIndex[length]=i;
lastIndex[length]=i;
} else {
nextIndex[lastIndex[length]]=i;
lastIndex[length]=i;
}
realItems++;
}
}
if (!maxDepth) throw Decompressor::DecompressionError();
// optimization, the multiple depends how sparse the tree really is. (minimum is *2)
// usually it is sparse.
_table.reserve(realItems*3);
uint32_t code=0;
for (uint32_t depth=minDepth;depth<=maxDepth;depth++)
{
if (firstIndex[depth]!=0xffffU)
nextIndex[lastIndex[depth]]=bitTableLength;
for (uint32_t i=firstIndex[depth];i<bitTableLength;i=nextIndex[i])
{
insert(HuffmanCode<T>{depth,code>>(maxDepth-depth),(T)i});
code+=1<<(maxDepth-depth);
}
}
}
private:
std::vector<Node> _table;
};
template<typename T>
class OptionalHuffmanDecoder
{
public:
OptionalHuffmanDecoder() :
_base()
{
// nothing needed
}
~OptionalHuffmanDecoder()
{
// nothing needed
}
void reset()
{
_base.reset();
}
void setEmpty(T value)
{
reset();
_emptyValue=value;
}
template<typename F>
T decode(F bitReader) const
{
if (!_base._table.size()) return _emptyValue;
else return _base.decode(bitReader);
}
void insert(const HuffmanCode<T> &code)
{
_base.insert(code);
}
void createOrderlyHuffmanTable(const uint8_t *bitLengths,uint32_t bitTableLength)
{
_base.createOrderlyHuffmanTable(bitLengths,bitTableLength);
}
private:
HuffmanDecoder<T> _base;
T _emptyValue=0;
};
}
#endif