    {-# LANGUAGE BangPatterns, CPP, RankNTypes, UnboxedTuples #-}

    -- |
    -- Module      : Data.Text.Internal.Private
    -- Copyright   : (c) 2011 Bryan O'Sullivan
    --
    -- License     : BSD-style
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : GHC

    module Data.Text.Internal.Private
        (
          runText
        , span_
        , spanAscii_
        ) where

    import Control.Monad.ST (ST, runST)
    import Data.Text.Internal (Text(..), text)
    import Data.Text.Unsafe (Iter(..), iter)
    import qualified Data.Text.Array as A
    import Data.Word (Word8)

    #if defined(ASSERTS)
    import GHC.Stack (HasCallStack)
    #endif

    span_ :: (Char -> Bool) -> Text -> (# Text, Text #)
    span_ :: (Char -> Bool) -> Text -> (# Text, Text #)
    span_ Char -> Bool
    p t :: Text
    t@(Text Array
    arr Int
    off Int
    len) = (# Text
    hd,Text
    tl #)
      where hd :: Text
    hd = Array -> Int -> Int -> Text
    text Array
    arr Int
    off Int
    k
            tl :: Text
    tl = Array -> Int -> Int -> Text
    text Array
    arr (Int
    offInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    k) (Int
    lenInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    k)
            !k :: Int
    k = Int -> Int
    loop Int
    0
            loop :: Int -> Int
    loop !Int
    i | Int
    i Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    len Bool -> Bool -> Bool
    && Char -> Bool
    p Char
    c = Int -> Int
    loop (Int
    iInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    d)
                    | Bool
    otherwise      = Int
    i
                where Iter Char
    c Int
    d       = Text -> Int -> Iter
    iter Text
    t Int
    i
    {-# INLINE span_ #-}

    -- | For the sake of performance this function does not check
    -- that a char is in ASCII range; it is a responsibility of @p@.
    --
    -- @since 2.0
    spanAscii_ :: (Word8 -> Bool) -> Text -> (# Text, Text #)
    spanAscii_ :: (Word8 -> Bool) -> Text -> (# Text, Text #)
    spanAscii_ Word8 -> Bool
    p (Text Array
    arr Int
    off Int
    len) = (# Text
    hd, Text
    tl #)
      where hd :: Text
    hd = Array -> Int -> Int -> Text
    text Array
    arr Int
    off Int
    k
            tl :: Text
    tl = Array -> Int -> Int -> Text
    text Array
    arr (Int
    off Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    k) (Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    k)
            !k :: Int
    k = Int -> Int
    loop Int
    0
            loop :: Int -> Int
    loop !Int
    i | Int
    i Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    len Bool -> Bool -> Bool
    && Word8 -> Bool
    p (Array -> Int -> Word8
    A.unsafeIndex Array
    arr (Int
    off Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    i)) = Int -> Int
    loop (Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1)
                    | Bool
    otherwise = Int
    i
    {-# INLINE spanAscii_ #-}

    runText ::
    #if defined(ASSERTS)
      HasCallStack =>
    #endif
      (forall s. (A.MArray s -> Int -> ST s Text) -> ST s Text) -> Text
    runText :: (forall s. (MArray s -> Int -> ST s Text) -> ST s Text) -> Text
    runText forall s. (MArray s -> Int -> ST s Text) -> ST s Text
    act = (forall s. ST s Text) -> Text
    forall a. (forall s. ST s a) -> a
    runST ((MArray s -> Int -> ST s Text) -> ST s Text
    forall s. (MArray s -> Int -> ST s Text) -> ST s Text
    act ((MArray s -> Int -> ST s Text) -> ST s Text)
    -> (MArray s -> Int -> ST s Text) -> ST s Text
    forall a b. (a -> b) -> a -> b
    $ \ !MArray s
    marr !Int
    len -> do
                                 MArray s -> Int -> ST s ()
    forall s. MArray s -> Int -> ST s ()
    A.shrinkM MArray s
    marr Int
    len
                                 arr <- MArray s -> ST s Array
    forall s. MArray s -> ST s Array
    A.unsafeFreeze MArray s
    marr
                                 return $! text arr 0 len)
    {-# INLINE runText #-}