{-# OPTIONS -fno-implicit-prelude #-}
-----------------------------------------------------------------------------
---
+-- |
-- Module : Foreign.Marshal.Array
-- Copyright : (c) The FFI task force 2001
-- License : BSD-style (see the file libraries/core/LICENSE)
--
-- Maintainer : ffi@haskell.org
--- Stability : experimental
--- Portability : non-portable
+-- Stability : provisional
+-- Portability : portable
--
--- $Id: Array.hs,v 1.1 2001/06/28 14:15:03 simonmar Exp $
+-- $Id: Array.hs,v 1.5 2002/04/24 16:31:44 simonmar Exp $
--
-- Marshalling support: routines allocating, storing, and retrieving Haskell
-- lists that are represented as arrays in the foreign language
withArray, -- :: Storable a => [a] -> (Ptr a -> IO b) -> IO b
withArray0, -- :: Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
- -- destruction
- --
- destructArray, -- :: Storable a => Int -> Ptr a -> IO ()
- destructArray0, -- :: (Storable a, Eq a) => a -> Ptr a -> IO ()
-
-- copying (argument order: destination, source)
--
copyArray, -- :: Storable a => Ptr a -> Ptr a -> Int -> IO ()
-- indexing
--
- advancePtr -- :: Storable a => Ptr a -> Int -> Ptr a
+ advancePtr, -- :: Storable a => Ptr a -> Int -> Ptr a
) where
import Control.Monad
#ifdef __GLASGOW_HASKELL__
import Foreign.Ptr (Ptr, plusPtr)
-import GHC.Storable (Storable(sizeOf,peekElemOff,pokeElemOff,destruct))
+import GHC.Storable (Storable(sizeOf,peekElemOff,pokeElemOff))
import Foreign.Marshal.Alloc (mallocBytes, allocaBytes, reallocBytes)
import Foreign.Marshal.Utils (copyBytes, moveBytes)
import GHC.IOBase
-- marshalling
-- -----------
--- convert an array of given length into a Haskell list
+-- convert an array of given length into a Haskell list. This version
+-- traverses the array backwards using an accumulating parameter,
+-- which uses constant stack space. The previous version using mapM
+-- needed linear stack space.
--
peekArray :: Storable a => Int -> Ptr a -> IO [a]
-peekArray size ptr = mapM (peekElemOff ptr) [0..size-1]
-
+peekArray size ptr | size <= 0 = return []
+ | otherwise = f (size-1) []
+ where
+ f 0 acc = do e <- peekElemOff ptr 0; return (e:acc)
+ f n acc = do e <- peekElemOff ptr n; f (n-1) (e:acc)
+
-- convert an array terminated by the given end marker into a Haskell list
--
peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a]
allocaArray len $ \ptr -> do
pokeArray ptr vals
res <- f ptr
- destructArray len ptr
return res
where
len = length vals
allocaArray0 len $ \ptr -> do
pokeArray0 marker ptr vals
res <- f ptr
- destructArray (len+1) ptr
return res
where
len = length vals
--- destruction
--- -----------
-
--- destruct each element of an array (in reverse order)
---
-destructArray :: Storable a => Int -> Ptr a -> IO ()
-destructArray size ptr =
- sequence_ [destruct (ptr `advancePtr` i)
- | i <- [size-1, size-2 .. 0]]
-
--- like `destructArray', but a terminator indicates where the array ends
---
-destructArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO ()
-destructArray0 marker ptr = do
- size <- lengthArray0 marker ptr
- sequence_ [destruct (ptr `advancePtr` i)
- | i <- [size, size-1 .. 0]]
-
-
-- copying (argument order: destination, source)
-- -------