{-# LANGUAGE BangPatterns #-}
module Haxl.Core.Flags
(
ReportFlag(..)
, ReportFlags
, defaultReportFlags
, profilingReportFlags
, setReportFlag
, clearReportFlag
, testReportFlag
, Flags(..)
, defaultFlags
, ifTrace
, ifReport
, ifProfiling
) where
import Control.Monad
import Data.Bits
import Data.List (foldl')
import Text.Printf (printf)
data ReportFlag
= ReportOutgoneFetches
| ReportFetchStats
| ReportProfiling
| ReportExceptionLabelStack
| ReportFetchStack
deriving (ReportFlag
ReportFlag -> ReportFlag -> Bounded ReportFlag
forall a. a -> a -> Bounded a
maxBound :: ReportFlag
$cmaxBound :: ReportFlag
minBound :: ReportFlag
$cminBound :: ReportFlag
Bounded, Int -> ReportFlag
ReportFlag -> Int
ReportFlag -> [ReportFlag]
ReportFlag -> ReportFlag
ReportFlag -> ReportFlag -> [ReportFlag]
ReportFlag -> ReportFlag -> ReportFlag -> [ReportFlag]
(ReportFlag -> ReportFlag)
-> (ReportFlag -> ReportFlag)
-> (Int -> ReportFlag)
-> (ReportFlag -> Int)
-> (ReportFlag -> [ReportFlag])
-> (ReportFlag -> ReportFlag -> [ReportFlag])
-> (ReportFlag -> ReportFlag -> [ReportFlag])
-> (ReportFlag -> ReportFlag -> ReportFlag -> [ReportFlag])
-> Enum ReportFlag
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: ReportFlag -> ReportFlag -> ReportFlag -> [ReportFlag]
$cenumFromThenTo :: ReportFlag -> ReportFlag -> ReportFlag -> [ReportFlag]
enumFromTo :: ReportFlag -> ReportFlag -> [ReportFlag]
$cenumFromTo :: ReportFlag -> ReportFlag -> [ReportFlag]
enumFromThen :: ReportFlag -> ReportFlag -> [ReportFlag]
$cenumFromThen :: ReportFlag -> ReportFlag -> [ReportFlag]
enumFrom :: ReportFlag -> [ReportFlag]
$cenumFrom :: ReportFlag -> [ReportFlag]
fromEnum :: ReportFlag -> Int
$cfromEnum :: ReportFlag -> Int
toEnum :: Int -> ReportFlag
$ctoEnum :: Int -> ReportFlag
pred :: ReportFlag -> ReportFlag
$cpred :: ReportFlag -> ReportFlag
succ :: ReportFlag -> ReportFlag
$csucc :: ReportFlag -> ReportFlag
Enum, ReportFlag -> ReportFlag -> Bool
(ReportFlag -> ReportFlag -> Bool)
-> (ReportFlag -> ReportFlag -> Bool) -> Eq ReportFlag
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ReportFlag -> ReportFlag -> Bool
$c/= :: ReportFlag -> ReportFlag -> Bool
== :: ReportFlag -> ReportFlag -> Bool
$c== :: ReportFlag -> ReportFlag -> Bool
Eq, Int -> ReportFlag -> ShowS
[ReportFlag] -> ShowS
ReportFlag -> String
(Int -> ReportFlag -> ShowS)
-> (ReportFlag -> String)
-> ([ReportFlag] -> ShowS)
-> Show ReportFlag
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ReportFlag] -> ShowS
$cshowList :: [ReportFlag] -> ShowS
show :: ReportFlag -> String
$cshow :: ReportFlag -> String
showsPrec :: Int -> ReportFlag -> ShowS
$cshowsPrec :: Int -> ReportFlag -> ShowS
Show)
profilingDependents :: [ReportFlag]
profilingDependents :: [ReportFlag]
profilingDependents =
[ ReportFlag
ReportExceptionLabelStack
, ReportFlag
ReportFetchStack
]
newtype ReportFlags = ReportFlags Int
instance Show ReportFlags where
show :: ReportFlags -> String
show (ReportFlags Int
fs) = String -> Int -> Int -> String
forall r. PrintfType r => String -> r
printf String
"%0*b" (ReportFlag -> Int
forall a. Enum a => a -> Int
fromEnum ReportFlag
maxReportFlag Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
fs
where
maxReportFlag :: ReportFlag
maxReportFlag = ReportFlag
forall a. Bounded a => a
maxBound :: ReportFlag
defaultReportFlags :: ReportFlags
defaultReportFlags :: ReportFlags
defaultReportFlags = Int -> ReportFlags
ReportFlags Int
0
profilingReportFlags :: ReportFlags
profilingReportFlags :: ReportFlags
profilingReportFlags = (ReportFlags -> ReportFlag -> ReportFlags)
-> ReportFlags -> [ReportFlag] -> ReportFlags
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' ((ReportFlag -> ReportFlags -> ReportFlags)
-> ReportFlags -> ReportFlag -> ReportFlags
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReportFlag -> ReportFlags -> ReportFlags
setReportFlag) ReportFlags
defaultReportFlags
[ ReportFlag
ReportOutgoneFetches
, ReportFlag
ReportFetchStats
, ReportFlag
ReportProfiling
]
setReportFlag :: ReportFlag -> ReportFlags -> ReportFlags
setReportFlag :: ReportFlag -> ReportFlags -> ReportFlags
setReportFlag ReportFlag
f (ReportFlags Int
fs) =
Int -> ReportFlags
ReportFlags (Int -> ReportFlags) -> Int -> ReportFlags
forall a b. (a -> b) -> a -> b
$ Int -> Int
setDependencies (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int
forall a. Bits a => a -> Int -> a
setBit Int
fs (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ ReportFlag -> Int
forall a. Enum a => a -> Int
fromEnum ReportFlag
f
where
setDependencies :: Int -> Int
setDependencies
| ReportFlag
f ReportFlag -> [ReportFlag] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ReportFlag]
profilingDependents = (Int -> Int -> Int) -> Int -> Int -> Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Int -> Int
forall a. Bits a => a -> Int -> a
setBit (Int -> Int -> Int) -> Int -> Int -> Int
forall a b. (a -> b) -> a -> b
$ ReportFlag -> Int
forall a. Enum a => a -> Int
fromEnum ReportFlag
ReportProfiling
| Bool
otherwise = Int -> Int
forall a. a -> a
id
clearReportFlag :: ReportFlag -> ReportFlags -> ReportFlags
clearReportFlag :: ReportFlag -> ReportFlags -> ReportFlags
clearReportFlag ReportFlag
f (ReportFlags Int
fs) =
Int -> ReportFlags
ReportFlags (Int -> ReportFlags) -> Int -> ReportFlags
forall a b. (a -> b) -> a -> b
$ Int -> Int
forall p. Bits p => p -> p
clearDependents (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int
forall a. Bits a => a -> Int -> a
clearBit Int
fs (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ ReportFlag -> Int
forall a. Enum a => a -> Int
fromEnum ReportFlag
f
where
clearDependents :: p -> p
clearDependents p
z = case ReportFlag
f of
ReportFlag
ReportProfiling -> (p -> Int -> p) -> p -> [Int] -> p
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' p -> Int -> p
forall a. Bits a => a -> Int -> a
clearBit p
z ([Int] -> p) -> [Int] -> p
forall a b. (a -> b) -> a -> b
$ (ReportFlag -> Int) -> [ReportFlag] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ReportFlag -> Int
forall a. Enum a => a -> Int
fromEnum [ReportFlag]
profilingDependents
ReportFlag
_ -> p
z
{-# INLINE testReportFlag #-}
testReportFlag :: ReportFlag -> ReportFlags -> Bool
testReportFlag :: ReportFlag -> ReportFlags -> Bool
testReportFlag !ReportFlag
f (ReportFlags !Int
fs) = Int -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit Int
fs (Int -> Bool) -> Int -> Bool
forall a b. (a -> b) -> a -> b
$ ReportFlag -> Int
forall a. Enum a => a -> Int
fromEnum ReportFlag
f
data Flags = Flags
{ Flags -> Int
trace :: {-# UNPACK #-} !Int
, Flags -> ReportFlags
report :: {-# UNPACK #-} !ReportFlags
, Flags -> Int
caching :: {-# UNPACK #-} !Int
, Flags -> Int
recording :: {-# UNPACK #-} !Int
}
defaultFlags :: Flags
defaultFlags :: Flags
defaultFlags = Flags :: Int -> ReportFlags -> Int -> Int -> Flags
Flags
{ trace :: Int
trace = Int
0
, report :: ReportFlags
report = ReportFlags
defaultReportFlags
, caching :: Int
caching = Int
1
, recording :: Int
recording = Int
0
}
ifTrace :: Monad m => Flags -> Int -> m a -> m ()
ifTrace :: Flags -> Int -> m a -> m ()
ifTrace Flags
flags Int
i = Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Flags -> Int
trace Flags
flags Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
i) (m () -> m ()) -> (m a -> m ()) -> m a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void
ifReport :: Monad m => Flags -> ReportFlag -> m a -> m ()
ifReport :: Flags -> ReportFlag -> m a -> m ()
ifReport Flags
flags ReportFlag
i = Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (ReportFlag -> ReportFlags -> Bool
testReportFlag ReportFlag
i (ReportFlags -> Bool) -> ReportFlags -> Bool
forall a b. (a -> b) -> a -> b
$ Flags -> ReportFlags
report Flags
flags) (m () -> m ()) -> (m a -> m ()) -> m a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void
ifProfiling :: Monad m => Flags -> m a -> m ()
ifProfiling :: Flags -> m a -> m ()
ifProfiling Flags
flags = Flags -> ReportFlag -> m a -> m ()
forall (m :: * -> *) a.
Monad m =>
Flags -> ReportFlag -> m a -> m ()
ifReport Flags
flags ReportFlag
ReportProfiling