Skip to content

Commit 9b4d561

Browse files
authored
Merge pull request #494 from IntersectMBO/wenkokke/rc-fundep
Use functional dependencies rather than type families to enable SPECIALISE
2 parents 21f4bf7 + 2eeabd6 commit 9b4d561

File tree

6 files changed

+57
-35
lines changed

6 files changed

+57
-35
lines changed

src-control/Control/RefCount.hs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
{-# LANGUAGE CPP #-}
2-
{-# LANGUAGE DefaultSignatures #-}
3-
{-# LANGUAGE MagicHash #-}
4-
{-# LANGUAGE PatternSynonyms #-}
5-
{-# LANGUAGE TypeFamilies #-}
1+
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE DefaultSignatures #-}
3+
{-# LANGUAGE FunctionalDependencies #-}
4+
{-# LANGUAGE MagicHash #-}
5+
{-# LANGUAGE PatternSynonyms #-}
6+
{-# LANGUAGE TypeFamilies #-}
67

78
module Control.RefCount (
89
-- * Using references
@@ -30,15 +31,12 @@ module Control.RefCount (
3031
, checkForgottenRefs
3132
) where
3233

33-
import Data.Kind (Type)
34-
import Data.Primitive.PrimVar
35-
3634
import Control.DeepSeq
3735
import Control.Exception (assert)
3836
import Control.Monad (when)
3937
import Control.Monad.Class.MonadThrow
4038
import Control.Monad.Primitive
41-
39+
import Data.Primitive.PrimVar
4240
import GHC.Stack (CallStack, prettyCallStack)
4341

4442
#ifdef NO_IGNORE_ASSERTS
@@ -195,30 +193,36 @@ instance NFData obj => NFData (Ref obj) where
195193
-- For objects in this class the guarantee is that (when the 'Ref' rules are
196194
-- followed) the object's finaliser is called exactly once.
197195
--
198-
class RefCounted obj where
199-
type FinaliserM obj :: Type -> Type
200-
getRefCounter :: obj -> RefCounter (FinaliserM obj)
196+
class RefCounted m obj | obj -> m where
197+
getRefCounter :: obj -> RefCounter m
201198

202199
#ifdef NO_IGNORE_ASSERTS
203200
#define HasCallStackIfDebug HasCallStack
204201
#else
205202
#define HasCallStackIfDebug ()
206203
#endif
207204

208-
-- GHC says specialising is too complicated! But it's ok, each of these can
209-
-- inline to calling a few other specialised helpers.
210-
{-# INLINE newRef #-}
211-
{-# INLINE releaseRef #-}
212-
{-# INLINE dupRef #-}
213-
{-# INLINE deRefWeak #-}
214-
205+
{-# SPECIALISE
206+
newRef ::
207+
RefCounted IO obj
208+
=> IO ()
209+
-> (RefCounter IO -> obj)
210+
-> IO (Ref obj)
211+
#-}
215212
-- | Make a new reference.
216213
--
217214
-- The given finaliser is run when the last reference is released. The
218215
-- finaliser is run with async exceptions masked.
219216
--
217+
{-# SPECIALISE
218+
newRef ::
219+
RefCounted IO obj
220+
=> IO ()
221+
-> (RefCounter IO -> obj)
222+
-> IO (Ref obj)
223+
#-}
220224
newRef ::
221-
(RefCounted obj, FinaliserM obj ~ m, PrimMonad m)
225+
(RefCounted m obj, PrimMonad m)
222226
=> HasCallStackIfDebug
223227
=> m ()
224228
-> (RefCounter m -> obj)
@@ -232,8 +236,14 @@ newRef finaliser mkObject = do
232236
-- | Release a reference to an object that will no longer be used (via this
233237
-- reference).
234238
--
239+
{-# SPECIALISE
240+
releaseRef ::
241+
RefCounted IO obj
242+
=> Ref obj
243+
-> IO ()
244+
#-}
235245
releaseRef ::
236-
(RefCounted obj, FinaliserM obj ~ m, PrimMonad m, MonadMask m)
246+
(RefCounted m obj, PrimMonad m, MonadMask m)
237247
=> HasCallStackIfDebug
238248
=> Ref obj
239249
-> m ()
@@ -261,6 +271,12 @@ deRef ref@Ref{refobj} =
261271
`seq` refobj
262272
#endif
263273

274+
{-# SPECIALISE
275+
withRef ::
276+
Ref obj
277+
-> (obj -> IO a)
278+
-> IO a
279+
#-}
264280
{-# INLINE withRef #-}
265281
-- | Use the object in a 'Ref'. Do not retain the object after the scope of
266282
-- the body. If you cannot use scoped \"with\" style, use pattern 'DeRef'.
@@ -276,10 +292,16 @@ withRef ref@Ref{refobj} f = do
276292
assertNoUseAfterRelease ref
277293
f refobj
278294

295+
{-# SPECIALISE
296+
dupRef ::
297+
RefCounted IO obj
298+
=> Ref obj
299+
-> IO (Ref obj)
300+
#-}
279301
-- | Duplicate an existing reference, to produce a new reference.
280302
--
281303
dupRef ::
282-
(RefCounted obj, FinaliserM obj ~ m, PrimMonad m)
304+
(RefCounted m obj, PrimMonad m)
283305
=> HasCallStackIfDebug
284306
=> Ref obj
285307
-> m (Ref obj)
@@ -308,11 +330,17 @@ mkWeakRef Ref {refobj} = WeakRef refobj
308330
mkWeakRefFromRaw :: obj -> WeakRef obj
309331
mkWeakRefFromRaw obj = WeakRef obj
310332

333+
{-# SPECIALISE
334+
deRefWeak ::
335+
RefCounted IO obj
336+
=> WeakRef obj
337+
-> IO (Maybe (Ref obj))
338+
#-}
311339
-- | If the object is still alive, obtain a /new/ normal reference. The normal
312340
-- rules for 'Ref' apply, including the need to eventually call 'releaseRef'.
313341
--
314342
deRefWeak ::
315-
(RefCounted obj, FinaliserM obj ~ m, PrimMonad m)
343+
(RefCounted m obj, PrimMonad m)
316344
=> HasCallStackIfDebug
317345
=> WeakRef obj
318346
-> m (Maybe (Ref obj))

src/Database/LSMTree/Internal/BlobFile.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ data BlobFile m h = BlobFile {
3232
}
3333
deriving stock (Show)
3434

35-
instance RefCounted (BlobFile m h) where
36-
type FinaliserM (BlobFile m h) = m
35+
instance RefCounted m (BlobFile m h) where
3736
getRefCounter = blobFileRefCounter
3837

3938
instance NFData h => NFData (BlobFile m h) where

src/Database/LSMTree/Internal/MergeSchedule.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ data MergingRun m h = MergingRun {
325325
, mergeRefCounter :: !(RefCounter m)
326326
}
327327

328-
instance RefCounted (MergingRun m h) where
329-
type FinaliserM (MergingRun m h) = m
328+
instance RefCounted m (MergingRun m h) where
330329
getRefCounter = mergeRefCounter
331330

332331
{-# SPECIALISE newMergingRun ::

src/Database/LSMTree/Internal/Run.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ instance NFData h => NFData (Run m h) where
101101
rnf a `seq` rwhnf b `seq` rnf c `seq` rnf d `seq` rnf e `seq`
102102
rnf f `seq` rnf g `seq` rnf h `seq` rwhnf i `seq` rwhnf j
103103

104-
instance RefCounted (Run m h) where
105-
type FinaliserM (Run m h) = m
104+
instance RefCounted m (Run m h) where
106105
getRefCounter = runRefCounter
107106

108107
size :: Ref (Run m h) -> NumEntries

src/Database/LSMTree/Internal/WriteBufferBlobs.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ data WriteBufferBlobs m h =
112112
instance NFData h => NFData (WriteBufferBlobs m h) where
113113
rnf (WriteBufferBlobs a b c) = rnf a `seq` rnf b `seq` rnf c
114114

115-
instance RefCounted (WriteBufferBlobs m h) where
116-
type FinaliserM (WriteBufferBlobs m h) = m
115+
instance RefCounted m (WriteBufferBlobs m h) where
117116
getRefCounter = writeBufRefCounter
118117

119118
{-# SPECIALISE new :: HasFS IO h -> FS.FsPath -> IO (Ref (WriteBufferBlobs IO h)) #-}

test-control/Test/Control/RefCount.hs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,12 @@ readRefCount (RefCounter countVar _) = readPrimVar countVar
108108
#ifdef NO_IGNORE_ASSERTS
109109
data TestObject = TestObject !(RefCounter IO)
110110

111-
instance RefCounted TestObject where
112-
type FinaliserM TestObject = IO
111+
instance RefCounted IO TestObject where
113112
getRefCounter (TestObject rc) = rc
114113

115114
data TestObject2 = TestObject2 (Ref TestObject)
116115

117-
instance RefCounted TestObject2 where
118-
type FinaliserM TestObject2 = IO
116+
instance RefCounted IO TestObject2 where
119117
getRefCounter (TestObject2 (DeRef to1)) = getRefCounter to1
120118

121119
prop_ref_double_free :: Property

0 commit comments

Comments
 (0)