profiteur-0.3.0.0: src/Profiteur/Core.hs
--------------------------------------------------------------------------------
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RecordWildCards #-}
module Profiteur.Core
( CostCentre (..)
, Node (..)
, nodesFromCostCentre
, NodeMap (..)
, nodeMapFromNodes
, nodeMapFromCostCentre
) where
--------------------------------------------------------------------------------
import Control.Monad (guard)
import qualified Data.Aeson as A
import qualified Data.HashMap.Strict as HMS
import Data.List (foldl')
import Data.Maybe (maybeToList)
import Data.Monoid ((<>))
import qualified Data.Text as T
import qualified Data.Vector as V
--------------------------------------------------------------------------------
type Id = T.Text
--------------------------------------------------------------------------------
data CostCentre = CostCentre
{ ccName :: !T.Text
, ccModule :: !T.Text
, ccId :: !Id
, ccEntries :: !Int
, ccIndividualTime :: !Double
, ccIndividualAlloc :: !Double
, ccInheritedTime :: !Double
, ccInheritedAlloc :: !Double
, ccChildren :: !(V.Vector CostCentre)
} deriving (Show)
--------------------------------------------------------------------------------
data Node = Node
{ nId :: !Id
, nName :: !T.Text
, nModule :: !T.Text
, nEntries :: !Int
, nTime :: !Double
, nAlloc :: !Double
, nChildren :: !(V.Vector Id)
} deriving (Show)
--------------------------------------------------------------------------------
nodesFromCostCentre :: CostCentre -> [Node]
nodesFromCostCentre cc
| V.null (ccChildren cc), Just indiv' <- indiv =
[ indiv' {nId = nId self, nName = nName self}
]
| otherwise =
self : maybeToList indiv ++
concatMap nodesFromCostCentre (V.toList $ ccChildren cc)
where
self = Node
{ nId = ccId cc
, nName = ccName cc
, nModule = ccModule cc
, nEntries = ccEntries cc
, nTime = ccInheritedTime cc
, nAlloc = ccInheritedAlloc cc
, nChildren = V.fromList $
maybeToList (nId <$> indiv) ++ map ccId (V.toList $ ccChildren cc)
}
indiv = do
guard $ ccIndividualTime cc > 0 || ccIndividualAlloc cc > 0
return Node
{ nId = nId self <> ".indiv"
, nName = ccName cc <> " (indiv)"
, nModule = ccModule cc
, nEntries = ccEntries cc
, nTime = ccIndividualTime cc
, nAlloc = ccIndividualAlloc cc
, nChildren = V.empty
}
--------------------------------------------------------------------------------
instance A.ToJSON Node where
toJSON Node {..} = A.toJSON
[ A.toJSON nName
, A.toJSON nModule
, A.toJSON nEntries
, A.toJSON nTime
, A.toJSON nAlloc
, A.toJSON nChildren
]
--------------------------------------------------------------------------------
data NodeMap = NodeMap
{ nmNodes :: !(HMS.HashMap Id Node)
, nmRoot :: !Id
} deriving (Show)
--------------------------------------------------------------------------------
instance A.ToJSON NodeMap where
toJSON NodeMap {..} = A.toJSON
[ A.toJSON nmNodes
, A.toJSON nmRoot
]
--------------------------------------------------------------------------------
nodeMapFromNodes :: Id -> [Node] -> NodeMap
nodeMapFromNodes root nodes = NodeMap
{ nmNodes = foldl' (\acc n -> HMS.insert (nId n) n acc) HMS.empty nodes
, nmRoot = root
}
--------------------------------------------------------------------------------
nodeMapFromCostCentre :: CostCentre -> NodeMap
nodeMapFromCostCentre root =
nodeMapFromNodes (ccId root) (nodesFromCostCentre root)