1{-# LANGUAGE BangPatterns, CPP, ForeignFunctionInterface, MagicHash, Rank2Types,
2 RecordWildCards, UnboxedTuples, UnliftedFFITypes #-}
3{-# OPTIONS_GHC -fno-warn-unused-matches #-}
5-- Module : Data.Text.Array
6-- Copyright : (c) 2009, 2010, 2011 Bryan O'Sullivan
9-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
11-- Stability : experimental
12-- Portability : portable
14-- Packed, unboxed, heap-resident arrays. Suitable for performance
15-- critical use, both in terms of large data quantities and high
18-- This module is intended to be imported @qualified@, to avoid name
19-- clashes with "Prelude" functions, e.g.
21-- > import qualified Data.Text.Array as A
23-- The names in this module resemble those in the 'Data.Array' family
24-- of modules, but are shorter due to the assumption of qualifid
50-- This fugly hack is brought by GHC's apparent reluctance to deal
51-- with MagicHash and UnboxedTuples when inferring types. Eek!
52# define CHECK_BOUNDS(_func_,_len_,_k_) \
53if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else
55# define CHECK_BOUNDS(_func_,_len_,_k_)
61import Control.Exception (assert)
63#if __GLASGOW_HASKELL__ >= 702
64import Control.Monad.ST.Unsafe (unsafeIOToST)
66import Control.Monad.ST (unsafeIOToST)
68import Data.Bits ((.&.), xor)
69import Data.Text.Unsafe.Base (inlinePerformIO)
70import Data.Text.UnsafeShift (shiftL, shiftR)
71#if __GLASGOW_HASKELL__ >= 703
72import Foreign.C.Types (CInt(CInt), CSize(CSize))
74import Foreign.C.Types (CInt, CSize)
76import GHC.Base (ByteArray#, MutableByteArray#, Int(..),
77 indexWord16Array#, newByteArray#,
78 unsafeCoerce#, writeWord16Array#)
79import GHC.ST (ST(..), runST)
80import GHC.Word (Word16(..))
81import Prelude hiding (length, read)
83-- | Immutable array type.
87 , aLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)
91-- | Mutable array type, for use in the ST monad.
92data MArray s = MArray {
93 maBA :: MutableByteArray# s
95 , maLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)
100-- | Operations supported by all arrays.
102 -- | Return the length of an array.
105instance IArray Array where
107 {-# INLINE length #-}
109instance IArray (MArray s) where
111 {-# INLINE length #-}
114-- | Create an uninitialized mutable array.
115new :: forall s. Int -> ST s (MArray s)
117 | n < 0 || n .&. highBit /= 0 = error $ "Data.Text.Array.new: size overflow"
118 | otherwise = ST $ \s1# ->
119 case newByteArray# len# s1# of
120 (# s2#, marr# #) -> (# s2#, MArray marr#
125 where !(I# len#) = bytesInArray n
126 highBit = maxBound `xor` (maxBound `shiftR` 1)
129-- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!
130unsafeFreeze :: MArray s -> ST s Array
131unsafeFreeze MArray{..} = ST $ \s# ->
132 (# s#, Array (unsafeCoerce# maBA)
137{-# INLINE unsafeFreeze #-}
139-- | Indicate how many bytes would be used for an array of the given
141bytesInArray :: Int -> Int
142bytesInArray n = n `shiftL` 1
143{-# INLINE bytesInArray #-}
145-- | Unchecked read of an immutable array. May return garbage or
146-- crash on an out-of-bounds access.
147unsafeIndex :: Array -> Int -> Word16
148unsafeIndex Array{..} i@(I# i#) =
149 CHECK_BOUNDS("unsafeIndex",aLen,i)
150 case indexWord16Array# aBA i# of r# -> (W16# r#)
151{-# INLINE unsafeIndex #-}
153-- | Unchecked write of a mutable array. May return garbage or crash
154-- on an out-of-bounds access.
155unsafeWrite :: MArray s -> Int -> Word16 -> ST s ()
156unsafeWrite MArray{..} i@(I# i#) (W16# e#) = ST $ \s1# ->
157 CHECK_BOUNDS("unsafeWrite",maLen,i)
158 case writeWord16Array# maBA i# e# s1# of
160{-# INLINE unsafeWrite #-}
162-- | Convert an immutable array to a list.
163toList :: Array -> Int -> Int -> [Word16]
164toList ary off len = loop 0
165 where loop i | i < len = unsafeIndex ary (off+i) : loop (i+1)
168-- | An empty immutable array.
170empty = runST (new 0 >>= unsafeFreeze)
172-- | Run an action in the ST monad and return an immutable array of
174run :: (forall s. ST s (MArray s)) -> Array
175run k = runST (k >>= unsafeFreeze)
177-- | Run an action in the ST monad and return an immutable array of
178-- its result paired with whatever else the action returns.
179run2 :: (forall s. ST s (MArray s, a)) -> (Array, a)
182 arr <- unsafeFreeze marr
185-- | Copy some elements of a mutable array.
186copyM :: MArray s -- ^ Destination
187 -> Int -- ^ Destination offset
188 -> MArray s -- ^ Source
189 -> Int -- ^ Source offset
192copyM dest didx src sidx count
193 | count <= 0 = return ()
196 assert (sidx + count <= length src) .
197 assert (didx + count <= length dest) .
199 unsafeIOToST $ memcpyM (maBA dest) (fromIntegral didx)
200 (maBA src) (fromIntegral sidx)
204-- | Copy some elements of an immutable array.
205copyI :: MArray s -- ^ Destination
206 -> Int -- ^ Destination offset
208 -> Int -- ^ Source offset
209 -> Int -- ^ First offset in destination /not/ to
210 -- copy (i.e. /not/ length)
212copyI dest i0 src j0 top
213 | i0 >= top = return ()
214 | otherwise = unsafeIOToST $
215 memcpyI (maBA dest) (fromIntegral i0)
216 (aBA src) (fromIntegral j0)
217 (fromIntegral (top-i0))
220-- | Compare portions of two arrays for equality. No bounds checking
222equal :: Array -- ^ First
223 -> Int -- ^ Offset into first
225 -> Int -- ^ Offset into second
228equal arrA offA arrB offB count = inlinePerformIO $ do
229 i <- memcmp (aBA arrA) (fromIntegral offA)
230 (aBA arrB) (fromIntegral offB) (fromIntegral count)
234foreign import ccall unsafe "_hs_text_memcpy" memcpyI
235 :: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO ()
237foreign import ccall unsafe "_hs_text_memcmp" memcmp
238 :: ByteArray# -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt
240foreign import ccall unsafe "_hs_text_memcpy" memcpyM
241 :: MutableByteArray# s -> CSize -> MutableByteArray# s -> CSize -> CSize
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list