module Data.Text.Array
(
Array(..)
, MArray(..)
, copyM
, copyI
, empty
, equal
, run
, run2
, toList
, unsafeFreeze
, unsafeIndex
, new
, unsafeWrite
) where
#if defined(ASSERTS)
import Control.Exception (assert)
import GHC.Base (sizeofByteArray#, sizeofMutableByteArray#)
import GHC.Stack (HasCallStack)
#endif
import Control.Monad.ST.Unsafe (unsafeIOToST)
import Data.Bits ((.&.), xor)
import Data.Text.Internal.Unsafe (inlinePerformIO)
import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)
import Foreign.C.Types (CInt(CInt), CSize(CSize))
import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
indexWord16Array#, newByteArray#,
unsafeFreezeByteArray#, writeWord16Array#)
import GHC.ST (ST(..), runST)
import GHC.Word (Word16(..))
import Prelude hiding (length, read)
data Array = Array { aBA :: ByteArray# }
data MArray s = MArray { maBA :: MutableByteArray# s }
new :: forall s. Int -> ST s (MArray s)
new n
| n < 0 || n .&. highBit /= 0 = array_size_error
| otherwise = ST $ \s1# ->
case newByteArray# len# s1# of
(# s2#, marr# #) -> (# s2#, MArray marr# #)
where !(I# len#) = bytesInArray n
highBit = maxBound `xor` (maxBound `shiftR` 1)
array_size_error :: a
array_size_error = error "Data.Text.Array.new: size overflow"
unsafeFreeze :: MArray s -> ST s Array
unsafeFreeze MArray{..} = ST $ \s1# ->
case unsafeFreezeByteArray# maBA s1# of
(# s2#, ba# #) -> (# s2#, Array ba# #)
bytesInArray :: Int -> Int
bytesInArray n = n `shiftL` 1
unsafeIndex ::
#if defined(ASSERTS)
HasCallStack =>
#endif
Array -> Int -> Word16
unsafeIndex a@Array{..} i@(I# i#) =
#if defined(ASSERTS)
let word16len = I# (sizeofByteArray# aBA) `quot` 2 in
if i < 0 || i >= word16len
then error ("Data.Text.Array.unsafeIndex: bounds error, offset " ++ show i ++ ", length " ++ show word16len)
else
#endif
case indexWord16Array# aBA i# of r# -> (W16# r#)
unsafeWrite ::
#if defined(ASSERTS)
HasCallStack =>
#endif
MArray s -> Int -> Word16 -> ST s ()
unsafeWrite ma@MArray{..} i@(I# i#) (W16# e#) = ST $ \s1# ->
#if defined(ASSERTS)
let word16len = I# (sizeofMutableByteArray# maBA) `quot` 2 in
if i < 0 || i >= word16len then error ("Data.Text.Array.unsafeWrite: bounds error, offset " ++ show i ++ ", length " ++ show word16len) else
#endif
case writeWord16Array# maBA i# e# s1# of
s2# -> (# s2#, () #)
toList :: Array -> Int -> Int -> [Word16]
toList ary off len = loop 0
where loop i | i < len = unsafeIndex ary (off+i) : loop (i+1)
| otherwise = []
empty :: Array
empty = runST (new 0 >>= unsafeFreeze)
run :: (forall s. ST s (MArray s)) -> Array
run k = runST (k >>= unsafeFreeze)
run2 :: (forall s. ST s (MArray s, a)) -> (Array, a)
run2 k = runST (do
(marr,b) <- k
arr <- unsafeFreeze marr
return (arr,b))
copyM :: MArray s
-> Int
-> MArray s
-> Int
-> Int
-> ST s ()
copyM dest didx src sidx count
| count <= 0 = return ()
| otherwise =
#if defined(ASSERTS)
assert (sidx + count <= I# (sizeofMutableByteArray# (maBA src)) `quot` 2) .
assert (didx + count <= I# (sizeofMutableByteArray# (maBA dest)) `quot` 2) .
#endif
unsafeIOToST $ memcpyM (maBA dest) (intToCSize didx)
(maBA src) (intToCSize sidx)
(intToCSize count)
copyI :: MArray s
-> Int
-> Array
-> Int
-> Int
-> ST s ()
copyI dest i0 src j0 top
| i0 >= top = return ()
| otherwise = unsafeIOToST $
memcpyI (maBA dest) (intToCSize i0)
(aBA src) (intToCSize j0)
(intToCSize (topi0))
equal :: Array
-> Int
-> Array
-> Int
-> Int
-> Bool
equal arrA offA arrB offB count = inlinePerformIO $ do
i <- memcmp (aBA arrA) (intToCSize offA)
(aBA arrB) (intToCSize offB) (intToCSize count)
return $! i == 0
intToCSize :: Int -> CSize
intToCSize = fromIntegral
foreign import ccall unsafe "_hs_text_memcpy" memcpyI
:: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO ()
foreign import ccall unsafe "_hs_text_memcmp" memcmp
:: ByteArray# -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt
foreign import ccall unsafe "_hs_text_memcpy" memcpyM
:: MutableByteArray# s -> CSize -> MutableByteArray# s -> CSize -> CSize
-> IO ()