1
0
mirror of https://github.com/chylex/Brotli-Builder.git synced 2024-10-17 12:42:47 +02:00
Brotli-Builder/BrotliLib/Brotli/Dictionary/Format/BitDepthFormat.cs

61 lines
2.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace BrotliLib.Brotli.Dictionary.Format{
/// <summary>
/// Specifies a dictionary format defined by an array of values, where each index represents word length, and each value represents the amount of bits needed to count words of that length.
/// Given a bit depth of N, the local position of a word is encoded in the lower N bits, and any bits above (up to the integer boundary) represent the transformation index.
/// </summary>
public sealed class BitDepthFormat : IDictionaryFormat{
public IEnumerable<int> WordLengths => Enumerable.Range(minLength, maxLength - minLength + 1);
public int WordCount(int length) => length <= maxLength ? wordCounts[length] : 0;
private readonly int minLength, maxLength;
private readonly int[] wordLengthBits;
private readonly int[] wordCounts;
private readonly int[] wordMasks;
private readonly int[] wordOffsets;
public BitDepthFormat(int[] wordLengthBits){
this.minLength = Array.FindIndex(wordLengthBits, bits => bits > 0);
this.maxLength = Array.FindLastIndex(wordLengthBits, bits => bits > 0);
this.wordLengthBits = wordLengthBits;
this.wordCounts = Array.ConvertAll(wordLengthBits, bits => bits == 0 ? 0 : 1 << bits);
this.wordMasks = Array.ConvertAll(wordCounts, count => count - 1);
this.wordOffsets = new int[wordLengthBits.Length];
for(int length = 0; length < wordOffsets.Length - 1; length++){
wordOffsets[length + 1] = wordOffsets[length] + length * wordCounts[length];
}
}
public int UnpackWordIndex(int length, int packed){
CheckLengthBounds(length);
return packed & wordMasks[length];
}
public int UnpackTransformIndex(int length, int packed){
CheckLengthBounds(length);
return packed >> wordLengthBits[length];
}
public int GetWordPosition(int length, int word){
CheckLengthBounds(length);
return wordOffsets[length] + length * word;
}
public int GetPackedValue(int length, int word, int transform){
CheckLengthBounds(length);
return (transform << wordLengthBits[length]) | word;
}
private void CheckLengthBounds(int length){
if (length < minLength || length > maxLength){
throw new ArgumentOutOfRangeException(nameof(length), "Dictionary word length must be between " + minLength + " and " + maxLength + ".");
}
}
}
}