11{-# LANGUAGE MagicHash, UnboxedTuples, UnliftedDatatypes #-}
22{-# OPTIONS_GHC -Wno-name-shadowing -ddump-simpl -ddump-to-file -dsuppress-all -dno-suppress-type-signatures -dno-typeable-binds #-}
3+ {-# LANGUAGE LambdaCase #-}
34
45{-|
56Module : Fleet.Array
@@ -19,10 +20,12 @@ latest version.
1920-}
2021module Fleet.Array (Array , fromList , toList , (!) , index , set , copy , swap , aseq ) where
2122
22- import GHC.Exts hiding (fromList , toList )
2323import Data.Tuple (Solo (MkSolo ))
24+ import GHC.Exts hiding (fromList , toList , Lifted )
2425
2526import Data.Kind (Type )
27+ import GHC.IO.Unsafe (unsafeDupablePerformIO )
28+ import GHC.Base (IO (IO ), unIO )
2629
2730data Op a = Set Int # a | Swap Int # Int #
2831
@@ -40,42 +43,82 @@ instance Show a => Show (Array a) where
4043aseq :: a -> b -> b
4144aseq x y = x `seq` lazy y
4245
46+ type Lifted :: UnliftedType -> Type
47+ data Lifted a = Lifted a
48+
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 # )
54+
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')
58+
59+ {-# INLINE writeMutVarIO #-}
60+ writeMutVarIO :: forall (a :: UnliftedType ). MutVar # RealWorld a -> a -> IO ()
61+ writeMutVarIO v x = IO (\ s -> (# writeMutVar# v x s, () # ))
62+
63+ readArrayIO :: MutableArray # RealWorld a -> Int # -> IO a
64+ readArrayIO arr i = IO (readArray# arr i)
65+
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 ->
71+ case newArray# n x s of
72+ (# s', arr # ) -> (# s', Lifted arr # )
73+
4374-- | Convert a list into an array. O(n)
4475fromList :: [a ] -> Array a
45- fromList xs = DA (runRW# $ \ s ->
46- case newArray# (case length xs of (I # n) -> n) undefined s of { (# s , arr # ) ->
47- case newMutVar# (Current arr) (go arr 0 # xs s) of { (# _ , x # ) -> x
48- }}) where
49- go _ _ [] s = s
50- go arr i (x: xs) s = go arr (i +# 1 # ) xs (writeArray# arr i x s)
76+ fromList xs = unsafeDupablePerformIO $ do
77+ let ! (I # n) = length xs
78+ Lifted arr <- newArrayIO n undefined
79+ 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)
84+
85+ cloneMutableArrayIO :: MutableArray # RealWorld a -> Int # -> Int # -> IO (Lifted (MutableArray # RealWorld a ))
86+ cloneMutableArrayIO arr off len = IO $ \ s ->
87+ case cloneMutableArray# arr off len s of
88+ (# s', arr' # ) -> (# s', Lifted arr' # )
89+
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)
94+ Diff op v' -> do
95+ Lifted clone <- copyInternalIO v'
96+ appOpIO clone op
97+ pure (Lifted clone)
5198
5299-- | Converting an array into a list. O(n)
53100toList :: Array a -> [a ]
54- toList (DA v) = runRW# $ \ s ->
55- case copyInternal v s of { (# s, arr # ) ->
56- let
57- n = sizeofMutableArray# arr
58- go i s
59- | isTrue# (i >=# n) = []
60- | otherwise =
61- case readArray# arr i s of
62- { (# s, x # ) -> x : go (i +# 1 # ) s
63- }
64- in go 0 # s
65- }
101+ toList (DA v) = unsafeDupablePerformIO $ do
102+ Lifted arr <- copyInternalIO v
103+ let n = sizeofMutableArray# arr
104+ go i
105+ | isTrue# (i >=# n) = pure []
106+ | otherwise = do
107+ x <- readArrayIO arr i
108+ xs <- go (i +# 1 # )
109+ pure (x : xs)
110+ go 0 #
66111
67112-- | Indexing an array. O(1)
68113{-# INLINE (!) #-}
69114(!) :: Array a -> Int -> a
70- DA v ! I # i = helper v i where
71- helper v i = runRW# $ \ s ->
72- case readMutVar# v s of
73- (# s , Current arr # ) ->
74- case readArray# arr i s of (# _ , x # ) -> x
75- (# _ , Diff (Set j x) xs # )
76- | isTrue# (i ==# j) -> x
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
77120 | otherwise -> helper xs i
78- ( # _ , Diff (Swap j1 j2) xs # )
121+ Diff (Swap j1 j2) xs
79122 | isTrue# (i ==# j1) -> helper xs j2
80123 | isTrue# (i ==# j2) -> helper xs j1
81124 | otherwise -> helper xs i
@@ -85,78 +128,49 @@ DA v ! I# i = helper v i where
85128-- future updates without having to evaluate the element itself.
86129{-# INLINE index #-}
87130index :: Int -> Array a -> Solo a
88- index (I # i) (DA v) = helper v i where
89- helper v i = runRW# $ \ s ->
90- case readMutVar# v s of
91- (# s , Current arr # ) ->
92- case readArray# arr i s of (# _ , x # ) -> MkSolo x
93- (# _ , Diff (Set j x) xs # )
94- | isTrue# (i ==# j) -> MkSolo x
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
134+ Diff (Set j x) xs
135+ | isTrue# (i ==# j) -> pure (MkSolo x)
95136 | otherwise -> helper xs i
96- ( # _ , Diff (Swap j1 j2) xs # )
137+ Diff (Swap j1 j2) xs
97138 | isTrue# (i ==# j1) -> helper xs j2
98139 | isTrue# (i ==# j2) -> helper xs j1
99140 | otherwise -> helper xs i
100141
101- {-# INLINE appOp #-}
102- appOp :: MutableArray # RealWorld a -> Op a -> State # RealWorld -> State # RealWorld
103- appOp arr (Set i x) s = writeArray# arr i x s
104- appOp arr (Swap i j) s =
105- case readArray# arr i s of { (# s, x # ) ->
106- case readArray# arr j s of { (# s, y # ) ->
107- case writeArray# arr i y s of { s ->
108- writeArray# arr j x s
109- }}}
110-
111- {-# INLINE invert #-}
112- invert :: MutableArray # RealWorld a -> Op a -> State # RealWorld -> (# State # RealWorld , Op a # )
113- invert _ (Swap i j) s = (# s , Swap i j # )
114- invert arr (Set i _) s =
115- case readArray# arr i s of { (# s, y # ) ->
116- (# s, Set i y # ) }
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
147+ pure (Set i y)
148+
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
117157
118158{-# INLINE appDiffOp #-}
119159appDiffOp :: Op a -> Array a -> Array a
120- appDiffOp op (DA v) = runRW# $ \ s ->
121- case noDuplicate# s of { s ->
122- case readMutVar# v s of
123- (# s , xs@ (Current arr) # ) ->
124- case invert arr op s of { (# s, op' # ) ->
125- case appOp arr op s of { s ->
126- case newMutVar# xs s of { (# s , v' # ) ->
127- case writeMutVar# v (Diff op' v') s of { ! _ ->
128- DA v'
129- }}}}
130- -- making a change to an old version of the array
131- -- we copy to anticipate more usage
132- (# s, Diff op' v' # ) ->
133- case copyInternal v' s of { (# s , arr # ) ->
134- case appOp arr op' s of { s ->
135- case appOp arr op s of { s ->
136- case newMutVar# (Current arr) s of { (# _ , v'' # ) ->
137- DA v''
138- }}}}}
139-
140- -- {-# INLINE appUndoOp #-}
141- -- appUndoOp :: Op a -> Array a -> Array a
142- -- appUndoOp op (DA v) = runRW# $ \s ->
143- -- case readMutVar# v s of
144- -- (# s , xs@(Current arr) #) ->
145- -- case invert arr op s of { (# s, op' #) ->
146- -- case appOp arr op s of { s ->
147- -- case newMutVar# xs s of { (# s , v' #) ->
148- -- case writeMutVar# v (Diff op' v') s of { !_ ->
149- -- DA v'
150- -- }}}}
151- -- -- making a change to an old version of the array
152- -- -- we roll back all changes
153- -- (# s, Diff op' v' #) ->
154- -- case appUndoOp ov' s of { (# s , arr #) ->
155- -- case appOp arr op s of { s ->
156- -- case appOp arr op s of { s ->
157- -- case newMutVar# (Current arr) s of { (# _ , v'' #) ->
158- -- DA v''
159- -- }}}}
160+ appDiffOp op (DA v) = unsafeDupablePerformIO $
161+ readMutVarIO v $ \ case
162+ 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')
168+ 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'')
160174
161175-- | Update the array element at a given position to a new value. O(1)
162176{-# INLINE set #-}
@@ -168,21 +182,11 @@ set (I# i) x = appDiffOp (Set i x)
168182swap :: Int -> Int -> Array a -> Array a
169183swap (I # i) (I # j) = appDiffOp (Swap i j)
170184
171- copyInternal :: MutVar # RealWorld (ArrayData a ) -> State # RealWorld -> (# State # RealWorld , MutableArray # RealWorld a # )
172- copyInternal v s =
173- case readMutVar# v s of
174- (# s , Current arr # ) ->
175- cloneMutableArray# arr 0 # (sizeofMutableArray# arr) s
176- (# s , Diff op v # ) ->
177- case copyInternal v s of { (# s , arr # ) ->
178- case appOp arr op s of { s -> (# s , arr # )
179- }}
180-
181185-- | Copy an array. O(n)
182186-- This detaches any future updates from old versions of the array.
183187-- Use this when you know you will be updating a large part of an array.
184188copy :: Array a -> Array a
185- copy (DA v) = runRW # $ \ s ->
186- case copyInternal v s of { ( # s , arr # ) ->
187- case newMutVar # (Current arr) s of { ( # _, v # ) -> DA v
188- }}
189+ copy (DA v) = unsafeDupablePerformIO $ do
190+ Lifted arr <- copyInternalIO v
191+ Lifted var <- newMutVarIO (Current arr)
192+ pure ( DA var)
0 commit comments