packages feed

tasty-autocollect-0.4.2: 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 Data.Map.Strict qualified 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)