SafeHaskell: Added SafeHaskell to base
[ghc.git] / libraries / base / Foreign / Marshal / Pool.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE CPP, NoImplicitPrelude #-}
3
4 --------------------------------------------------------------------------------
5 -- |
6 -- Module : Foreign.Marshal.Pool
7 -- Copyright : (c) Sven Panne 2002-2004
8 -- License : BSD-style (see the file libraries/base/LICENSE)
9 --
10 -- Maintainer : sven.panne@aedion.de
11 -- Stability : provisional
12 -- Portability : portable
13 --
14 -- This module contains support for pooled memory management. Under this scheme,
15 -- (re-)allocations belong to a given pool, and everything in a pool is
16 -- deallocated when the pool itself is deallocated. This is useful when
17 -- 'Foreign.Marshal.Alloc.alloca' with its implicit allocation and deallocation
18 -- is not flexible enough, but explicit uses of 'Foreign.Marshal.Alloc.malloc'
19 -- and 'free' are too awkward.
20 --
21 --------------------------------------------------------------------------------
22
23 module Foreign.Marshal.Pool (
24 -- * Pool management
25 Pool,
26 newPool, -- :: IO Pool
27 freePool, -- :: Pool -> IO ()
28 withPool, -- :: (Pool -> IO b) -> IO b
29
30 -- * (Re-)Allocation within a pool
31 pooledMalloc, -- :: Storable a => Pool -> IO (Ptr a)
32 pooledMallocBytes, -- :: Pool -> Int -> IO (Ptr a)
33
34 pooledRealloc, -- :: Storable a => Pool -> Ptr a -> IO (Ptr a)
35 pooledReallocBytes, -- :: Pool -> Ptr a -> Int -> IO (Ptr a)
36
37 pooledMallocArray, -- :: Storable a => Pool -> Int -> IO (Ptr a)
38 pooledMallocArray0, -- :: Storable a => Pool -> Int -> IO (Ptr a)
39
40 pooledReallocArray, -- :: Storable a => Pool -> Ptr a -> Int -> IO (Ptr a)
41 pooledReallocArray0, -- :: Storable a => Pool -> Ptr a -> Int -> IO (Ptr a)
42
43 -- * Combined allocation and marshalling
44 pooledNew, -- :: Storable a => Pool -> a -> IO (Ptr a)
45 pooledNewArray, -- :: Storable a => Pool -> [a] -> IO (Ptr a)
46 pooledNewArray0 -- :: Storable a => Pool -> a -> [a] -> IO (Ptr a)
47 ) where
48
49 #ifdef __GLASGOW_HASKELL__
50 import GHC.Base ( Int, Monad(..), (.), not )
51 import GHC.Err ( undefined )
52 import GHC.Exception ( throw )
53 import GHC.IO ( IO, mask, catchAny )
54 import GHC.IORef ( IORef, newIORef, readIORef, writeIORef )
55 import GHC.List ( elem, length )
56 import GHC.Num ( Num(..) )
57 #else
58 import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
59 #if defined(__NHC__)
60 import IO ( bracket )
61 #else
62 import Control.Exception.Base ( bracket )
63 #endif
64 #endif
65
66 import Control.Monad ( liftM )
67 import Data.List ( delete )
68 import Foreign.Marshal.Alloc ( mallocBytes, reallocBytes, free )
69 import Foreign.Marshal.Array ( pokeArray, pokeArray0 )
70 import Foreign.Marshal.Error ( throwIf )
71 import Foreign.Ptr ( Ptr, castPtr )
72 import Foreign.Storable ( Storable(sizeOf, poke) )
73
74 --------------------------------------------------------------------------------
75
76 -- To avoid non-H98 stuff like existentially quantified data constructors, we
77 -- simply use pointers to () below. Not very nice, but...
78
79 -- | A memory pool.
80
81 newtype Pool = Pool (IORef [Ptr ()])
82
83 -- | Allocate a fresh memory pool.
84
85 newPool :: IO Pool
86 newPool = liftM Pool (newIORef [])
87
88 -- | Deallocate a memory pool and everything which has been allocated in the
89 -- pool itself.
90
91 freePool :: Pool -> IO ()
92 freePool (Pool pool) = readIORef pool >>= freeAll
93 where freeAll [] = return ()
94 freeAll (p:ps) = free p >> freeAll ps
95
96 -- | Execute an action with a fresh memory pool, which gets automatically
97 -- deallocated (including its contents) after the action has finished.
98
99 withPool :: (Pool -> IO b) -> IO b
100 #ifdef __GLASGOW_HASKELL__
101 withPool act = -- ATTENTION: cut-n-paste from Control.Exception below!
102 mask (\restore -> do
103 pool <- newPool
104 val <- catchAny
105 (restore (act pool))
106 (\e -> do freePool pool; throw e)
107 freePool pool
108 return val)
109 #else
110 withPool = bracket newPool freePool
111 #endif
112
113 --------------------------------------------------------------------------------
114
115 -- | Allocate space for storable type in the given pool. The size of the area
116 -- allocated is determined by the 'sizeOf' method from the instance of
117 -- 'Storable' for the appropriate type.
118
119 pooledMalloc :: Storable a => Pool -> IO (Ptr a)
120 pooledMalloc = pm undefined
121 where
122 pm :: Storable a' => a' -> Pool -> IO (Ptr a')
123 pm dummy pool = pooledMallocBytes pool (sizeOf dummy)
124
125 -- | Allocate the given number of bytes of storage in the pool.
126
127 pooledMallocBytes :: Pool -> Int -> IO (Ptr a)
128 pooledMallocBytes (Pool pool) size = do
129 ptr <- mallocBytes size
130 ptrs <- readIORef pool
131 writeIORef pool (ptr:ptrs)
132 return (castPtr ptr)
133
134 -- | Adjust the storage area for an element in the pool to the given size of
135 -- the required type.
136
137 pooledRealloc :: Storable a => Pool -> Ptr a -> IO (Ptr a)
138 pooledRealloc = pr undefined
139 where
140 pr :: Storable a' => a' -> Pool -> Ptr a' -> IO (Ptr a')
141 pr dummy pool ptr = pooledReallocBytes pool ptr (sizeOf dummy)
142
143 -- | Adjust the storage area for an element in the pool to the given size.
144
145 pooledReallocBytes :: Pool -> Ptr a -> Int -> IO (Ptr a)
146 pooledReallocBytes (Pool pool) ptr size = do
147 let cPtr = castPtr ptr
148 _ <- throwIf (not . (cPtr `elem`)) (\_ -> "pointer not in pool") (readIORef pool)
149 newPtr <- reallocBytes cPtr size
150 ptrs <- readIORef pool
151 writeIORef pool (newPtr : delete cPtr ptrs)
152 return (castPtr newPtr)
153
154 -- | Allocate storage for the given number of elements of a storable type in the
155 -- pool.
156
157 pooledMallocArray :: Storable a => Pool -> Int -> IO (Ptr a)
158 pooledMallocArray = pma undefined
159 where
160 pma :: Storable a' => a' -> Pool -> Int -> IO (Ptr a')
161 pma dummy pool size = pooledMallocBytes pool (size * sizeOf dummy)
162
163 -- | Allocate storage for the given number of elements of a storable type in the
164 -- pool, but leave room for an extra element to signal the end of the array.
165
166 pooledMallocArray0 :: Storable a => Pool -> Int -> IO (Ptr a)
167 pooledMallocArray0 pool size =
168 pooledMallocArray pool (size + 1)
169
170 -- | Adjust the size of an array in the given pool.
171
172 pooledReallocArray :: Storable a => Pool -> Ptr a -> Int -> IO (Ptr a)
173 pooledReallocArray = pra undefined
174 where
175 pra :: Storable a' => a' -> Pool -> Ptr a' -> Int -> IO (Ptr a')
176 pra dummy pool ptr size = pooledReallocBytes pool ptr (size * sizeOf dummy)
177
178 -- | Adjust the size of an array with an end marker in the given pool.
179
180 pooledReallocArray0 :: Storable a => Pool -> Ptr a -> Int -> IO (Ptr a)
181 pooledReallocArray0 pool ptr size =
182 pooledReallocArray pool ptr (size + 1)
183
184 --------------------------------------------------------------------------------
185
186 -- | Allocate storage for a value in the given pool and marshal the value into
187 -- this storage.
188
189 pooledNew :: Storable a => Pool -> a -> IO (Ptr a)
190 pooledNew pool val = do
191 ptr <- pooledMalloc pool
192 poke ptr val
193 return ptr
194
195 -- | Allocate consecutive storage for a list of values in the given pool and
196 -- marshal these values into it.
197
198 pooledNewArray :: Storable a => Pool -> [a] -> IO (Ptr a)
199 pooledNewArray pool vals = do
200 ptr <- pooledMallocArray pool (length vals)
201 pokeArray ptr vals
202 return ptr
203
204 -- | Allocate consecutive storage for a list of values in the given pool and
205 -- marshal these values into it, terminating the end with the given marker.
206
207 pooledNewArray0 :: Storable a => Pool -> a -> [a] -> IO (Ptr a)
208 pooledNewArray0 pool marker vals = do
209 ptr <- pooledMallocArray0 pool (length vals)
210 pokeArray0 marker ptr vals
211 return ptr