Source

text / Data / Text / Lazy / Fusion.hs

Bryan O'Sullivan fd9bda5 

Bryan O'Sullivan 53b9461 
Bryan O'Sullivan fd9bda5 

Bryan O'Sullivan 9adb5ed 
Bryan O'Sullivan fd9bda5 









Bryan O'Sullivan 53b9461 
Bryan O'Sullivan bfc542c 

Bryan O'Sullivan 9c2cd37 
Bryan O'Sullivan 17ec386 

Bryan O'Sullivan d77bd97 


Bryan O'Sullivan fd9bda5 

Bryan O'Sullivan bfc542c 

Bryan O'Sullivan fd9bda5 



Bryan O'Sullivan f8c1e64 
Bryan O'Sullivan fd9bda5 
Bryan O'Sullivan bfc542c 
Bryan O'Sullivan fd9bda5 
Bryan O'Sullivan bfc542c 
Bryan O'Sullivan fd9bda5 
Bryan O'Sullivan 53b9461 
Bryan O'Sullivan fd9bda5 
Nicolas Pouillar… deaf0b3 
Bryan O'Sullivan fd9bda5 







Bryan O'Sullivan 53b9461 



Bryan O'Sullivan fd9bda5 



Bryan O'Sullivan 53b9461 



Bryan O'Sullivan f8c1e64 
Nicolas Pouillar… ef3e373 

Bryan O'Sullivan 53b9461 
Nicolas Pouillar… ef3e373 
Bryan O'Sullivan 53b9461 


Bryan O'Sullivan fd9bda5 

Nicolas Pouillar… ef3e373 
Bryan O'Sullivan fd9bda5 

Nicolas Pouillar… ef3e373 


Bryan O'Sullivan 53b9461 





Bryan O'Sullivan fd9bda5 
Bryan O'Sullivan 53b9461 
Bryan O'Sullivan bfc542c 




Bryan O'Sullivan 1086a63 

Bryan O'Sullivan bfc542c 





Nicolas Pouillar… 7938a65 
Bryan O'Sullivan bfc542c 
Bryan O'Sullivan 9c2cd37 




Bryan O'Sullivan 17ec386 













Bryan O'Sullivan d77bd97 

















-- |
-- Module      : Data.Text.Lazy.Fusion
-- Copyright   : (c) Bryan O'Sullivan 2009
--
-- License     : BSD-style
-- Maintainer  : bos@serpentine.com, rtharper@aftereternity.co.uk,
--               duncan@haskell.org
-- Stability   : experimental
-- Portability : GHC
--
-- Core stream fusion functionality for text.

module Data.Text.Lazy.Fusion
    (
      stream
    , unstream
    , unstreamChunks
    , length
    , unfoldrN
    , index
    , findIndex
    , findIndices
    , elemIndex
    , elemIndices
    , count
    ) where

import Prelude hiding (length)
import qualified Data.Text.Fusion.Common as S
import Data.Text.Fusion.Internal
import Data.Text.Lazy.Internal
import qualified Data.Text.Internal as I
import qualified Data.Text.Array as A
import Data.Text.UnsafeChar (unsafeWrite)
import Data.Text.Unsafe (iter)
import Data.Int (Int64)

default(Int64)

-- | /O(n)/ Convert a 'Text' into a 'Stream Char'.
stream :: Text -> Stream Char
stream text = Stream next (text :!: 0) 4 -- random HINT
  where
    next (Empty :!: _) = Done
    next (txt@(Chunk t@(I.Text _ _ len) ts) :!: i)
        | i >= len  = next (ts :!: 0)
        | otherwise = Yield c (txt :!: i+d)
        where (c,d) = iter t i
{-# INLINE [0] stream #-}

-- | /O(n)/ Convert a 'Stream Char' into a 'Text', using the given
-- chunk size.
unstreamChunks :: Int -> Stream Char -> Text
unstreamChunks chunkSize (Stream next s0 len0)
  | len0 == 0 = Empty
  | otherwise = outer s0
  where
    outer s = case next s of
                Done       -> Empty
                Skip s'    -> outer s'
                Yield x s' -> I.Text arr 0 len `chunk` outer s''
                  where (arr,(s'',len)) = A.run2 fill
                        fill = do a <- A.unsafeNew unknownLength
                                  i <- unsafeWrite a 0 x
                                  inner a unknownLength s' i
                        unknownLength = 4
    inner marr len s i
        | i + 1 >= chunkSize = return (marr, (s,i))
        | i + 1 >= len       = do
            let newLen = min (len * 2) chunkSize
            marr' <- A.unsafeNew newLen
            A.copy marr marr'
            inner marr' newLen s i
        | otherwise =
            case next s of
              Done        -> return (marr,(s,i))
              Skip s'     -> inner marr len s' i
              Yield x s'  -> unsafeWrite marr i x >>= inner marr len s'
{-# INLINE [0] unstreamChunks #-}

-- | /O(n)/ Convert a 'Stream Char' into a 'Text', using
-- 'defaultChunkSize'.
unstream :: Stream Char -> Text
unstream = unstreamChunks defaultChunkSize
{-# INLINE [0] unstream #-}

-- | /O(n)/ Returns the number of characters in a text.
length :: Stream Char -> Int64
length = S.lengthI
{-# INLINE[0] length #-}

{-# RULES "LAZY STREAM stream/unstream fusion" forall s.
    stream (unstream s) = s #-}

-- | /O(n)/ Like 'unfoldr', 'unfoldrN64' builds a stream from a seed
-- value. However, the length of the result is limited by the
-- first argument to 'unfoldrN64'. This function is more efficient than
-- 'unfoldr' when the length of the result is known.
unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Stream Char
unfoldrN n = S.unfoldrNI n
{-# INLINE [0] unfoldrN #-}

-- | /O(n)/ stream index (subscript) operator, starting from 0.
index :: Stream Char -> Int64 -> Char
index = S.indexI
{-# INLINE [0] index #-}

-- | The 'findIndex' function takes a predicate and a stream and
-- returns the index of the first element in the stream
-- satisfying the predicate.
findIndex :: (Char -> Bool) -> Stream Char -> Maybe Int64
findIndex = S.findIndexI
{-# INLINE [0] findIndex #-}

-- | The 'findIndices' function takes a predicate and a stream and
-- returns all indices of the elements in the stream
-- satisfying the predicate.
findIndices :: (Char -> Bool) -> Stream Char -> [Int64]
findIndices = S.findIndicesI
{-# INLINE [0] findIndices #-}

-- | /O(n)/ The 'elemIndex' function returns the index of the first
-- element in the given stream which is equal to the query
-- element, or 'Nothing' if there is no such element.
elemIndex :: Char -> Stream Char -> Maybe Int64
elemIndex = S.elemIndexI
{-# INLINE [0] elemIndex #-}

-- | /O(n)/ The 'elemIndices' function returns the index of every
-- element in the given stream which is equal to the query element.
elemIndices :: Char -> Stream Char -> [Int64]
elemIndices = S.elemIndicesI
{-# INLINE [0] elemIndices #-}

-- | /O(n)/ The 'count' function returns the number of times the query
-- element appears in the given stream.
count :: Char -> Stream Char -> Int64
count = S.countI
{-# INLINE [0] count #-}