-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDynamicVector.hs
More file actions
78 lines (66 loc) · 2.71 KB
/
DynamicVector.hs
File metadata and controls
78 lines (66 loc) · 2.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
module DynamicVector
( DynamicVector
, new, length, append, unsafeRead, unsafeWrite, freeze, imap_
, printVector
) where
import Control.Applicative
import Data.IORef
import Data.Vector (Vector)
import Data.Vector.Mutable (IOVector)
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as VM
import Prelude hiding (length)
-- TODO: doubling strategy as parameter
-- (resoltuion proofs tend to be around the length of the cnf,
-- so initializing with that & then growing w/ 100 or so could be good)
-- | A mutable vector in the IO monad that grows automatically to accomodate
-- its elements. The growth strategy is to simply double the internal size
-- of the vector once it is full.
data DynamicVector a = DynamicVector (IORef (IOVector a)) (IORef Int)
-- | Create a dynamic vector with the given initial capacity.
new :: Int -> IO (DynamicVector a)
new m = do
vref <- newIORef =<< VM.new m
nref <- newIORef 0
return $ DynamicVector vref nref
-- | Length of the dynamic vector. (This is the number of actual elements
-- in the vector. The amount of storage consumed may be higher.)
length :: DynamicVector a -> IO Int
length (DynamicVector _ nref) = readIORef nref
-- | Append an item to the vector. May double the storage claimed by the vector.
append :: DynamicVector a -> a -> IO ()
append (DynamicVector vref nref) x = do
v <- readIORef vref
n <- readIORef nref
if n < VM.length v
then VM.unsafeWrite v n x
else do v' <- VM.unsafeGrow v n
writeIORef vref v'
VM.unsafeWrite v' n x
writeIORef nref (n+1)
-- | Yield the element at the given position. No bounds checks are performed.
unsafeRead :: DynamicVector a -> Int -> IO a
unsafeRead (DynamicVector vref _) i = do
v <- readIORef vref
VM.unsafeRead v i
-- | Replace the element at the given position. No bounds checks are performed.
unsafeWrite :: DynamicVector a -> Int -> a -> IO ()
unsafeWrite (DynamicVector vref _) i x = do
v <- readIORef vref
VM.unsafeWrite v i x
-- | /O(n)/ Yield an immutable copy.
freeze :: DynamicVector a -> IO (Vector a)
freeze dv = V.freeze =<< activeSlice dv
-- | /O(n)/ Apply the IO action to every element of the vector and its index
-- and ignore the results.
imap_ :: (Int -> a -> IO b) -> DynamicVector a -> IO ()
imap_ f dv = go 0 f =<< V.toList <$> (V.unsafeFreeze =<< activeSlice dv)
where
go _ _ [] = return ()
go n f (x:xs) = f n x >> go (n+1) f xs
activeSlice :: DynamicVector a -> IO (IOVector a)
activeSlice (DynamicVector vref nref) =
VM.unsafeSlice 0 <$> readIORef nref <*> readIORef vref
printVector :: Show a => DynamicVector a -> IO ()
printVector v = flip imap_ v $ \i x -> do
putStrLn (show i ++ ": " ++ show x)