%
-% (c) The GRASP/AQUA Project, Glasgow University, 1997
+% (c) The GRASP/AQUA Project, Glasgow University, 1997-1998
%
\section{Basic ops on packed representations}
subsystem, mostly.
\begin{code}
+{-# OPTIONS -optc-DNON_POSIX_SOURCE #-}
+
+module PrimPacked (
+ Ptr(..), nullPtr, plusAddr#,
+ BA(..),
+ packString, -- :: String -> (Int, BA)
+ unpackNBytesBA, -- :: BA -> Int -> [Char]
+ strLength, -- :: Ptr CChar -> Int
+ copyPrefixStr, -- :: Addr# -> Int -> BA
+ copySubStrBA, -- :: BA -> Int -> Int -> BA
+ eqStrPrefix, -- :: Addr# -> ByteArray# -> Int# -> Bool
+ eqStrPrefixBA, -- :: ByteArray# -> ByteArray# -> Int# -> Int# -> Bool
+ ) where
+
+-- This #define suppresses the "import FastString" that
+-- HsVersions otherwise produces
+#define COMPILING_FAST_STRING
#include "HsVersions.h"
-module PrimPacked
- (
- strLength, -- :: _Addr -> Int
- copyPrefixStr, -- :: _Addr -> Int -> _ByteArray Int
- copySubStr, -- :: _Addr -> Int -> Int -> _ByteArray Int
- copySubStrFO, -- :: ForeignObj -> Int -> Int -> _ByteArray Int
- copySubStrBA, -- :: _ByteArray Int -> Int -> Int -> _ByteArray Int
-
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 205
- stringToByteArray, -- :: String -> _ByteArray Int
- byteArrayToString, -- :: _ByteArray Int -> String
-#endif
-
- eqStrPrefix, -- :: Addr# -> ByteArray# -> Int# -> Bool
- eqCharStrPrefix, -- :: Addr# -> Addr# -> Int# -> Bool
- eqStrPrefixBA, -- :: ByteArray# -> ByteArray# -> Int# -> Int# -> Bool
- eqCharStrPrefixBA, -- :: Addr# -> ByteArray# -> Int# -> Int# -> Bool
- eqStrPrefixFO, -- :: ForeignObj# -> ByteArray# -> Int# -> Int# -> Bool
+import GLAEXTS
+import UNSAFE_IO ( unsafePerformIO )
- addrOffset#, -- :: Addr# -> Int# -> Addr#
- indexCharOffFO# -- :: ForeignObj# -> Int# -> Char#
- ) where
+import MONAD_ST
+import Foreign
-#if __GLASGOW_HASKELL__ <= 201
-import PreludeGlaST
-import PreludeGlaMisc
+#if __GLASGOW_HASKELL__ < 503
+import PrelST
#else
-import GlaExts
-import Foreign
-import GHC
-import ArrBase
-import ST
-import STBase
+import GHC.ST
+#endif
+
+#if __GLASGOW_HASKELL__ >= 504
+import GHC.Ptr ( Ptr(..) )
+#elif __GLASGOW_HASKELL__ >= 500
+import Ptr ( Ptr(..) )
+#endif
-# if __GLASGOW_HASKELL__ == 202
-import PrelBase ( Char(..) )
-# endif
+#if __GLASGOW_HASKELL__ < 504
+import PrelIOBase ( IO(..) )
+#else
+import GHC.IOBase ( IO(..) )
+#endif
+\end{code}
-# if __GLASGOW_HASKELL__ >= 206
-import PackBase
-# endif
+Compatibility: 4.08 didn't have the Ptr type.
-# if __GLASGOW_HASKELL__ >= 209
-import Addr
-# endif
+\begin{code}
+#if __GLASGOW_HASKELL__ <= 408
+data Ptr a = Ptr Addr# deriving (Eq, Ord)
+nullPtr :: Ptr a
+nullPtr = Ptr (int2Addr# 0#)
#endif
-\end{code}
+#if __GLASGOW_HASKELL__ <= 500
+-- plusAddr# is a primop in GHC > 5.00
+plusAddr# :: Addr# -> Int# -> Addr#
+plusAddr# a# i# = int2Addr# (addr2Int# a# +# i#)
+#endif
+\end{code}
-Return the length of a @\\NUL@ terminated character string:
+Wrapper types for bytearrays
\begin{code}
-strLength :: _Addr -> Int
-strLength a =
- unsafePerformPrimIO (
- _ccall_ strlen a `thenPrimIO` \ len@(I# _) ->
- returnPrimIO len
- )
-
+data BA = BA ByteArray#
+data MBA s = MBA (MutableByteArray# s)
\end{code}
-Copying a char string prefix into a byte array,
-{\em assuming} the prefix does not contain any
-NULs.
-
\begin{code}
+packString :: String -> (Int, BA)
+packString str = (l, arr)
+ where
+ l@(I# length#) = length str
-copyPrefixStr :: _Addr -> Int -> _ByteArray Int
-copyPrefixStr (A# a) len@(I# length#) =
- unsafePerformST (
- {- allocate an array that will hold the string
- (not forgetting the NUL at the end)
- -}
- new_ps_array (length# +# 1#) `thenStrictlyST` \ ch_array ->
- -- fill in packed string from "addr"
- fill_in ch_array 0# `thenStrictlyST` \ _ ->
- -- freeze the puppy:
- freeze_ps_array ch_array `thenStrictlyST` \ barr ->
- returnStrictlyST barr )
- where
- fill_in :: _MutableByteArray s Int -> Int# -> _ST s ()
-
- fill_in arr_in# idx
- | idx ==# length#
- = write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
- returnStrictlyST ()
- | otherwise
- = case (indexCharOffAddr# a idx) of { ch ->
- write_ps_array arr_in# idx ch `seqStrictlyST`
- fill_in arr_in# (idx +# 1#) }
+ arr = runST (do
+ ch_array <- new_ps_array length#
+ -- fill in packed string from "str"
+ fill_in ch_array 0# str
+ -- freeze the puppy:
+ freeze_ps_array ch_array length#
+ )
+ fill_in :: MBA s -> Int# -> [Char] -> ST s ()
+ fill_in arr_in# idx [] =
+ return ()
+ fill_in arr_in# idx (C# c : cs) =
+ write_ps_array arr_in# idx c >>
+ fill_in arr_in# (idx +# 1#) cs
\end{code}
-Copying out a substring, assume a 0-indexed string:
-(and positive lengths, thank you).
+Unpacking a string
\begin{code}
-copySubStr :: _Addr -> Int -> Int -> _ByteArray Int
-copySubStr a start length =
- unsafePerformPrimIO (
- _casm_ `` %r= (char *)((char *)%0 + (int)%1); '' a start
- `thenPrimIO` \ a_start ->
- returnPrimIO (copyPrefixStr a_start length))
+unpackNBytesBA :: BA -> Int -> [Char]
+unpackNBytesBA (BA bytes) (I# len)
+ = unpack 0#
+ where
+ unpack nh
+ | nh >=# len = []
+ | otherwise = C# ch : unpack (nh +# 1#)
+ where
+ ch = indexCharArray# bytes nh
\end{code}
-Copying a sub-string out of a ForeignObj
+Copying a char string prefix into a byte array.
\begin{code}
-copySubStrFO :: _ForeignObj -> Int -> Int -> _ByteArray Int
-copySubStrFO (_ForeignObj fo) (I# start#) len@(I# length#) =
- unsafePerformST (
- {- allocate an array that will hold the string
- (not forgetting the NUL at the end)
- -}
- new_ps_array (length# +# 1#) `thenStrictlyST` \ ch_array ->
- -- fill in packed string from "addr"
- fill_in ch_array 0# `seqStrictlyST`
- -- freeze the puppy:
- freeze_ps_array ch_array)
- where
- fill_in :: _MutableByteArray s Int -> Int# -> _ST s ()
-
- fill_in arr_in# idx
+copyPrefixStr :: Addr# -> Int -> BA
+copyPrefixStr a# len@(I# length#) = copy' length#
+ where
+ copy' length# = runST (do
+ {- allocate an array that will hold the string
+ -}
+ ch_array <- new_ps_array length#
+ {- Revert back to Haskell-only solution for the moment.
+ _ccall_ memcpy ch_array (A# a) len >>= \ () ->
+ write_ps_array ch_array length# (chr# 0#) >>
+ -}
+ -- fill in packed string from "addr"
+ fill_in ch_array 0#
+ -- freeze the puppy:
+ freeze_ps_array ch_array length#
+ )
+
+ fill_in :: MBA s -> Int# -> ST s ()
+ fill_in arr_in# idx
| idx ==# length#
- = write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
- returnStrictlyST ()
+ = return ()
| otherwise
- = case (indexCharOffFO# fo (idx +# start#)) of { ch ->
- write_ps_array arr_in# idx ch `seqStrictlyST`
+ = case (indexCharOffAddr# a# idx) of { ch ->
+ write_ps_array arr_in# idx ch >>
fill_in arr_in# (idx +# 1#) }
+\end{code}
-{- ToDo: add FO primitives.. -}
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <=205
-indexCharOffFO# :: ForeignObj# -> Int# -> Char#
-indexCharOffFO# fo# i# =
- case unsafePerformPrimIO (_casm_ ``%r=(char)*((char *)%0 + (int)%1); '' (_ForeignObj fo#) (I# i#)) of
- C# c -> c
-#else
-indexCharOffFO# :: ForeignObj# -> Int# -> Char#
-indexCharOffFO# fo i = indexCharOffForeignObj# fo i
+Copying out a substring, assume a 0-indexed string:
+(and positive lengths, thank you).
+
+\begin{code}
+#ifdef UNUSED
+copySubStr :: Addr# -> Int -> Int -> BA
+copySubStr a# (I# start#) length =
+ copyPrefixStr (a# `plusAddr#` start#) length
#endif
--- step on (char *) pointer by x units.
-addrOffset# :: Addr# -> Int# -> Addr#
-addrOffset# a# i# =
- case unsafePerformPrimIO (_casm_ ``%r=(char *)((char *)%0 + (int)%1); '' (A# a#) (I# i#)) of
- A# a -> a
-
-copySubStrBA :: _ByteArray Int -> Int -> Int -> _ByteArray Int
-copySubStrBA (_ByteArray _ barr#) (I# start#) len@(I# length#) =
- unsafePerformST (
- {- allocate an array that will hold the string
- (not forgetting the NUL at the end)
- -}
- new_ps_array (length# +# 1#) `thenStrictlyST` \ ch_array ->
- -- fill in packed string from "addr"
- fill_in ch_array 0# `seqStrictlyST`
- -- freeze the puppy:
- freeze_ps_array ch_array)
- where
- fill_in :: _MutableByteArray s Int -> Int# -> _ST s ()
-
- fill_in arr_in# idx
+copySubStrBA :: BA -> Int -> Int -> BA
+copySubStrBA (BA barr#) (I# start#) len@(I# length#) = ba
+ where
+ ba = runST (do
+ -- allocate an array that will hold the string
+ ch_array <- new_ps_array length#
+ -- fill in packed string from "addr"
+ fill_in ch_array 0#
+ -- freeze the puppy:
+ freeze_ps_array ch_array length#
+ )
+
+ fill_in :: MBA s -> Int# -> ST s ()
+ fill_in arr_in# idx
| idx ==# length#
- = write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
- returnStrictlyST ()
+ = return ()
| otherwise
= case (indexCharArray# barr# (start# +# idx)) of { ch ->
- write_ps_array arr_in# idx ch `seqStrictlyST`
+ write_ps_array arr_in# idx ch >>
fill_in arr_in# (idx +# 1#) }
-
\end{code}
(Very :-) ``Specialised'' versions of some CharArray things...
+[Copied from PackBase; no real reason -- UGH]
\begin{code}
-new_ps_array :: Int# -> _ST s (_MutableByteArray s Int)
-write_ps_array :: _MutableByteArray s Int -> Int# -> Char# -> _ST s ()
-freeze_ps_array :: _MutableByteArray s Int -> _ST s (_ByteArray Int)
+new_ps_array :: Int# -> ST s (MBA s)
+write_ps_array :: MBA s -> Int# -> Char# -> ST s ()
+freeze_ps_array :: MBA s -> Int# -> ST s BA
+
+#if __GLASGOW_HASKELL__ < 411
+#define NEW_BYTE_ARRAY newCharArray#
+#else
+#define NEW_BYTE_ARRAY newPinnedByteArray#
+#endif
-new_ps_array size =
- MkST ( \ STATE_TOK(s#) ->
- case (newCharArray# size s#) of { StateAndMutableByteArray# s2# barr# ->
- ST_RET(_MutableByteArray (0, max 0 (I# (size -# 1#))) barr#, STATE_TOK(s2#))})
+new_ps_array size = ST $ \ s ->
+ case (NEW_BYTE_ARRAY size s) of { (# s2#, barr# #) ->
+ (# s2#, MBA barr# #) }
-write_ps_array (_MutableByteArray _ barr#) n ch =
- MkST ( \ STATE_TOK(s#) ->
+write_ps_array (MBA barr#) n ch = ST $ \ s# ->
case writeCharArray# barr# n ch s# of { s2# ->
- ST_RET((), STATE_TOK(s2#) )})
+ (# s2#, () #) }
-- same as unsafeFreezeByteArray
-freeze_ps_array (_MutableByteArray ixs arr#) =
- MkST ( \ STATE_TOK(s#) ->
- case unsafeFreezeByteArray# arr# s# of { StateAndByteArray# s2# frozen# ->
- ST_RET((_ByteArray ixs frozen#), STATE_TOK(s2#))})
+freeze_ps_array (MBA arr#) len# = ST $ \ s# ->
+ case unsafeFreezeByteArray# arr# s# of { (# s2#, frozen# #) ->
+ (# s2#, BA frozen# #) }
\end{code}
+
Compare two equal-length strings for equality:
\begin{code}
eqStrPrefix :: Addr# -> ByteArray# -> Int# -> Bool
eqStrPrefix a# barr# len# =
- unsafePerformPrimIO (
- _ccall_ strncmp (A# a#) (_ByteArray bottom barr#) (I# len#) `thenPrimIO` \ (I# x#) ->
- returnPrimIO (x# ==# 0#))
- where
- bottom :: (Int,Int)
- bottom = error "eqStrPrefix"
+ inlinePerformIO $ do
+ x <- memcmp_ba a# barr# (I# len#)
+ return (x == 0)
+#ifdef UNUSED
eqCharStrPrefix :: Addr# -> Addr# -> Int# -> Bool
eqCharStrPrefix a1# a2# len# =
- unsafePerformPrimIO (
- _ccall_ strncmp (A# a1#) (A# a2#) (I# len#) `thenPrimIO` \ (I# x#) ->
- returnPrimIO (x# ==# 0#))
- where
- bottom :: (Int,Int)
- bottom = error "eqStrPrefix"
+ inlinePerformIO $ do
+ x <- memcmp a1# a2# (I# len#)
+ return (x == 0)
+#endif
eqStrPrefixBA :: ByteArray# -> ByteArray# -> Int# -> Int# -> Bool
eqStrPrefixBA b1# b2# start# len# =
- unsafePerformPrimIO (
- _casm_ ``%r=(int)strncmp((char *)%0+(int)%1,%2,%3); ''
- (_ByteArray bottom b2#)
- (I# start#)
- (_ByteArray bottom b1#)
- (I# len#) `thenPrimIO` \ (I# x#) ->
- returnPrimIO (x# ==# 0#))
- where
- bottom :: (Int,Int)
- bottom = error "eqStrPrefixBA"
+ inlinePerformIO $ do
+ x <- memcmp_baoff_ba b2# (I# start#) b1# (I# len#)
+ return (x == 0)
+#ifdef UNUSED
eqCharStrPrefixBA :: Addr# -> ByteArray# -> Int# -> Int# -> Bool
eqCharStrPrefixBA a# b2# start# len# =
- unsafePerformPrimIO (
- _casm_ ``%r=(int)strncmp((char *)%0+(int)%1,%2,%3); ''
- (_ByteArray bottom b2#)
- (I# start#)
- (A# a#)
- (I# len#) `thenPrimIO` \ (I# x#) ->
- returnPrimIO (x# ==# 0#))
- where
- bottom :: (Int,Int)
- bottom = error "eqCharStrPrefixBA"
-
-eqStrPrefixFO :: ForeignObj# -> ByteArray# -> Int# -> Int# -> Bool
-eqStrPrefixFO fo# barr# start# len# =
- unsafePerformPrimIO (
- _casm_ ``%r=(int)strncmp((char *)%0+(int)%1,%2,%3); ''
- (_ForeignObj fo#)
- (I# start#)
- (_ByteArray bottom barr#)
- (I# len#) `thenPrimIO` \ (I# x#) ->
- returnPrimIO (x# ==# 0#))
- where
- bottom :: (Int,Int)
- bottom = error "eqStrPrefixFO"
+ inlinePerformIO $ do
+ x <- memcmp_baoff b2# (I# start#) a# (I# len#)
+ return (x == 0)
+#endif
\end{code}
\begin{code}
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 205
-byteArrayToString :: _ByteArray Int -> String
-byteArrayToString (_ByteArray (I# start#,I# end#) barr#) =
- unpack start#
- where
- unpack nh#
- | nh# >=# end# = []
- | otherwise = C# ch : unpack (nh# +# 1#)
- where
- ch = indexCharArray# barr# nh#
-#elif defined(__GLASGOW_HASKELL__)
-byteArrayToString :: _ByteArray Int -> String
-byteArrayToString = unpackCStringBA
+-- Just like unsafePerformIO, but we inline it. This is safe when
+-- there are no side effects, and improves performance.
+{-# INLINE inlinePerformIO #-}
+inlinePerformIO :: IO a -> a
+inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
+
+#if __GLASGOW_HASKELL__ <= 408
+strLength (Ptr a#) = ghc_strlen a#
+foreign import ccall unsafe "ghc_strlen"
+ ghc_strlen :: Addr# -> Int
#else
-#error "byteArrayToString: cannot handle this!"
+foreign import ccall unsafe "ghc_strlen"
+ strLength :: Ptr () -> Int
#endif
-\end{code}
-
+foreign import ccall unsafe "ghc_memcmp"
+ memcmp :: Addr# -> Addr# -> Int -> IO Int
-\begin{code}
-stringToByteArray :: String -> (_ByteArray Int)
-#if __GLASGOW_HASKELL__ >= 206
-stringToByteArray = packString
-#elif defined(__GLASGOW_HASKELL__)
-stringToByteArray str = _runST (packStringST str)
-
-packStringST :: [Char] -> _ST s (_ByteArray Int)
-packStringST str =
- let len = length str in
- packNCharsST len str
-
-packNCharsST :: Int -> [Char] -> _ST s (_ByteArray Int)
-packNCharsST len@(I# length#) str =
- {-
- allocate an array that will hold the string
- (not forgetting the NUL byte at the end)
- -}
- new_ps_array (length# +# 1#) `thenStrictlyST` \ ch_array ->
- -- fill in packed string from "str"
- fill_in ch_array 0# str `seqStrictlyST`
- -- freeze the puppy:
- freeze_ps_array ch_array `thenStrictlyST` \ (_ByteArray _ frozen#) ->
- returnStrictlyST (_ByteArray (0,len) frozen#)
- where
- fill_in :: _MutableByteArray s Int -> Int# -> [Char] -> _ST s ()
- fill_in arr_in# idx [] =
- write_ps_array arr_in# idx (chr# 0#) `seqStrictlyST`
- returnStrictlyST ()
+foreign import ccall unsafe "ghc_memcmp"
+ memcmp_ba :: Addr# -> ByteArray# -> Int -> IO Int
- fill_in arr_in# idx (C# c : cs) =
- write_ps_array arr_in# idx c `seqStrictlyST`
- fill_in arr_in# (idx +# 1#) cs
-#else
-#error "stringToByteArray: cannot handle this"
-#endif
+foreign import ccall unsafe "ghc_memcmp_off"
+ memcmp_baoff :: ByteArray# -> Int -> Addr# -> Int -> IO Int
+foreign import ccall unsafe "ghc_memcmp_off"
+ memcmp_baoff_ba :: ByteArray# -> Int -> ByteArray# -> Int -> IO Int
\end{code}