@@ -1,9 +1,9 @@
1−{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, RecordWildCards,
2− UnboxedTuples #-}
1+{-# LANGUAGE BangPatterns, CPP, ForeignFunctionInterface, MagicHash, Rank2Types,
2+ RecordWildCards, UnboxedTuples, UnliftedFFITypes #-}
33{-# OPTIONS_GHC -fno-warn-unused-matches #-}
44-- |
55-- Module : Data.Text.Array
6−-- Copyright : (c) 2009, 2010 Bryan O'Sullivan
6+-- Copyright : (c) 2009, 2010, 2011 Bryan O'Sullivan
77--
88-- License : BSD-style
99-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
@@ -60,14 +60,16 @@ if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ "
6060#if defined(ASSERTS)
6161import Control.Exception (assert)
6262#endif
63+import Control.Monad.ST (unsafeIOToST)
6364import Data.Bits ((.&.), xor)
65+import Data.Text.Unsafe.Base (inlinePerformIO)
6466import Data.Text.UnsafeShift (shiftL, shiftR)
67+import Foreign.C.Types (CInt, CSize)
6568import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
66− indexWord16Array#, indexWordArray#, newByteArray#,
67− readWord16Array#, readWordArray#, unsafeCoerce#,
68− writeWord16Array#, writeWordArray#)
69+ indexWord16Array#, newByteArray#,
70+ unsafeCoerce#, writeWord16Array#)
6971import GHC.ST (ST(..), runST)
70−import GHC.Word (Word16(..), Word(..))
72+import GHC.Word (Word16(..))
7173import Prelude hiding (length, read)
7274
7375-- | Immutable array type.
@@ -140,23 +142,6 @@ unsafeIndex Array{..} i@(I# i#) =
140142 case indexWord16Array# aBA i# of r# -> (W16# r#)
141143{-# INLINE unsafeIndex #-}
142144
143−-- | Unchecked read of an immutable array. May return garbage or
144−-- crash on an out-of-bounds access.
145−unsafeIndexWord :: Array -> Int -> Word
146−unsafeIndexWord Array{..} i@(I# i#) =
147− CHECK_BOUNDS("unsafeIndexWord",aLen`div`wordFactor,i)
148− case indexWordArray# aBA i# of r# -> (W# r#)
149−{-# INLINE unsafeIndexWord #-}
150−
151−-- | Unchecked read of a mutable array. May return garbage or
152−-- crash on an out-of-bounds access.
153−unsafeRead :: MArray s -> Int -> ST s Word16
154−unsafeRead MArray{..} i@(I# i#) = ST $ \s# ->
155− CHECK_BOUNDS("unsafeRead",maLen,i)
156− case readWord16Array# maBA i# s# of
157− (# s2#, r# #) -> (# s2#, W16# r# #)
158−{-# INLINE unsafeRead #-}
159−
160145-- | Unchecked write of a mutable array. May return garbage or crash
161146-- on an out-of-bounds access.
162147unsafeWrite :: MArray s -> Int -> Word16 -> ST s ()
@@ -166,24 +151,6 @@ unsafeWrite MArray{..} i@(I# i#) (W16# e#) = ST $ \s1# ->
166151 s2# -> (# s2#, () #)
167152{-# INLINE unsafeWrite #-}
168153
169−-- | Unchecked read of a mutable array. May return garbage or
170−-- crash on an out-of-bounds access.
171−unsafeReadWord :: MArray s -> Int -> ST s Word
172−unsafeReadWord MArray{..} i@(I# i#) = ST $ \s# ->
173− CHECK_BOUNDS("unsafeRead64",maLen`div`wordFactor,i)
174− case readWordArray# maBA i# s# of
175− (# s2#, r# #) -> (# s2#, W# r# #)
176−{-# INLINE unsafeReadWord #-}
177−
178−-- | Unchecked write of a mutable array. May return garbage or crash
179−-- on an out-of-bounds access.
180−unsafeWriteWord :: MArray s -> Int -> Word -> ST s ()
181−unsafeWriteWord MArray{..} i@(I# i#) (W# e#) = ST $ \s1# ->
182− CHECK_BOUNDS("unsafeWriteWord",maLen`div`wordFactor,i)
183− case writeWordArray# maBA i# e# s1# of
184− s2# -> (# s2#, () #)
185−{-# INLINE unsafeWriteWord #-}
186−
187154-- | Convert an immutable array to a list.
188155toList :: Array -> Int -> Int -> [Word16]
189156toList ary off len = loop 0
@@ -207,15 +174,6 @@ run2 k = runST (do
207174 arr <- unsafeFreeze marr
208175 return (arr,b))
209176
210−-- | The amount to divide or multiply by to switch between units of
211−-- 'Word16' and units of 'Word'.
212−wordFactor :: Int
213−wordFactor = SIZEOF_HSWORD `shiftR` 1
214−
215−-- | Indicate whether an offset is word-aligned.
216−wordAligned :: Int -> Bool
217−wordAligned i = i .&. (wordFactor - 1) == 0
218−
219177-- | Copy some elements of a mutable array.
220178copyM :: MArray s -- ^ Destination
221179 -> Int -- ^ Destination offset
@@ -223,49 +181,33 @@ copyM :: MArray s -- ^ Destination
223181 -> Int -- ^ Source offset
224182 -> Int -- ^ Count
225183 -> ST s ()
226−copyM dest didx src sidx count =
184+copyM dest didx src sidx count
185+ | count <= 0 = return ()
186+ | otherwise =
227187#if defined(ASSERTS)
228188 assert (sidx + count <= length src) .
229− assert (didx + count <= length dest) $
189+ assert (didx + count <= length dest) .
230190#endif
231− if srem == 0 && drem == 0
232− then fast_loop 0
233− else slow_loop 0
234− where
235− (swidx,srem) = sidx `divMod` wordFactor
236− (dwidx,drem) = didx `divMod` wordFactor
237− nwds = count `div` wordFactor
238− fast_loop !i
239− | i >= nwds = slow_loop (i * wordFactor)
240− | otherwise = do w <- unsafeReadWord src (swidx+i)
241− unsafeWriteWord dest (dwidx+i) w
242− fast_loop (i+1)
243− slow_loop !i
244− | i >= count= return ()
245− | otherwise = do unsafeRead src (sidx+i) >>= unsafeWrite dest (didx+i)
246− slow_loop (i+1)
191+ unsafeIOToST $ memcpyM (maBA dest) (fromIntegral didx)
192+ (maBA src) (fromIntegral sidx)
193+ (fromIntegral count)
194+{-# INLINE copyM #-}
247195
248196-- | Copy some elements of an immutable array.
249197copyI :: MArray s -- ^ Destination
250198 -> Int -- ^ Destination offset
251199 -> Array -- ^ Source
252200 -> Int -- ^ Source offset
253− -> Int -- ^ First offset in source /not/ to
201+ -> Int -- ^ First offset in destination /not/ to
254202 -- copy (i.e. /not/ length)
255203 -> ST s ()
256204copyI dest i0 src j0 top
257− | wordAligned i0 && wordAligned j0 = fast (i0 `div` wordFactor) (j0 `div` wordFactor)
258− | otherwise = slow i0 j0
259− where
260− topwds = top `div` wordFactor
261− fast !i !j
262− | i >= topwds = slow (i * wordFactor) (j * wordFactor)
263− | otherwise = do unsafeWriteWord dest i (src `unsafeIndexWord` j)
264− fast (i+1) (j+1)
265− slow !i !j
266− | i >= top = return ()
267− | otherwise = do unsafeWrite dest i (src `unsafeIndex` j)
268− slow (i+1) (j+1)
205+ | i0 >= top = return ()
206+ | otherwise = unsafeIOToST $
207+ memcpyI (maBA dest) (fromIntegral i0)
208+ (aBA src) (fromIntegral j0)
209+ (fromIntegral (top-i0))
210+{-# INLINE copyI #-}
269211
270212-- | Compare portions of two arrays for equality. No bounds checking
271213-- is performed.
@@ -275,22 +217,18 @@ equal :: Array -- ^ First
275217 -> Int -- ^ Offset into second
276218 -> Int -- ^ Count
277219 -> Bool
278−equal arrA offA arrB offB count
279− | wordAligned offA && wordAligned offB = fast 0
280− | otherwise = slow 0
281− where
282− countWords = count `div` wordFactor
283− fast !i
284− | i >= countWords = slow (i * wordFactor)
285− | a /= b = False
286− | otherwise = fast (i+1)
287− where a = unsafeIndexWord arrA (offAW+i)
288− b = unsafeIndexWord arrB (offBW+i)
289− offAW = offA `div` wordFactor
290− offBW = offB `div` wordFactor
291− slow !i
292− | i >= count = True
293− | a /= b = False
294− | otherwise = slow (i+1)
295− where a = unsafeIndex arrA (offA+i)
296− b = unsafeIndex arrB (offB+i)
220+equal arrA offA arrB offB count = inlinePerformIO $ do
221+ i <- memcmp (aBA arrA) (fromIntegral offA)
222+ (aBA arrB) (fromIntegral offB) (fromIntegral count)
223+ return $! i == 0
224+{-# INLINE equal #-}
225+
226+foreign import ccall unsafe "_hs_text_memcpy" memcpyI
227+ :: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO ()
228+
229+foreign import ccall unsafe "_hs_text_memcmp" memcmp
230+ :: ByteArray# -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt
231+
232+foreign import ccall unsafe "_hs_text_memcpy" memcpyM
233+ :: MutableByteArray# s -> CSize -> MutableByteArray# s -> CSize -> CSize
234+ -> IO ()