packages feed

tasty-autocollect-0.1.0.0: src/Test/Tasty/AutoCollect/Utils/TreeMap.hs

{-# LANGUAGE RecordWildCards #-}

module Test.Tasty.AutoCollect.Utils.TreeMap (
  TreeMap (..),
  fromList,
  foldTreeMap,
) where

import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)

data TreeMap k v = TreeMap
  { value :: Maybe v
  , children :: Map k (TreeMap k v)
  }
  deriving (Show, Eq)

{- |
Convert the given list of values into a 'TreeMap'.

For example,
@
fromList [[A, B, C], [A, B], [A, C, D], [Z]]
@
would become
@
TreeMap
  { value = Nothing
  , children = Map.fromList
      [ ("A", TreeMap
          { value = Nothing
          , children = Map.fromList
              [ ("B", TreeMap
                  { value = Just ...
                  , children = Map.fromList
                      ("C", [ TreeMap
                          { value = Just ...
                          , children = Map.empty
                          }
                      ])
                  })
              , ("C", TreeMap
                  { value = Nothing
                  , children = Map.fromList
                      [ ("D", TreeMap
                          { value = Just ...
                          , children = Map.empty
                          })
                      ]
                  })
              ]
          })
    , ("Z", TreeMap
        { value = Just ...
        , children = Map.empty
        })
    ]
  }
@
-}
fromList :: Ord k => [([k], v)] -> TreeMap k v
fromList = foldr (uncurry insert) empty

empty :: TreeMap k v
empty = TreeMap Nothing Map.empty

insert :: Ord k => [k] -> v -> TreeMap k v -> TreeMap k v
insert originalKeys v = go originalKeys
  where
    go ks treeMap =
      case ks of
        [] -> treeMap{value = Just v}
        k : ks' -> treeMap{children = Map.alter (Just . go ks' . fromMaybe empty) k (children treeMap)}

foldTreeMap :: (Maybe v -> Map k r -> r) -> TreeMap k v -> r
foldTreeMap f = go
  where
    go TreeMap{..} = f value (go <$> children)