{-# 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
                             Array
arr <- MArray s -> ST s Array
forall s. MArray s -> ST s Array
A.unsafeFreeze MArray s
marr
                             Text -> ST s Text
forall a. a -> ST s a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> ST s Text) -> Text -> ST s Text
forall a b. (a -> b) -> a -> b
$! Array -> Int -> Int -> Text
text Array
arr Int
0 Int
len)
{-# INLINE runText #-}