module Codec.Compression.Zlib.HuffmanTree( HuffmanTree , AdvanceResult(..) , createHuffmanTree , advanceTree ) where import Data.Bits(testBit) import Data.Word(Word8) data HuffmanTree a = HuffmanNode (HuffmanTree a) (HuffmanTree a) | HuffmanValue a | HuffmanEmpty deriving (Show) data AdvanceResult a = AdvanceError String | NewTree (HuffmanTree a) | Result a emptyHuffmanTree :: HuffmanTree a emptyHuffmanTree = HuffmanEmpty createHuffmanTree :: Show a => [(a, Int, Int)] -> Either String (HuffmanTree a) createHuffmanTree = foldr addHuffmanNode' (Right emptyHuffmanTree) where addHuffmanNode' (a, b, c) acc = case acc of Left err -> Left err Right tree -> addHuffmanNode a b c tree addHuffmanNode :: Show a => a -> Int -> Int -> HuffmanTree a -> Either String (HuffmanTree a) addHuffmanNode val len code node = case node of HuffmanEmpty | len == 0 -> Right (HuffmanValue val) HuffmanEmpty -> case addHuffmanNode val (len - 1) code HuffmanEmpty of Left err -> Left err Right newNode | testBit code (len - 1) -> Right (HuffmanNode HuffmanEmpty newNode) | otherwise -> Right (HuffmanNode newNode HuffmanEmpty) -- HuffmanValue _ | len == 0 -> Left "Two values point to the same place!" HuffmanValue _ -> Left "HuffmanValue hit while inserting a value!" -- HuffmanNode _ _ | len == 0 -> Left ("Tried to add where the leaf is a node: " ++ show val) HuffmanNode l r | testBit code (len - 1) -> case addHuffmanNode val (len - 1) code r of Left err -> Left err Right r' -> Right (HuffmanNode l r') HuffmanNode l r -> case addHuffmanNode val (len - 1) code l of Left err -> Left err Right l' -> Right (HuffmanNode l' r) advanceTree :: Word8 -> HuffmanTree a -> AdvanceResult a advanceTree x node = case node of HuffmanEmpty -> AdvanceError "Tried to advance empty tree!" HuffmanValue _ -> AdvanceError "Tried to advance value!" HuffmanNode l r -> case if (x == 1) then r else l of HuffmanEmpty -> AdvanceError "Advanced to empty tree!" HuffmanValue y -> Result y t -> NewTree t {-# INLINE advanceTree #-}