11{-# 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 #-}
35{-# LANGUAGE LambdaCase #-}
46
57{-|
@@ -25,16 +27,26 @@ import GHC.Exts hiding (fromList, toList, Lifted)
2527
2628import Data.Kind (Type )
2729import GHC.IO.Unsafe (unsafeDupablePerformIO )
28- import GHC.Base (IO (IO ), unIO )
30+ import GHC.Base (IO (IO ))
2931
30- data Op a = Set Int # a | Swap Int # Int #
32+ data Op a = Set {- # UNPACK # -} ! Int a | Swap {- # UNPACK # -} ! Int {- # UNPACK # -} ! Int
3133
3234-- | 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
3850
3951instance Show a => Show (Array a ) where
4052 show xs = " fromList " ++ show (toList xs)
@@ -43,150 +55,162 @@ instance Show a => Show (Array a) where
4355aseq :: a -> b -> b
4456aseq x y = x `seq` lazy y
4557
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 # )
4864
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 # )
5467
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, () # )
5870
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
6272
63- readArrayIO :: MutableArray # RealWorld a -> Int # -> IO a
64- readArrayIO arr i = IO (readArray# arr i)
73+ data MutArray a = MA (MutableArray # RealWorld a )
6574
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 ->
7177 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, () # ))
7385
7486-- | Convert a list into an array. O(n)
7587fromList :: [a ] -> Array a
7688fromList xs = unsafeDupablePerformIO $ do
77- let ! (I # n) = length xs
78- Lifted arr <- newArrayIO n undefined
89+ arr0 <- newMutArray (length xs) undefined
7990 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 )
8495
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 ->
8798 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)
89103
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)
94109 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
98113
99114-- | Converting an array into a list. O(n)
100115toList :: 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
104119 go i
105- | isTrue # ( i >=# n) = pure []
120+ | i >= n = pure []
106121 | otherwise = do
107- x <- readArrayIO arr i
108- xs <- go (i +# 1 # )
122+ x <- readMutArray arr i
123+ xs <- go (i + 1 )
109124 pure (x : xs)
110- go 0 #
125+ go 0
111126
112127-- | Indexing an array. O(1)
113128{-# INLINE (!) #-}
114129(!) :: 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
125142
126143-- | Indexing an array. O(1)
127144-- Using the 'Solo' constructor, you can sequence indexing to happen before
128145-- future updates without having to evaluate the element itself.
129146{-# INLINE index #-}
130147index :: 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
134153 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
137156 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
147166 pure (Set i y)
148167
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
157176
158177{-# INLINE appDiffOp #-}
159178appDiffOp :: 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
162182 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')
168188 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'')
174198
175199-- | Update the array element at a given position to a new value. O(1)
176200{-# INLINE set #-}
177201set :: Int -> a -> Array a -> Array a
178- set ( I # i) x = appDiffOp (Set i x)
202+ set i x = appDiffOp (Set i x)
179203
180204-- | Swap two elements in an array. O(1)
181205{-# INLINE swap #-}
182206swap :: Int -> Int -> Array a -> Array a
183- swap ( I # i) ( I # j) = appDiffOp (Swap i j)
207+ swap i j = appDiffOp (Swap i j)
184208
185209-- | Copy an array. O(n)
186210-- This detaches any future updates from old versions of the array.
187211-- Use this when you know you will be updating a large part of an array.
188212copy :: 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