@@ -57,9 +57,10 @@ if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ "
57#if defined(ASSERTS)
57#if defined(ASSERTS)
58import Control.Exception (assert)
58import Control.Exception (assert)
60+import Data.Bits ((.&.))
60import Data.Text.UnsafeShift (shiftL, shiftR)
61import Data.Text.UnsafeShift (shiftL, shiftR)
61import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
62import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
62− indexWord16Array#, newByteArray#,
63+ indexWord16Array#, indexWordArray#, newByteArray#,
63 readWord16Array#, readWordArray#, unsafeCoerce#,
64 readWord16Array#, readWordArray#, unsafeCoerce#,
64 writeWord16Array#, writeWordArray#)
65 writeWord16Array#, writeWordArray#)
65import GHC.ST (ST(..), runST)
66import GHC.ST (ST(..), runST)
@@ -125,6 +126,14 @@ unsafeIndex (Array len ba#) i@(I# i#) =
125 case indexWord16Array# ba# i# of r# -> (W16# r#)
126 case indexWord16Array# ba# i# of r# -> (W16# r#)
126{-# INLINE unsafeIndex #-}
127{-# INLINE unsafeIndex #-}
129+-- | Unchecked read of an immutable array. May return garbage or
130+-- crash on an out-of-bounds access.
131+unsafeIndexWord :: Array -> Int -> Word
132+unsafeIndexWord (Array len ba#) i@(I# i#) =
133+ CHECK_BOUNDS("unsafeIndexWord",len,i)
134+ case indexWordArray# ba# i# of r# -> (W# r#)
135+{-# INLINE unsafeIndexWord #-}
128-- | Unchecked read of a mutable array. May return garbage or
137-- | Unchecked read of a mutable array. May return garbage or
129-- crash on an out-of-bounds access.
138-- crash on an out-of-bounds access.
130unsafeRead :: MArray s -> Int -> ST s Word16
139unsafeRead :: MArray s -> Int -> ST s Word16
@@ -185,6 +194,15 @@ run2 k = runST (do
185 arr <- unsafeFreeze marr
194 arr <- unsafeFreeze marr
186 return (arr,b))
195 return (arr,b))
197+-- | The amount to divide or multiply by to switch between units of
198+-- 'Word16' and units of 'Word'.
200+wordFactor = SIZEOF_HSWORD `shiftR` 1
202+-- | Indicate whether an offset is word-aligned.
203+wordAligned :: Int -> Bool
204+wordAligned i = i .&. (wordFactor - 1) == 0
188-- | Copy an array in its entirety. The destination array must be at
206-- | Copy an array in its entirety. The destination array must be at
189-- least as big as the source.
207-- least as big as the source.
190copy :: MArray s -- ^ source array
208copy :: MArray s -- ^ source array
@@ -194,9 +212,9 @@ copy dest@(MArray dlen _) src@(MArray slen _)
194 | dlen >= slen = fast_loop 0
212 | dlen >= slen = fast_loop 0
195 | otherwise = fail "Data.Text.Array.copy: array too small"
213 | otherwise = fail "Data.Text.Array.copy: array too small"
197− nwds = slen `div` (SIZEOF_HSWORD `shiftR` 1)
215+ nwds = slen `div` wordFactor
198 fast_loop !i
216 fast_loop !i
199− | i >= nwds = copy_loop (i * (SIZEOF_HSWORD `shiftR` 1))
217+ | i >= nwds = copy_loop (i * wordFactor)
200 | otherwise = do unsafeReadWord src i >>= unsafeWriteWord dest i
218 | otherwise = do unsafeReadWord src i >>= unsafeWriteWord dest i
201 fast_loop (i+1)
219 fast_loop (i+1)
202 copy_loop !i
220 copy_loop !i
@@ -205,7 +223,12 @@ copy dest@(MArray dlen _) src@(MArray slen _)
205 copy_loop (i+1)
223 copy_loop (i+1)
207-- | Copy some elements of a mutable array.
225-- | Copy some elements of a mutable array.
208−partialCopyM :: MArray s -> Int -> MArray s -> Int -> Int -> ST s ()
226+partialCopyM :: MArray s -- ^ Destination
227+ -> Int -- ^ Destination offset
228+ -> MArray s -- ^ Source
229+ -> Int -- ^ Source offset
209partialCopyM dest didx src sidx count =
232partialCopyM dest didx src sidx count =
210#if defined(ASSERTS)
233#if defined(ASSERTS)
211 assert (sidx + count <= length src) .
234 assert (sidx + count <= length src) .
@@ -219,9 +242,23 @@ partialCopyM dest didx src sidx count =
219 copy_loop (i+1) (j+1) (c+1)
242 copy_loop (i+1) (j+1) (c+1)
221-- | Copy some elements of an immutable array.
244-- | Copy some elements of an immutable array.
222−partialCopyI :: MArray s -> Int -> Array -> Int -> Int -> ST s ()
245+partialCopyI :: MArray s -- ^ Destination
246+ -> Int -- ^ Destination offset
247+ -> Array -- ^ Source
248+ -> Int -- ^ Source offset
249+ -> Int -- ^ First offset in source /not/ to
250+ -- copy (i.e. /not/ length)
223−partialCopyI dest i0 src j0 top = go i0 j0
252+partialCopyI dest i0 src j0 top
253+ | wordAligned i0 && wordAligned j0 = fast (i0 `div` wordFactor) (j0 `div` wordFactor)
254+ | otherwise = slow i0 j0
256+ topwds = top `div` wordFactor
258+ | i >= topwds = slow (i * wordFactor) (j * wordFactor)
259+ | otherwise = do unsafeWriteWord dest i (src `unsafeIndexWord` j)
225− go !i !j | i >= top = return ()
262+ | i >= top = return ()
226− | otherwise = do unsafeWrite dest i (src `unsafeIndex` j)
263+ | otherwise = do unsafeWrite dest i (src `unsafeIndex` j)
227− go (i+1) (j+1)
264+ slow (i+1) (j+1)