1
1
{-# LANGUAGE MagicHash, UnboxedTuples, UnliftedDatatypes #-}
2
- {-# OPTIONS_GHC -Wno-name-shadowing -ddump-simpl -ddump-to-file -dsuppress-all -dno-suppress-type-signatures -dno-typeable-binds #-}
2
+ {-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dsuppress-all -dno-suppress-type-signatures -dno-typeable-binds #-}
3
+ -- O2 is necessary to get the right call pattern specializations and remove all the lifted abstractions
4
+ {-# OPTIONS_GHC -O2 #-}
3
5
{-# LANGUAGE LambdaCase #-}
4
6
5
7
{-|
@@ -25,16 +27,26 @@ import GHC.Exts hiding (fromList, toList, Lifted)
25
27
26
28
import Data.Kind (Type )
27
29
import GHC.IO.Unsafe (unsafeDupablePerformIO )
28
- import GHC.Base (IO (IO ), unIO )
30
+ import GHC.Base (IO (IO ))
29
31
30
- data Op a = Set Int # a | Swap Int # Int #
32
+ data Op a = Set {- # UNPACK # -} ! Int a | Swap {- # UNPACK # -} ! Int {- # UNPACK # -} ! Int
31
33
32
34
-- | Fleet arrays.
33
- data Array a = DA (MutVar # RealWorld (ArrayData a ))
34
- type ArrayData :: Type -> UnliftedType
35
- data ArrayData a
36
- = Current (MutableArray # RealWorld a )
37
- | Diff {- # UNPACK #-} !(Op a ) (MutVar # RealWorld (ArrayData a ))
35
+ data Array a = A {- # UNPACK #-} !(ArrayVar a )
36
+ type ArrayData # :: Type -> UnliftedType
37
+ data ArrayData # a
38
+ = Current # {- # UNPACK #-} !(MutArray a )
39
+ | Diff # {- # UNPACK #-} !(Op a ) {- # UNPACK #-} !(ArrayVar a )
40
+
41
+ data ArrayData a = Current (MutArray a ) | Diff ! (Op a ) ! (ArrayVar a )
42
+
43
+ to# :: ArrayData a -> ArrayData # a
44
+ to# (Current x) = Current # x
45
+ to# (Diff op v) = Diff # op v
46
+
47
+ from# :: ArrayData # a -> ArrayData a
48
+ from# (Current # x) = Current x
49
+ from# (Diff # op v) = Diff op v
38
50
39
51
instance Show a => Show (Array a ) where
40
52
show xs = " fromList " ++ show (toList xs)
@@ -43,150 +55,162 @@ instance Show a => Show (Array a) where
43
55
aseq :: a -> b -> b
44
56
aseq x y = x `seq` lazy y
45
57
46
- type Lifted :: UnliftedType -> Type
47
- data Lifted a = Lifted a
58
+ -- ArrayVar
59
+ data ArrayVar a = AV (MutVar # RealWorld (ArrayData # a ))
60
+ newArrayVar :: ArrayData a -> IO (ArrayVar a )
61
+ newArrayVar x = IO $ \ s ->
62
+ case newMutVar# (to# x) s of
63
+ (# s', v # ) -> (# s', AV v # )
48
64
49
- {-# INLINE newMutVarIO #-}
50
- newMutVarIO :: forall (a :: UnliftedType ). a -> IO (Lifted (MutVar # RealWorld a ))
51
- newMutVarIO x = IO $ \ s ->
52
- case newMutVar# x s of
53
- (# s', v # ) -> (# s', Lifted v # )
65
+ readArrayVar :: ArrayVar a -> IO (ArrayData a )
66
+ readArrayVar (AV v) = IO $ \ s -> case readMutVar# v s of (# s', x # ) -> (# s', from# x # )
54
67
55
- {-# INLINE readMutVarIO #-}
56
- readMutVarIO :: forall (a :: UnliftedType ) b . MutVar # RealWorld a -> (a -> IO b ) -> IO b
57
- readMutVarIO v f = IO (\ s -> case readMutVar# v s of (# s', x # ) -> unIO (f x) s')
68
+ writeArrayVar :: ArrayVar a -> ArrayData a -> IO ()
69
+ writeArrayVar (AV v) x = IO $ \ s -> (# writeMutVar# v (to# x) s, () # )
58
70
59
- {-# INLINE writeMutVarIO #-}
60
- writeMutVarIO :: forall (a :: UnliftedType ). MutVar # RealWorld a -> a -> IO ()
61
- writeMutVarIO v x = IO (\ s -> (# writeMutVar# v x s, () # ))
71
+ -- MutArray
62
72
63
- readArrayIO :: MutableArray # RealWorld a -> Int # -> IO a
64
- readArrayIO arr i = IO (readArray# arr i)
73
+ data MutArray a = MA (MutableArray # RealWorld a )
65
74
66
- writeArrayIO :: MutableArray # RealWorld a -> Int # -> a -> IO ()
67
- writeArrayIO arr i x = IO (\ s -> (# writeArray# arr i x s, () # ))
68
-
69
- newArrayIO :: Int # -> a -> IO (Lifted (MutableArray # RealWorld a ))
70
- newArrayIO n x = IO $ \ s ->
75
+ newMutArray :: Int -> a -> IO (MutArray a )
76
+ newMutArray (I # n) x = IO $ \ s ->
71
77
case newArray# n x s of
72
- (# s', arr # ) -> (# s', Lifted arr # )
78
+ (# s', arr # ) -> (# s', MA arr # )
79
+
80
+ readMutArray :: MutArray a -> Int -> IO a
81
+ readMutArray (MA arr) (I # i) = IO (readArray# arr i)
82
+
83
+ writeMutArray :: MutArray a -> Int -> a -> IO ()
84
+ writeMutArray (MA arr) (I # i) x = IO (\ s -> (# writeArray# arr i x s, () # ))
73
85
74
86
-- | Convert a list into an array. O(n)
75
87
fromList :: [a ] -> Array a
76
88
fromList xs = unsafeDupablePerformIO $ do
77
- let ! (I # n) = length xs
78
- Lifted arr <- newArrayIO n undefined
89
+ arr0 <- newMutArray (length xs) undefined
79
90
let go _ _ [] = pure ()
80
- go arr i (x: xs') = writeArrayIO arr i x >> go arr (i +# 1 # ) xs'
81
- go arr 0 # xs
82
- Lifted var <- newMutVarIO (Current arr )
83
- pure (DA var )
91
+ go arr i (x: xs') = writeMutArray arr i x *> go arr (i + 1 ) xs'
92
+ go arr0 0 xs
93
+ v <- newArrayVar (Current arr0 )
94
+ pure (A v )
84
95
85
- cloneMutableArrayIO :: MutableArray # RealWorld a -> Int # -> Int # -> IO (Lifted ( MutableArray # RealWorld a ) )
86
- cloneMutableArrayIO arr off len = IO $ \ s ->
96
+ cloneMutArray :: MutArray a -> Int -> Int -> IO (MutArray a )
97
+ cloneMutArray ( MA arr) ( I # off) ( I # len) = IO $ \ s ->
87
98
case cloneMutableArray# arr off len s of
88
- (# s', arr' # ) -> (# s', Lifted arr' # )
99
+ (# s', arr' # ) -> (# s', MA arr' # )
100
+
101
+ sizeofMutArray :: MutArray a -> Int
102
+ sizeofMutArray (MA x) = I # (sizeofMutableArray# x)
89
103
90
- copyInternalIO :: MutVar # RealWorld (ArrayData a ) -> IO (Lifted (MutableArray # RealWorld a ))
91
- copyInternalIO v =
92
- readMutVarIO v $ \ case
93
- Current arr -> cloneMutableArrayIO arr 0 # (sizeofMutableArray# arr)
104
+ copyInternal :: ArrayVar a -> IO (MutArray a )
105
+ copyInternal v = do
106
+ av <- readArrayVar v
107
+ case av of
108
+ Current arr -> cloneMutArray arr 0 (sizeofMutArray arr)
94
109
Diff op v' -> do
95
- Lifted clone <- copyInternalIO v'
96
- appOpIO clone op
97
- pure ( Lifted clone)
110
+ clone <- copyInternal v'
111
+ appOp clone op
112
+ pure clone
98
113
99
114
-- | Converting an array into a list. O(n)
100
115
toList :: Array a -> [a ]
101
- toList (DA v) = unsafeDupablePerformIO $ do
102
- Lifted arr <- copyInternalIO v
103
- let n = sizeofMutableArray # arr
116
+ toList (A v) = unsafeDupablePerformIO $ do
117
+ arr <- copyInternal v
118
+ let n = sizeofMutArray arr
104
119
go i
105
- | isTrue # ( i >=# n) = pure []
120
+ | i >= n = pure []
106
121
| otherwise = do
107
- x <- readArrayIO arr i
108
- xs <- go (i +# 1 # )
122
+ x <- readMutArray arr i
123
+ xs <- go (i + 1 )
109
124
pure (x : xs)
110
- go 0 #
125
+ go 0
111
126
112
127
-- | Indexing an array. O(1)
113
128
{-# INLINE (!) #-}
114
129
(!) :: Array a -> Int -> a
115
- DA v ! I # i = unsafeDupablePerformIO (helper v i) where
116
- helper v i = readMutVarIO v $ \ case
117
- Current arr -> readArrayIO arr i
118
- Diff (Set j x) xs
119
- | isTrue# (i ==# j) -> pure x
120
- | otherwise -> helper xs i
121
- Diff (Swap j1 j2) xs
122
- | isTrue# (i ==# j1) -> helper xs j2
123
- | isTrue# (i ==# j2) -> helper xs j1
124
- | otherwise -> helper xs i
130
+ A v0 ! i0 = unsafeDupablePerformIO (go v0 i0) where
131
+ go v i = do
132
+ dat <- readArrayVar v
133
+ case dat of
134
+ Current arr -> readMutArray arr i
135
+ Diff (Set j x) v'
136
+ | i == j -> pure x
137
+ | otherwise -> go v' i
138
+ Diff (Swap j1 j2) v'
139
+ | i == j1 -> go v' j2
140
+ | i == j2 -> go v' j1
141
+ | otherwise -> go v' i
125
142
126
143
-- | Indexing an array. O(1)
127
144
-- Using the 'Solo' constructor, you can sequence indexing to happen before
128
145
-- future updates without having to evaluate the element itself.
129
146
{-# INLINE index #-}
130
147
index :: Int -> Array a -> Solo a
131
- index (I # i) (DA v) = unsafeDupablePerformIO (helper v i) where
132
- helper v i = readMutVarIO v $ \ case
133
- Current arr -> MkSolo <$> readArrayIO arr i
148
+ index i0 (A v0) = unsafeDupablePerformIO (go v0 i0) where
149
+ go v i = do
150
+ dat <- readArrayVar v
151
+ case dat of
152
+ Current arr -> MkSolo <$> readMutArray arr i
134
153
Diff (Set j x) xs
135
- | isTrue # ( i ==# j) -> pure (MkSolo x)
136
- | otherwise -> helper xs i
154
+ | i == j -> pure (MkSolo x)
155
+ | otherwise -> go xs i
137
156
Diff (Swap j1 j2) xs
138
- | isTrue # ( i ==# j1) -> helper xs j2
139
- | isTrue # ( i ==# j2) -> helper xs j1
140
- | otherwise -> helper xs i
141
-
142
- {-# INLINE invertIO #-}
143
- invertIO :: MutableArray # RealWorld a -> Op a -> IO (Op a )
144
- invertIO _ (Swap i j) = pure (Swap i j)
145
- invertIO arr (Set i _) = do
146
- y <- readArrayIO arr i
157
+ | i == j1 -> go xs j2
158
+ | i == j2 -> go xs j1
159
+ | otherwise -> go xs i
160
+
161
+ {-# INLINE invert #-}
162
+ invert :: MutArray a -> Op a -> IO (Op a )
163
+ invert _ (Swap i j) = pure (Swap i j)
164
+ invert arr (Set i _) = do
165
+ y <- readMutArray arr i
147
166
pure (Set i y)
148
167
149
- {-# INLINE appOpIO #-}
150
- appOpIO :: MutableArray # RealWorld a -> Op a -> IO ()
151
- appOpIO arr (Set i x) = writeArrayIO arr i x
152
- appOpIO arr (Swap i j) = do
153
- x <- readArrayIO arr i
154
- y <- readArrayIO arr j
155
- writeArrayIO arr i y
156
- writeArrayIO arr j x
168
+ {-# INLINE appOp #-}
169
+ appOp :: MutArray a -> Op a -> IO ()
170
+ appOp arr (Set i x) = writeMutArray arr i x
171
+ appOp arr (Swap i j) = do
172
+ x <- readMutArray arr i
173
+ y <- readMutArray arr j
174
+ writeMutArray arr i y
175
+ writeMutArray arr j x
157
176
158
177
{-# INLINE appDiffOp #-}
159
178
appDiffOp :: Op a -> Array a -> Array a
160
- appDiffOp op (DA v) = unsafeDupablePerformIO $
161
- readMutVarIO v $ \ case
179
+ appDiffOp op (A v) = unsafeDupablePerformIO $ do
180
+ dat <- readArrayVar v
181
+ case dat of
162
182
xs@ (Current arr) -> do
163
- op' <- invertIO arr op
164
- appOpIO arr op
165
- Lifted v' <- newMutVarIO xs
166
- writeMutVarIO v (Diff op' v')
167
- pure (DA v')
183
+ op' <- invert arr op
184
+ appOp arr op
185
+ v' <- newArrayVar xs
186
+ writeArrayVar v (Diff op' v')
187
+ pure (A v')
168
188
Diff op' v' -> do
169
- Lifted arr <- copyInternalIO v'
170
- appOpIO arr op'
171
- appOpIO arr op
172
- Lifted v'' <- newMutVarIO (Current arr)
173
- pure (DA v'')
189
+ -- TODO: pointer inversion instead of copy
190
+ -- first invert all pointers until Current
191
+ -- then apply all updates until back at v
192
+ -- then do the same as above
193
+ arr <- copyInternal v'
194
+ appOp arr op'
195
+ appOp arr op
196
+ v'' <- newArrayVar (Current arr)
197
+ pure (A v'')
174
198
175
199
-- | Update the array element at a given position to a new value. O(1)
176
200
{-# INLINE set #-}
177
201
set :: Int -> a -> Array a -> Array a
178
- set ( I # i) x = appDiffOp (Set i x)
202
+ set i x = appDiffOp (Set i x)
179
203
180
204
-- | Swap two elements in an array. O(1)
181
205
{-# INLINE swap #-}
182
206
swap :: Int -> Int -> Array a -> Array a
183
- swap ( I # i) ( I # j) = appDiffOp (Swap i j)
207
+ swap i j = appDiffOp (Swap i j)
184
208
185
209
-- | Copy an array. O(n)
186
210
-- This detaches any future updates from old versions of the array.
187
211
-- Use this when you know you will be updating a large part of an array.
188
212
copy :: Array a -> Array a
189
- copy (DA v) = unsafeDupablePerformIO $ do
190
- Lifted arr <- copyInternalIO v
191
- Lifted var <- newMutVarIO (Current arr)
192
- pure (DA var)
213
+ copy (A v) = unsafeDupablePerformIO $ do
214
+ arr <- copyInternal v
215
+ var <- newArrayVar (Current arr)
216
+ pure (A var)
0 commit comments