{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE Strict #-}
-- |
-- Module : Data.MTF
-- Copyright : (c) Matthew Mosior 2022
-- License : BSD-style
-- Maintainer : mattm.github@gmail.com
-- Portability : portable
--
-- = Move-to-front transform (MTF)
--
-- Most users will get the most mileage by first compressing using a 'BWT'
-- on the initial 'ByteString' or 'Text' input before compressing to
-- a 'MTFB' or 'MTFT'.
--
-- To do this, users can use the 'bytestringToBWTToMTFB' and 'bytestringToBWTToMTFT' functions,
-- as well as the 'textToBWTToMTFB' and 'textToBWTToMTFT' functions.
--
-- The base functions for 'ByteString', 'bytestringToMTFB', 'bytestringToMTFT' can be used to
-- convert a 'Seq' ('Maybe' 'ByteString') to a 'MTFB' and 'MTFT', respectively.
--
-- Likewise, the base functions for 'Text', 'textToMTFB' and 'textToMTFT' can be used to
-- convert a 'Seq' ('Maybe' 'Text') to a 'MTFB' and 'MTFT' respectively.
--
-- There are various other lower-level functions for interacting with the MTF implementation on 'ByteString' and 'Text' as well.
--
-- @"Data.MTF.Internal"@ contains low-level, efficient, and stateful implementations of the MTF and Inverse MTF algorithms.
module Data.MTF ( -- * To MTF functions
bytestringToBWTToMTFB,
bytestringToBWTToMTFT,
textToBWTToMTFB,
textToBWTToMTFT,
textBWTToMTFB,
bytestringBWTToMTFB,
textBWTToMTFT,
bytestringBWTToMTFT,
textToMTFB,
bytestringToMTFB,
textToMTFT,
bytestringToMTFT,
-- * From MTF functions
bytestringFromBWTFromMTFB,
bytestringFromBWTFromMTFT,
textFromBWTFromMTFB,
textFromBWTFromMTFT,
textBWTFromMTFT,
bytestringBWTFromMTFT,
textBWTFromMTFB,
bytestringBWTFromMTFB,
textFromMTFB,
bytestringFromMTFB,
textFromMTFT,
bytestringFromMTFT
) where
import Data.BWT
import Data.BWT.Internal
import Data.MTF.Internal
import Control.Monad()
import Control.Monad.ST as CMST
import Control.Monad.State.Strict()
import Data.ByteString as BS
import Data.ByteString.Char8()
import Data.Char()
import Data.Foldable()
import Data.Maybe as DMaybe (isNothing,fromJust)
import Data.Sequence as DS (Seq(..))
import Data.STRef()
import Data.Text as DText
import Data.Text.Encoding as DTE (decodeUtf8,encodeUtf8)
import Data.Word (Word8)
import Prelude as P
{-toMTF Function(s)-}
-- | Helper function for converting a 'ByteString'
-- to a 'MTFB' via a 'BWT' first.
bytestringToBWTToMTFB :: ByteString ->
MTFB
bytestringToBWTToMTFB = bytestringBWTToMTFB . bytestringToBWT
-- | Helper function for converting a 'ByteString'
-- to a 'MTFT' via a 'BWT' first.
bytestringToBWTToMTFT :: ByteString ->
MTFT
bytestringToBWTToMTFT = bytestringBWTToMTFT . bytestringToBWT
-- | Helper function for converting a 'Text'
-- to a 'MTFB' via a 'BWT' first.
textToBWTToMTFB :: Text ->
MTFB
textToBWTToMTFB = textBWTToMTFB . textToBWT
-- | Helper function for converting a 'Text'
-- to a 'MTFT' via a 'BWT' first.
textToBWTToMTFT :: Text ->
MTFT
textToBWTToMTFT = textBWTToMTFT . textToBWT
-- | Take a 'BWT' of 'Word8's and generate the
-- Move-to-front transform ('MTFB').
textBWTToMTFB :: TextBWT
-> MTFB
textBWTToMTFB xs =
MTFB (CMST.runST $ seqToMTFB xss)
where
xss = fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
BS.singleton $
fromJust x
)
((\(BWT t) -> t) $
((\(TextBWT t) -> t) xs))
-- | Take a 'BWT' of 'Word8's and generate the
-- Move-to-front transform ('MTFB').
bytestringBWTToMTFB :: BWT Word8
-> MTFB
bytestringBWTToMTFB xs =
MTFB (CMST.runST $ seqToMTFB xss)
where
xss = fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
BS.singleton $
fromJust x
)
((\(BWT t) -> t) xs)
-- | Take a 'BWT' of 'Word8's and generate the
-- Move-to-front transform ('MTFB').
textBWTToMTFT :: TextBWT
-> MTFT
textBWTToMTFT xs =
MTFT (CMST.runST $ seqToMTFT xss)
where
xss = fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.decodeUtf8 $
BS.singleton $
fromJust x
)
((\(BWT t) -> t) $
((\(TextBWT t) -> t) xs))
-- | Take a 'BWT' of 'Word8's and generate the
-- Move-to-front transform ('MTFT').
bytestringBWTToMTFT :: BWT Word8
-> MTFT
bytestringBWTToMTFT xs =
MTFT (CMST.runST $ seqToMTFT xss)
where
xss = fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.decodeUtf8 $
BS.singleton $
fromJust x
)
((\(BWT t) -> t) xs)
-- | Takes a 'Text' and returns the Move-to-front transform ('MTFB').
textToMTFB :: Seq (Maybe Text)
-> MTFB
textToMTFB DS.Empty = MTFB (DS.Empty,DS.Empty)
textToMTFB xs =
MTFB (CMST.runST $ seqToMTFB xss)
where
xss = fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.encodeUtf8 $
fromJust x
)
xs
-- | Takes a 'Seq' of 'ByteString's and returns the Move-to-front transform ('MTFB').
bytestringToMTFB :: Seq (Maybe ByteString)
-> MTFB
bytestringToMTFB DS.Empty = MTFB (DS.Empty,DS.Empty)
bytestringToMTFB xs =
MTFB (CMST.runST $ seqToMTFB xs)
-- | Takes a 'Text' and returns the Move-to-front transform ('MTFT').
textToMTFT :: Seq (Maybe Text)
-> MTFT
textToMTFT DS.Empty = MTFT (DS.Empty,DS.Empty)
textToMTFT xs =
MTFT (CMST.runST $ seqToMTFT xs)
-- | Takes a 'ByteString' and returns the Move-to-front transform ('MTFT').
bytestringToMTFT :: Seq (Maybe ByteString)
-> MTFT
bytestringToMTFT DS.Empty = MTFT (DS.Empty,DS.Empty)
bytestringToMTFT xs =
MTFT (CMST.runST $ seqToMTFT xss)
where
xss = fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.decodeUtf8 $
fromJust x
)
xs
{-------------------}
{-fromMTF function(s)-}
-- | Helper function for converting a 'BWT'ed 'MTFB'
-- back to the original 'ByteString'.
bytestringFromBWTFromMTFB :: MTFB
-> ByteString
bytestringFromBWTFromMTFB = bytestringFromByteStringBWT . bytestringBWTFromMTFB
-- | Helper function for converting a 'BWT'ed 'MTFT'
-- back to the original 'ByteString'.
bytestringFromBWTFromMTFT :: MTFT
-> ByteString
bytestringFromBWTFromMTFT xs = bytestringFromByteStringBWT $
BWT $
fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.encodeUtf8 $
fromJust x
)
$
((\(BWT t) -> t) (textBWTFromMTFT xs))
-- | Helper function for converting a 'BWT'ed 'MTFB'
-- back to the original 'Text'.
textFromBWTFromMTFB :: MTFB
-> Text
textFromBWTFromMTFB = DTE.decodeUtf8 . bytestringFromByteStringBWT . bytestringBWTFromMTFB
-- | Helper function for converting a 'BWT'ed 'MTFT'
-- back to the original 'Text'.
textFromBWTFromMTFT :: MTFT
-> Text
textFromBWTFromMTFT = DTE.decodeUtf8 . bytestringFromByteStringBWT . bytestringBWTFromMTFT
-- | Takes a 'MTFT' and returns
-- the 'BWT' of 'Text's.
textBWTFromMTFT :: MTFT
-> BWT Text
textBWTFromMTFT (MTFT (DS.Empty,_)) = BWT DS.Empty
textBWTFromMTFT (MTFT (_,DS.Empty)) = BWT DS.Empty
textBWTFromMTFT xs =
BWT (CMST.runST $ seqFromMTFT xs)
-- | Takes a 'MTFT' and returns
-- the 'BWT' of 'ByteString's.
bytestringBWTFromMTFT :: MTFT
-> BWT ByteString
bytestringBWTFromMTFT (MTFT (DS.Empty,_)) = BWT DS.Empty
bytestringBWTFromMTFT (MTFT (_,DS.Empty)) = BWT DS.Empty
bytestringBWTFromMTFT xs = do
let originalbwtb = CMST.runST $ seqFromMTFT xs
BWT (fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.encodeUtf8 $
fromJust x
) originalbwtb)
-- | Takes a 'MTFB' and returns
-- the 'BWT' of 'Text's.
textBWTFromMTFB :: MTFB
-> BWT Text
textBWTFromMTFB (MTFB (DS.Empty,_)) = BWT DS.Empty
textBWTFromMTFB (MTFB (_,DS.Empty)) = BWT DS.Empty
textBWTFromMTFB xs = do
let originalbwtt = CMST.runST $ seqFromMTFB xs
BWT (fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.decodeUtf8 $
fromJust x
) originalbwtt)
-- | Take a 'MTFB' and returns
-- the 'BWT' of 'ByteString's.
bytestringBWTFromMTFB :: MTFB
-> BWT ByteString
bytestringBWTFromMTFB (MTFB (DS.Empty,_)) = BWT DS.Empty
bytestringBWTFromMTFB (MTFB (_,DS.Empty)) = BWT DS.Empty
bytestringBWTFromMTFB xs =
BWT (CMST.runST $ seqFromMTFB xs)
-- | Takes a 'MTFB' and returns
-- the original 'Seq' of 'Text's.
textFromMTFB :: MTFB
-> Seq (Maybe Text)
textFromMTFB (MTFB (DS.Empty,_)) = DS.Empty
textFromMTFB (MTFB (_,DS.Empty)) = DS.Empty
textFromMTFB xs = do
let originalt = CMST.runST $ seqFromMTFB xs
fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.decodeUtf8 $
fromJust x
) originalt
-- | Takes a 'MTFB' and returns
-- the original 'Seq' of 'ByteString's.
bytestringFromMTFB :: MTFB
-> Seq (Maybe ByteString)
bytestringFromMTFB (MTFB (DS.Empty,_)) = DS.Empty
bytestringFromMTFB (MTFB (_,DS.Empty)) = DS.Empty
bytestringFromMTFB xs =
CMST.runST $ seqFromMTFB xs
-- | Takes a 'MTFT' and returns
-- the original 'Seq' of 'Text's.
textFromMTFT :: MTFT
-> Seq (Maybe Text)
textFromMTFT (MTFT (DS.Empty,_)) = DS.Empty
textFromMTFT (MTFT (_,DS.Empty)) = DS.Empty
textFromMTFT xs =
CMST.runST $ seqFromMTFT xs
-- | Takes a 'MTFT' and returns
-- the original 'Seq' of 'ByteString's.
bytestringFromMTFT :: MTFT
-> Seq (Maybe ByteString)
bytestringFromMTFT (MTFT (DS.Empty,_)) = DS.Empty
bytestringFromMTFT (MTFT (_,DS.Empty)) = DS.Empty
bytestringFromMTFT xs = do
let originalb = CMST.runST $ seqFromMTFT xs
fmap (\x -> if | isNothing x
-> Nothing
| otherwise
-> Just $
DTE.encodeUtf8 $
fromJust x
) originalb
{---------------------}