Allow streams to produce entire vectors as well as individual elements
[darcs-mirrors/vector.git] / Data / Vector / Generic / Mutable / Base.hs
1 {-# LANGUAGE MultiParamTypeClasses, BangPatterns #-}
2 -- |
3 -- Module : Data.Vector.Generic.Mutable.Base
4 -- Copyright : (c) Roman Leshchinskiy 2008-2011
5 -- License : BSD-style
6 --
7 -- Maintainer : Roman Leshchinskiy <rl@cse.unsw.edu.au>
8 -- Stability : experimental
9 -- Portability : non-portable
10 --
11 -- Class of mutable vectors
12 --
13
14 module Data.Vector.Generic.Mutable.Base (
15 MVector(..)
16 ) where
17
18 import Control.Monad.Primitive ( PrimMonad, PrimState )
19
20 #include "vector.h"
21
22 -- | Class of mutable vectors parametrised with a primitive state token.
23 --
24 class MVector v a where
25 -- | Length of the mutable vector. This method should not be
26 -- called directly, use 'length' instead.
27 basicLength :: v s a -> Int
28
29 -- | Yield a part of the mutable vector without copying it. This method
30 -- should not be called directly, use 'unsafeSlice' instead.
31 basicUnsafeSlice :: Int -- ^ starting index
32 -> Int -- ^ length of the slice
33 -> v s a
34 -> v s a
35
36 -- Check whether two vectors overlap. This method should not be
37 -- called directly, use 'overlaps' instead.
38 basicOverlaps :: v s a -> v s a -> Bool
39
40 -- | Create a mutable vector of the given length. This method should not be
41 -- called directly, use 'unsafeNew' instead.
42 basicUnsafeNew :: PrimMonad m => Int -> m (v (PrimState m) a)
43
44 -- | Create a mutable vector of the given length and fill it with an
45 -- initial value. This method should not be called directly, use
46 -- 'replicate' instead.
47 basicUnsafeReplicate :: PrimMonad m => Int -> a -> m (v (PrimState m) a)
48
49 -- | Yield the element at the given position. This method should not be
50 -- called directly, use 'unsafeRead' instead.
51 basicUnsafeRead :: PrimMonad m => v (PrimState m) a -> Int -> m a
52
53 -- | Replace the element at the given position. This method should not be
54 -- called directly, use 'unsafeWrite' instead.
55 basicUnsafeWrite :: PrimMonad m => v (PrimState m) a -> Int -> a -> m ()
56
57 -- | Reset all elements of the vector to some undefined value, clearing all
58 -- references to external objects. This is usually a noop for unboxed
59 -- vectors. This method should not be called directly, use 'clear' instead.
60 basicClear :: PrimMonad m => v (PrimState m) a -> m ()
61
62 -- | Set all elements of the vector to the given value. This method should
63 -- not be called directly, use 'set' instead.
64 basicSet :: PrimMonad m => v (PrimState m) a -> a -> m ()
65
66 -- | Copy a vector. The two vectors may not overlap. This method should not
67 -- be called directly, use 'unsafeCopy' instead.
68 basicUnsafeCopy :: PrimMonad m => v (PrimState m) a -- ^ target
69 -> v (PrimState m) a -- ^ source
70 -> m ()
71
72 -- | Move the contents of a vector. The two vectors may overlap. This method
73 -- should not be called directly, use 'unsafeMove' instead.
74 basicUnsafeMove :: PrimMonad m => v (PrimState m) a -- ^ target
75 -> v (PrimState m) a -- ^ source
76 -> m ()
77
78 -- | Grow a vector by the given number of elements. This method should not be
79 -- called directly, use 'unsafeGrow' instead.
80 basicUnsafeGrow :: PrimMonad m => v (PrimState m) a -> Int
81 -> m (v (PrimState m) a)
82
83 {-# INLINE basicUnsafeReplicate #-}
84 basicUnsafeReplicate n x
85 = do
86 v <- basicUnsafeNew n
87 basicSet v x
88 return v
89
90 {-# INLINE basicClear #-}
91 basicClear _ = return ()
92
93 {-# INLINE basicSet #-}
94 basicSet !v x
95 | n == 0 = return ()
96 | otherwise = do
97 basicUnsafeWrite v 0 x
98 do_set 1
99 where
100 !n = basicLength v
101
102 do_set i | 2*i < n = do basicUnsafeCopy (basicUnsafeSlice i i v)
103 (basicUnsafeSlice 0 i v)
104 do_set (2*i)
105 | otherwise = basicUnsafeCopy (basicUnsafeSlice i (n-i) v)
106 (basicUnsafeSlice 0 (n-i) v)
107
108 {-# INLINE basicUnsafeCopy #-}
109 basicUnsafeCopy !dst !src = do_copy 0
110 where
111 !n = basicLength src
112
113 do_copy i | i < n = do
114 x <- basicUnsafeRead src i
115 basicUnsafeWrite dst i x
116 do_copy (i+1)
117 | otherwise = return ()
118
119 {-# INLINE basicUnsafeMove #-}
120 basicUnsafeMove !dst !src
121 | basicOverlaps dst src = do
122 srcCopy <- basicUnsafeNew (basicLength src)
123 basicUnsafeCopy srcCopy src
124 basicUnsafeCopy dst srcCopy
125 | otherwise = basicUnsafeCopy dst src
126
127 {-# INLINE basicUnsafeGrow #-}
128 basicUnsafeGrow v by
129 = do
130 v' <- basicUnsafeNew (n+by)
131 basicUnsafeCopy (basicUnsafeSlice 0 n v') v
132 return v'
133 where
134 n = basicLength v
135