[Haskell-cafe] bytestring vs. uvector
Don Stewart
dons at galois.com
Tue Mar 10 17:48:35 EDT 2009
bulat.ziganshin:
> Hello Don,
>
> Wednesday, March 11, 2009, 12:12:07 AM, you wrote:
>
> > Right, so my point stands: there's no difference now. If you can write a
> > Storable instance, you can write a UA et al instance.
>
> yes, if there is some class provided for this and not just hard-coded
> 4 or so base types
That's right. For example (supporting even pairs):
instance (RealFloat a, UA a) => UA (Complex a) where
newtype UArr (Complex a) = UAComplex (UArr (a :*: a))
newtype MUArr (Complex a) s = MUAComplex (MUArr (a :*: a) s)
> > And GHC 6.6 was released what, 11 October 2006? So this has been the
> > case for a long time.
>
> unfortunately, Array library unboxed arrays still aren't based on any
> Unboxable *class*
Hmm. Aren't all the array library types based on MArray and IArray?
So I can define my own say, new STUArray element type by writing an instance of
MArray for it. Like so:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE CPP #-}
-- get at low level representation stuff
import Data.Array.Base
import GHC.IOBase
import GHC.ST ( ST(..), runST )
import GHC.Prim
import GHC.Base
import GHC.Word
import GHC.Ptr
import GHC.Float
import GHC.Stable
import GHC.Int
import GHC.Word
import Data.Array.Unboxed
-- helpers
import Data.Bits
import Text.Printf
import System.Environment
import Control.Monad
-- portable to 32 bit or 64 bit
#include <MachDeps.h>
-- define a new data type we wish to store in unboxed arrays
data Boolean = IsTrue | IsFalse
deriving (Eq, Ord, Enum, Show, Bounded)
-- write a program using an unboxed array of these things
main = do
n <- getArgs >>= readIO . head :: IO Int
mapM_ (\i -> sieve (10000 `shiftL` (n-i))) [0, 1, 2]
-- Nsieve with bit packing of a custom MyBool type.
sieve n = do
let r = runST (do a <- newArray (2,n) IsTrue :: ST s (STUArray s Int Boolean)
go a n 2 0)
printf "Primes up to %8d %8d\n" (n::Int) (r::Int) :: IO ()
go !a !}m !n !c
| n == m = return c
| otherwise = do
e <- unsafeRead a n
if e == IsTrue
then let loop j
| j < m = do
x <- unsafeRead a j
when (x == IsTrue) $ unsafeWrite a j IsFalse
loop (j+n)
| otherwise = go a m (n+1) (c+1)
in loop (n `shiftL` 1)
else go a m (n+1) c
--
-- Create a new unboxed representation for MyBool
-- We choose to use bit packing, storing them in a W#
--
instance MArray (STUArray s) Boolean (ST s) where
getBounds (STUArray l u _ _) = return (l,u)
getNumElements (STUArray _ _ n _) = return n
newArray (l,u) initialValue = ST $ \s1# ->
case safeRangeSize (l,u) of { n@(I# n#) ->
case newByteArray# (bOOL_SCALE n#) s1# of { (# s2#, marr# #) ->
case bOOL_WORD_SCALE n# of { n'# ->
let loop i# s3# | i# ==# n'# = s3#
| otherwise =
case writeWordArray# marr# i# e# s3# of { s4# ->
loop (i# +# 1#) s4# } in
case loop 0# s2# of { s3# ->
(# s3#, STUArray l u n marr# #) }}}}
where
W# e# = if initialValue == IsTrue then maxBound else 0
unsafeNewArray_ (l,u) = unsafeNewArraySTUArray_ (l,u) bOOL_SCALE
newArray_ arrBounds = newArray arrBounds IsFalse
unsafeRead (STUArray _ _ _ marr#) (I# i#) = ST $ \s1# ->
case readWordArray# marr# (bOOL_INDEX i#) s1# of { (# s2#, e# #) ->
(# s2#, case (e# `and#` bOOL_BIT i#) `neWord#` int2Word# 0# of True -> IsTrue ; _ -> IsFalse #) }
unsafeWrite (STUArray _ _ _ marr#) (I# i#) e = ST $ \s1# ->
case bOOL_INDEX i# of { j# ->
case readWordArray# marr# j# s1# of { (# s2#, old# #) ->
case if e == IsTrue then old# `or#` bOOL_BIT i#
else old# `and#` bOOL_NOT_BIT i# of { e# ->
case writeWordArray# marr# j# e# s2# of { s3# ->
(# s3#, () #) }}}}
More information about the Haskell-Cafe
mailing list