    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE RecordWildCards #-}

    module Network.HPACK.Table.Dynamic (
        DynamicTable (..),
        newDynamicTableForEncoding,
        newDynamicTableForDecoding,
        renewDynamicTable,
        huffmanDecoder,
        printDynamicTable,
        isDynamicTableEmpty,
        isSuitableSize,
        TableSizeAction (..),
        needChangeTableSize,
        setLimitForEncoding,
        resetLimitForEncoding,
        insertEntry,
        toDynamicEntry,
        CodeInfo (..),
        withDynamicTableForEncoding,
        withDynamicTableForDecoding,
        toIndexedEntry,
        fromHIndexToIndex,
        getRevIndex,
    ) where

    import Control.Exception (throwIO)
    import Data.Array.Base (unsafeRead, unsafeWrite)
    import Data.Array.IO (IOArray, newArray)
    import qualified Data.ByteString.Char8 as BS
    import Data.IORef

    import Imports
    import Network.HPACK.Huffman
    import Network.HPACK.Table.Entry
    import Network.HPACK.Table.RevIndex
    import Network.HPACK.Table.Static
    import Network.HPACK.Types

    ----------------------------------------------------------------

    -- For decoder
    {-# INLINE toIndexedEntry #-}
    toIndexedEntry :: DynamicTable -> Index -> IO Entry
    toIndexedEntry :: DynamicTable -> Size -> IO Entry
    toIndexedEntry DynamicTable
    dyntbl Size
    idx
        | Size
    idx Size -> Size -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Size
    0 = DecodeError -> IO Entry
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO (DecodeError -> IO Entry) -> DecodeError -> IO Entry
    forall a b. (a -> b) -> a -> b
    $ Size -> DecodeError
    IndexOverrun Size
    idx
        | Size
    idx Size -> Size -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Size
    staticTableSize = Entry -> IO Entry
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Entry -> IO Entry) -> Entry -> IO Entry
    forall a b. (a -> b) -> a -> b
    $ Size -> Entry
    toStaticEntry Size
    idx
        | Bool
    otherwise = DynamicTable -> Size -> IO Entry
    toDynamicEntry DynamicTable
    dyntbl Size
    idx

    -- For encoder
    {-# INLINE fromHIndexToIndex #-}
    fromHIndexToIndex :: DynamicTable -> HIndex -> IO Index
    fromHIndexToIndex :: DynamicTable -> HIndex -> IO Size
    fromHIndexToIndex DynamicTable
    _ (SIndex Size
    idx) = Size -> IO Size
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Size
    idx
    fromHIndexToIndex DynamicTable{IORef Size
    IORef Table
    CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    ..} (DIndex Size
    didx) = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        x <- adj maxN (didx - off)
        return $ x + staticTableSize

    ----------------------------------------------------------------

    type Table = IOArray Index Entry

    {-
            offset
            v
       +-+-+-+-+-+-+-+-+
       | | | |z|y|x| | |
       +-+-+-+-+-+-+-+-+
              1 2 3      (numOfEntries = 3)

    After insertion:

          offset
          v
       +-+-+-+-+-+-+-+-+
       | | |w|z|y|x| | |
       +-+-+-+-+-+-+-+-+
            1 2 3 4      (numOfEntries = 4)
    -}

    data CodeInfo = CIE EncodeInfo | CID DecodeInfo
    data EncodeInfo
        = EncodeInfo
            RevIndex -- Reverse index
            -- The value informed by SETTINGS_HEADER_TABLE_SIZE.
            -- If 'Nothing', dynamic table size update is not necessary.
            -- Otherwise, dynamic table size update is sent
            -- and this value should be set to 'Nothing'.
            (IORef (Maybe Size))
    data DecodeInfo
        = DecodeInfo
            HuffmanDecoder
            (IORef Size) -- The limit size

    toEncodeInfo :: CodeInfo -> EncodeInfo
    toEncodeInfo :: CodeInfo -> EncodeInfo
    toEncodeInfo (CIE EncodeInfo
    x) = EncodeInfo
    x
    toEncodeInfo CodeInfo
    _ = [Char] -> EncodeInfo
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "toEncodeInfo"

    toDecodeInfo :: CodeInfo -> DecodeInfo
    toDecodeInfo :: CodeInfo -> DecodeInfo
    toDecodeInfo (CID DecodeInfo
    x) = DecodeInfo
    x
    toDecodeInfo CodeInfo
    _ = [Char] -> DecodeInfo
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "toDecodeInfo"

    -- | Type for dynamic table.
    data DynamicTable = DynamicTable
        { DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
        , DynamicTable -> IORef Table
    circularTable :: IORef Table
        -- ^ An array
        , DynamicTable -> IORef Size
    offset :: IORef Index
        -- ^ Start point
        , DynamicTable -> IORef Size
    numOfEntries :: IORef Int
        -- ^ The current number of entries
        , DynamicTable -> IORef Size
    maxNumOfEntries :: IORef Int
        -- ^ The size of the array
        , DynamicTable -> IORef Size
    dynamicTableSize :: IORef Size
        -- ^ The current dynamic table size (defined in HPACK)
        , DynamicTable -> IORef Size
    maxDynamicTableSize :: IORef Size
        -- ^ The max dynamic table size (defined in HPACK)
        }

    {-# INLINE adj #-}
    adj :: Int -> Int -> IO Int
    adj :: Size -> Size -> IO Size
    adj Size
    maxN Size
    x
        | Size
    maxN Size -> Size -> Bool
    forall a. Eq a => a -> a -> Bool
    == Size
    0 = DecodeError -> IO Size
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO DecodeError
    TooSmallTableSize
        | Bool
    otherwise =
            let ret :: Size
    ret = (Size
    x Size -> Size -> Size
    forall a. Num a => a -> a -> a
    + Size
    maxN) Size -> Size -> Size
    forall a. Integral a => a -> a -> a
    `mod` Size
    maxN
             in Size -> IO Size
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Size
    ret

    huffmanDecoder :: DynamicTable -> HuffmanDecoder
    huffmanDecoder :: DynamicTable -> HuffmanDecoder
    huffmanDecoder DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = HuffmanDecoder
    dec
      where
        DecodeInfo HuffmanDecoder
    dec IORef Size
    _ = CodeInfo -> DecodeInfo
    toDecodeInfo CodeInfo
    codeInfo

    ----------------------------------------------------------------

    -- | Printing 'DynamicTable'.
    printDynamicTable :: DynamicTable -> IO ()
    printDynamicTable :: DynamicTable -> IO ()
    printDynamicTable DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        n <- readIORef numOfEntries
        let beg = Size
    off Size -> Size -> Size
    forall a. Num a => a -> a -> a
    + Size
    1
            end = Size
    off Size -> Size -> Size
    forall a. Num a => a -> a -> a
    + Size
    n
        tbl <- readIORef circularTable
        es <- mapM (adj maxN >=> unsafeRead tbl) [beg .. end]
        let ts = [Size] -> [Entry] -> [(Size, Entry)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Size
    1 ..] [Entry]
    es
        mapM_ printEntry ts
        dsize <- readIORef dynamicTableSize
        maxdsize <- readIORef maxDynamicTableSize
        putStrLn $ "      Table size: " ++ show dsize ++ "/" ++ show maxdsize

    printEntry :: (Index, Entry) -> IO ()
    printEntry :: (Size, Entry) -> IO ()
    printEntry (Size
    i, Entry
    e) = do
        [Char] -> IO ()
    putStr [Char]
    "[ "
        [Char] -> IO ()
    putStr ([Char] -> IO ()) -> [Char] -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Size -> [Char]
    forall a. Show a => a -> [Char]
    show Size
    i
        [Char] -> IO ()
    putStr [Char]
    "] (s = "
        [Char] -> IO ()
    putStr ([Char] -> IO ()) -> [Char] -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Size -> [Char]
    forall a. Show a => a -> [Char]
    show (Size -> [Char]) -> Size -> [Char]
    forall a b. (a -> b) -> a -> b
    $ Entry -> Size
    entrySize Entry
    e
        [Char] -> IO ()
    putStr [Char]
    ") "
        ByteString -> IO ()
    BS.putStr (ByteString -> IO ()) -> ByteString -> IO ()
    forall a b. (a -> b) -> a -> b
    $ CI ByteString -> ByteString
    forall s. CI s -> s
    original (CI ByteString -> ByteString) -> CI ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ Entry -> CI ByteString
    entryHeaderName Entry
    e
        [Char] -> IO ()
    putStr [Char]
    ": "
        ByteString -> IO ()
    BS.putStrLn (ByteString -> IO ()) -> ByteString -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Entry -> ByteString
    entryFieldValue Entry
    e

    ----------------------------------------------------------------

    isDynamicTableEmpty :: DynamicTable -> IO Bool
    isDynamicTableEmpty :: DynamicTable -> IO Bool
    isDynamicTableEmpty DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        n <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    numOfEntries
        return $ n == 0

    isSuitableSize :: Size -> DynamicTable -> IO Bool
    isSuitableSize :: Size -> DynamicTable -> IO Bool
    isSuitableSize Size
    siz DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        let DecodeInfo HuffmanDecoder
    _ IORef Size
    limref = CodeInfo -> DecodeInfo
    toDecodeInfo CodeInfo
    codeInfo
        lim <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    limref
        return $ siz <= lim

    data TableSizeAction = Keep | Change Size | Ignore Size

    needChangeTableSize :: DynamicTable -> IO TableSizeAction
    needChangeTableSize :: DynamicTable -> IO TableSizeAction
    needChangeTableSize DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        let EncodeInfo RevIndex
    _ IORef (Maybe Size)
    limref = CodeInfo -> EncodeInfo
    toEncodeInfo CodeInfo
    codeInfo
        mlim <- IORef (Maybe Size) -> IO (Maybe Size)
    forall a. IORef a -> IO a
    readIORef IORef (Maybe Size)
    limref
        maxsiz <- readIORef maxDynamicTableSize
        return $ case mlim of
            Maybe Size
    Nothing -> TableSizeAction
    Keep
            Just Size
    lim
                | Size
    lim Size -> Size -> Bool
    forall a. Ord a => a -> a -> Bool
    < Size
    maxsiz -> Size -> TableSizeAction
    Change Size
    lim
                | Bool
    otherwise -> Size -> TableSizeAction
    Ignore Size
    maxsiz

    -- | When SETTINGS_HEADER_TABLE_SIZE is received from a peer,
    --   its value should be set by this function.
    setLimitForEncoding :: Size -> DynamicTable -> IO ()
    setLimitForEncoding :: Size -> DynamicTable -> IO ()
    setLimitForEncoding Size
    siz DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        let EncodeInfo RevIndex
    _ IORef (Maybe Size)
    limref = CodeInfo -> EncodeInfo
    toEncodeInfo CodeInfo
    codeInfo
        IORef (Maybe Size) -> Maybe Size -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef (Maybe Size)
    limref (Maybe Size -> IO ()) -> Maybe Size -> IO ()
    forall a b. (a -> b) -> a -> b
    $ Size -> Maybe Size
    forall a. a -> Maybe a
    Just Size
    siz

    resetLimitForEncoding :: DynamicTable -> IO ()
    resetLimitForEncoding :: DynamicTable -> IO ()
    resetLimitForEncoding DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        let EncodeInfo RevIndex
    _ IORef (Maybe Size)
    limref = CodeInfo -> EncodeInfo
    toEncodeInfo CodeInfo
    codeInfo
        IORef (Maybe Size) -> Maybe Size -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef (Maybe Size)
    limref Maybe Size
    forall a. Maybe a
    Nothing

    ----------------------------------------------------------------

    -- | Creating 'DynamicTable' for encoding.
    newDynamicTableForEncoding
        :: Size
        -- ^ The dynamic table size
        -> IO DynamicTable
    newDynamicTableForEncoding :: Size -> IO DynamicTable
    newDynamicTableForEncoding Size
    maxsiz = do
        rev <- IO RevIndex
    newRevIndex
        lim <- newIORef Nothing
        let info = EncodeInfo -> CodeInfo
    CIE (EncodeInfo -> CodeInfo) -> EncodeInfo -> CodeInfo
    forall a b. (a -> b) -> a -> b
    $ RevIndex -> IORef (Maybe Size) -> EncodeInfo
    EncodeInfo RevIndex
    rev IORef (Maybe Size)
    lim
        newDynamicTable maxsiz info

    -- | Creating 'DynamicTable' for decoding.
    newDynamicTableForDecoding
        :: Size
        -- ^ The dynamic table size
        -> Size
        -- ^ The size of temporary buffer for Huffman decoding
        -> IO DynamicTable
    newDynamicTableForDecoding :: Size -> Size -> IO DynamicTable
    newDynamicTableForDecoding Size
    maxsiz Size
    huftmpsiz = do
        lim <- Size -> IO (IORef Size)
    forall a. a -> IO (IORef a)
    newIORef Size
    maxsiz
        buf <- mallocPlainForeignPtrBytes huftmpsiz
        let decoder = ForeignPtr Word8 -> Size -> HuffmanDecoder
    decodeH ForeignPtr Word8
    buf Size
    huftmpsiz
            info = DecodeInfo -> CodeInfo
    CID (DecodeInfo -> CodeInfo) -> DecodeInfo -> CodeInfo
    forall a b. (a -> b) -> a -> b
    $ HuffmanDecoder -> IORef Size -> DecodeInfo
    DecodeInfo HuffmanDecoder
    decoder IORef Size
    lim
        newDynamicTable maxsiz info

    newDynamicTable :: Size -> CodeInfo -> IO DynamicTable
    newDynamicTable :: Size -> CodeInfo -> IO DynamicTable
    newDynamicTable Size
    maxsiz CodeInfo
    info = do
        tbl <- (Size, Size) -> Entry -> IO Table
    forall i. Ix i => (i, i) -> Entry -> IO (IOArray i Entry)
    forall (a :: * -> * -> *) e (m :: * -> *) i.
    (MArray a e m, Ix i) =>
    (i, i) -> e -> m (a i e)
    newArray (Size
    0, Size
    end) Entry
    dummyEntry
        DynamicTable info
            <$> newIORef tbl -- circularTable
            <*> newIORef end -- offset
            <*> newIORef 0 -- numOfEntries
            <*> newIORef maxN -- maxNumOfEntries
            <*> newIORef 0 -- dynamicTableSize
            <*> newIORef maxsiz -- maxDynamicTableSize
      where
        maxN :: Size
    maxN = Size -> Size
    maxNumbers Size
    maxsiz
        end :: Size
    end = Size
    maxN Size -> Size -> Size
    forall a. Num a => a -> a -> a
    - Size
    1

    -- | Renewing 'DynamicTable' with necessary entries copied.
    renewDynamicTable :: Size -> DynamicTable -> IO ()
    renewDynamicTable :: Size -> DynamicTable -> IO ()
    renewDynamicTable Size
    maxsiz dyntbl :: DynamicTable
    dyntbl@DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        renew <- DynamicTable -> Size -> IO Bool
    shouldRenew DynamicTable
    dyntbl Size
    maxsiz
        when renew $ do
            entries <- getEntries dyntbl
            let maxN = Size -> Size
    maxNumbers Size
    maxsiz
                end = Size
    maxN Size -> Size -> Size
    forall a. Num a => a -> a -> a
    - Size
    1
            newtbl <- newArray (0, end) dummyEntry
            writeIORef circularTable newtbl
            writeIORef offset end
            writeIORef numOfEntries 0
            writeIORef maxNumOfEntries maxN
            writeIORef dynamicTableSize 0
            writeIORef maxDynamicTableSize maxsiz
            case codeInfo of
                CIE (EncodeInfo RevIndex
    rev IORef (Maybe Size)
    _) -> RevIndex -> IO ()
    renewRevIndex RevIndex
    rev
                CodeInfo
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            copyEntries dyntbl entries

    getEntries :: DynamicTable -> IO [Entry]
    getEntries :: DynamicTable -> IO [Entry]
    getEntries DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        n <- readIORef numOfEntries
        table <- readIORef circularTable
        let readTable Size
    i = Size -> Size -> IO Size
    adj Size
    maxN (Size
    off Size -> Size -> Size
    forall a. Num a => a -> a -> a
    + Size
    i) IO Size -> (Size -> IO Entry) -> IO Entry
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Table -> Size -> IO Entry
    forall i. Ix i => IOArray i Entry -> Size -> IO Entry
    forall (a :: * -> * -> *) e (m :: * -> *) i.
    (MArray a e m, Ix i) =>
    a i e -> Size -> m e
    unsafeRead Table
    table
        forM [1 .. n] readTable

    copyEntries :: DynamicTable -> [Entry] -> IO ()
    copyEntries :: DynamicTable -> [Entry] -> IO ()
    copyEntries DynamicTable
    _ [] = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    copyEntries dyntbl :: DynamicTable
    dyntbl@DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} (Entry
    e : [Entry]
    es) = do
        dsize <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    dynamicTableSize
        maxdsize <- readIORef maxDynamicTableSize
        when (dsize + entrySize e <= maxdsize) $ do
            insertEnd e dyntbl
            copyEntries dyntbl es

    -- | Is the size of 'DynamicTable' really changed?
    shouldRenew :: DynamicTable -> Size -> IO Bool
    shouldRenew :: DynamicTable -> Size -> IO Bool
    shouldRenew DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} Size
    maxsiz = do
        maxdsize <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxDynamicTableSize
        return $ maxdsize /= maxsiz

    ----------------------------------------------------------------

    -- | Creating 'DynamicTable' for encoding,
    --   performing the action and
    --   clearing the 'DynamicTable'.
    withDynamicTableForEncoding
        :: Size
        -- ^ The dynamic table size
        -> (DynamicTable -> IO a)
        -> IO a
    withDynamicTableForEncoding :: forall a. Size -> (DynamicTable -> IO a) -> IO a
    withDynamicTableForEncoding Size
    maxsiz DynamicTable -> IO a
    action =
        Size -> IO DynamicTable
    newDynamicTableForEncoding Size
    maxsiz IO DynamicTable -> (DynamicTable -> IO a) -> IO a
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= DynamicTable -> IO a
    action

    -- | Creating 'DynamicTable' for decoding,
    --   performing the action and
    --   clearing the 'DynamicTable'.
    withDynamicTableForDecoding
        :: Size
        -- ^ The dynamic table size
        -> Size
        -- ^ The size of temporary buffer for Huffman
        -> (DynamicTable -> IO a)
        -> IO a
    withDynamicTableForDecoding :: forall a. Size -> Size -> (DynamicTable -> IO a) -> IO a
    withDynamicTableForDecoding Size
    maxsiz Size
    huftmpsiz DynamicTable -> IO a
    action =
        Size -> Size -> IO DynamicTable
    newDynamicTableForDecoding Size
    maxsiz Size
    huftmpsiz IO DynamicTable -> (DynamicTable -> IO a) -> IO a
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= DynamicTable -> IO a
    action

    ----------------------------------------------------------------

    -- | Inserting 'Entry' to 'DynamicTable'.
    insertEntry :: Entry -> DynamicTable -> IO ()
    insertEntry :: Entry -> DynamicTable -> IO ()
    insertEntry Entry
    e dyntbl :: DynamicTable
    dyntbl@DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        -- Theoretically speaking, dropping entries by adjustTableSize
        -- should be first. However, non-used slots always exist since the
        -- size of dynamic table calculated via the minimum entry size (32
        -- bytes). To simply adjustTableSize, insertFront is called first.
        Entry -> DynamicTable -> IO ()
    insertFront Entry
    e DynamicTable
    dyntbl
        es <- DynamicTable -> IO [Entry]
    adjustTableSize DynamicTable
    dyntbl
        case codeInfo of
            CIE (EncodeInfo RevIndex
    rev IORef (Maybe Size)
    _) -> [Entry] -> RevIndex -> IO ()
    deleteRevIndexList [Entry]
    es RevIndex
    rev
            CodeInfo
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    insertFront :: Entry -> DynamicTable -> IO ()
    insertFront :: Entry -> DynamicTable -> IO ()
    insertFront Entry
    e DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        n <- readIORef numOfEntries
        dsize <- readIORef dynamicTableSize
        table <- readIORef circularTable
        let i = Size
    off
            dsize' = Size
    dsize Size -> Size -> Size
    forall a. Num a => a -> a -> a
    + Entry -> Size
    entrySize Entry
    e
        if maxN == 0
            then return ()
            else do
                off' <- adj maxN (off - 1)
                unsafeWrite table i e
                writeIORef offset off'
                writeIORef numOfEntries $ n + 1
                writeIORef dynamicTableSize dsize'
                case codeInfo of
                    CIE (EncodeInfo RevIndex
    rev IORef (Maybe Size)
    _) -> Entry -> HIndex -> RevIndex -> IO ()
    insertRevIndex Entry
    e (Size -> HIndex
    DIndex Size
    i) RevIndex
    rev
                    CodeInfo
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    adjustTableSize :: DynamicTable -> IO [Entry]
    adjustTableSize :: DynamicTable -> IO [Entry]
    adjustTableSize dyntbl :: DynamicTable
    dyntbl@DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = [Entry] -> IO [Entry]
    adjust []
      where
        adjust :: [Entry] -> IO [Entry]
        adjust :: [Entry] -> IO [Entry]
    adjust [Entry]
    es = do
            dsize <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    dynamicTableSize
            maxdsize <- readIORef maxDynamicTableSize
            if dsize <= maxdsize
                then return es
                else do
                    e <- removeEnd dyntbl
                    adjust (e : es)

    ----------------------------------------------------------------

    -- Used in copyEntries.
    insertEnd :: Entry -> DynamicTable -> IO ()
    insertEnd :: Entry -> DynamicTable -> IO ()
    insertEnd Entry
    e DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        n <- readIORef numOfEntries
        dsize <- readIORef dynamicTableSize
        table <- readIORef circularTable
        i <- adj maxN (off + n + 1)
        let dsize' = Size
    dsize Size -> Size -> Size
    forall a. Num a => a -> a -> a
    + Entry -> Size
    entrySize Entry
    e
        unsafeWrite table i e
        writeIORef numOfEntries $ n + 1
        writeIORef dynamicTableSize dsize'
        case codeInfo of
            CIE (EncodeInfo RevIndex
    rev IORef (Maybe Size)
    _) -> Entry -> HIndex -> RevIndex -> IO ()
    insertRevIndex Entry
    e (Size -> HIndex
    DIndex Size
    i) RevIndex
    rev
            CodeInfo
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    ----------------------------------------------------------------

    removeEnd :: DynamicTable -> IO Entry
    removeEnd :: DynamicTable -> IO Entry
    removeEnd DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        n <- readIORef numOfEntries
        i <- adj maxN (off + n)
        table <- readIORef circularTable
        e <- unsafeRead table i
        unsafeWrite table i dummyEntry -- let the entry GCed
        dsize <- readIORef dynamicTableSize
        let dsize' = Size
    dsize Size -> Size -> Size
    forall a. Num a => a -> a -> a
    - Entry -> Size
    entrySize Entry
    e
        writeIORef numOfEntries (n - 1)
        writeIORef dynamicTableSize dsize'
        return e

    ----------------------------------------------------------------

    {-# INLINE toDynamicEntry #-}
    toDynamicEntry :: DynamicTable -> Index -> IO Entry
    toDynamicEntry :: DynamicTable -> Size -> IO Entry
    toDynamicEntry DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} Size
    idx = do
        maxN <- IORef Size -> IO Size
    forall a. IORef a -> IO a
    readIORef IORef Size
    maxNumOfEntries
        off <- readIORef offset
        n <- readIORef numOfEntries
        when (idx > n + staticTableSize) $ throwIO $ IndexOverrun idx
        didx <- adj maxN (idx + off - staticTableSize)
        table <- readIORef circularTable
        unsafeRead table didx

    ----------------------------------------------------------------

    {-# INLINE getRevIndex #-}
    getRevIndex :: DynamicTable -> RevIndex
    getRevIndex :: DynamicTable -> RevIndex
    getRevIndex DynamicTable{IORef Size
    IORef Table
    CodeInfo
    maxDynamicTableSize :: DynamicTable -> IORef Size
    dynamicTableSize :: DynamicTable -> IORef Size
    maxNumOfEntries :: DynamicTable -> IORef Size
    numOfEntries :: DynamicTable -> IORef Size
    offset :: DynamicTable -> IORef Size
    circularTable :: DynamicTable -> IORef Table
    codeInfo :: DynamicTable -> CodeInfo
    codeInfo :: CodeInfo
    circularTable :: IORef Table
    offset :: IORef Size
    numOfEntries :: IORef Size
    maxNumOfEntries :: IORef Size
    dynamicTableSize :: IORef Size
    maxDynamicTableSize :: IORef Size
    ..} = RevIndex
    rev
      where
        EncodeInfo RevIndex
    rev IORef (Maybe Size)
    _ = CodeInfo -> EncodeInfo
    toEncodeInfo CodeInfo
    codeInfo