{-# LANGUAGE BangPatterns, ExistentialQuantification #-}
-- |-- Module : Data.Text.Internal.Fusion.Types-- Copyright : (c) Tom Harper 2008-2009,-- (c) Bryan O'Sullivan 2009,-- (c) Duncan Coutts 2009,-- (c) Jasper Van der Jeugt 2011---- License : BSD-style-- Maintainer : bos@serpentine.com-- Stability : experimental-- Portability : GHC---- /Warning/: this is an internal module, and does not have a stable-- API or name. Functions in this module may not check or enforce-- preconditions expected by public modules. Use at your own risk!---- Core stream fusion functionality for text.
module Data.Text.Internal.Fusion.Types
(
CC(..)
, M(..)
, M8
, PairS(..)
, RS(..)
, Step(..)
, Stream(..)
, Switch(..)
, empty
) where
import Data.Text.Internal.Fusion.Size
import Data.Word (Word8)
-- | Specialised tuple for case conversion.
data CCs = CC !s {-# UNPACK #-} !Char {-# UNPACK #-} !Char-- | Specialised, strict Maybe-like type.
data Ma = N
| J !atype M8 = M Word8-- Restreaming state.
data RSs
= RS0 !s
| RS1 !s {-# UNPACK #-} !Word8
| RS2 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8
| RS3 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8infixl 2 :*:
data PairSab = !a:*: !b-- deriving (Eq, Ord, Show)-- | Allow a function over a stream to switch between two states.
data Switch = S1 | S2
data Stepsa = Done
| Skip !s
| Yield !a !s{-
instance (Show a) => Show (Step s a)
where show Done = "Done"
show (Skip _) = "Skip"
show (Yield x _) = "Yield " ++ show x
-}
instance (Eq a) =>Eq (Streama) where
(==) = eq
instance (Ord a) =>Ord (Streama) where
compare = cmp-- The length hint in a Stream has two roles. If its value is zero,-- we trust it, and treat the stream as empty. Otherwise, we treat it-- as a hint: it should usually be accurate, so we use it when-- unstreaming to decide what size array to allocate. However, the-- unstreaming functions must be able to cope with the hint being too-- small or too large.---- The size hint tries to track the UTF-16 code points in a stream,-- but often counts the number of characters instead. It can easily-- undercount if, for instance, a transformed stream contains astral-- plane characters (those above 0x10000).
data Streama =
forall s. Stream
(s -> Stepsa) -- stepper function
!s-- current state
!Size-- size hint-- | /O(n)/ Determines if two streams are equal.eq :: (Eq a) =>Streama -> Streama -> Booleq (Streamnext1s1 _) (Streamnext2s2 _) = loop (next1s1) (next2s2)
where
loopDoneDone = Trueloop (Skips1') (Skips2') = loop (next1s1') (next2s2')
loop (Skips1') x2 = loop (next1s1') x2loopx1 (Skips2') = loopx1 (next2s2')
loopDone _ = Falseloop _ Done = Falseloop (Yieldx1s1') (Yieldx2s2') = x1==x2&&loop (next1s1') (next2s2')
{-# INLINE [0] eq #-}cmp :: (Ord a) =>Streama -> Streama -> Orderingcmp (Streamnext1s1 _) (Streamnext2s2 _) = loop (next1s1) (next2s2)
where
loopDoneDone = EQloop (Skips1') (Skips2') = loop (next1s1') (next2s2')
loop (Skips1') x2 = loop (next1s1') x2loopx1 (Skips2') = loopx1 (next2s2')
loopDone _ = LTloop _ Done = GTloop (Yieldx1s1') (Yieldx2s2') =
case comparex1x2 of
EQ -> loop (next1s1') (next2s2')
other -> other{-# INLINE [0] cmp #-}-- | The empty stream.empty :: Streamaempty = Streamnext()0
where next _ = Done{-# INLINE [0] empty #-}