packages feed

yaya-containers-0.2.0.0: src/Yaya/Containers/Pattern/Map.hs

{-# LANGUAGE Safe #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module Yaya.Containers.Pattern.Map
  ( MapF (BinF, TipF),
    -- | @since 0.1.2.0
    eqMapF,
    -- | @since 0.1.2.0
    compareMapF,
    -- | @since 0.1.2.0
    readMapFPrec,
    -- | @since 0.1.2.0
    showsMapFPrec,
  )
where

import "base" Control.Applicative
  ( Alternative ((<|>)),
    Applicative ((<*>)),
    (*>),
  )
import "base" Control.Category (Category ((.)))
import "base" Data.Bool (Bool (False, True), (&&))
import "base" Data.Eq (Eq ((==)))
import "base" Data.Foldable (Foldable)
import "base" Data.Function (($))
import "base" Data.Functor (Functor (fmap), (<$), (<$>))
import "base" Data.Functor.Classes
  ( Eq1 (liftEq),
    Eq2 (liftEq2),
    Ord1 (liftCompare),
    Ord2 (liftCompare2),
    Read1 (liftReadPrec),
    Read2 (liftReadPrec2),
    Show1 (liftShowsPrec),
    Show2 (liftShowsPrec2),
  )
import "base" Data.Int (Int)
import "base" Data.Ord (Ord (compare, (<=)), Ordering (EQ, GT, LT))
import "base" Data.Semigroup ((<>))
import "base" Data.Traversable (Traversable)
import qualified "base" Data.Tuple as Tuple
import "base" GHC.Generics (Generic, Generic1)
import "base" GHC.Read (expectP)
import "base" Text.Read
  ( Read (readListPrec, readPrec),
    ReadPrec,
    parens,
    prec,
    step,
  )
import qualified "base" Text.Read.Lex as Lex
import "base" Text.Show
  ( Show (showList, showsPrec),
    ShowS,
    showParen,
    showString,
  )
import qualified "containers" Data.Map.Internal as Map
import "yaya" Yaya.Fold
  ( Projectable (project),
    Recursive (cata),
    Steppable (embed),
  )
import "base" Prelude (Num ((+)))

data MapF k v r = TipF | BinF Map.Size k ~v r r
  deriving stock
    ( Eq,
      Ord,
      Generic,
      -- | @since 0.1.2.0
      Read,
      Show,
      Foldable,
      Functor,
      Generic1,
      Traversable
    )

instance Projectable (->) (Map.Map k v) (MapF k v) where
  project Map.Tip = TipF
  project (Map.Bin size k v l r) = BinF size k v l r

instance Recursive (->) (Map.Map k v) (MapF k v) where
  cata φ = φ . fmap (cata φ) . project

instance Steppable (->) (Map.Map k v) (MapF k v) where
  embed TipF = Map.Tip
  embed (BinF size k v l r) = Map.Bin size k v l r

eqMapF ::
  (k -> k' -> Bool) ->
  (v -> v' -> Bool) ->
  (r -> r' -> Bool) ->
  MapF k v r ->
  MapF k' v' r' ->
  Bool
eqMapF eqK eqV eqR = Tuple.curry $ \case
  (TipF, TipF) -> True
  (BinF size k v l r, BinF size' k' v' l' r') ->
    size == size' && eqK k k' && eqV v v' && eqR l l' && eqR r r'
  (_, _) -> False

compareMapF ::
  (k -> k' -> Ordering) ->
  (v -> v' -> Ordering) ->
  (r -> r' -> Ordering) ->
  MapF k v r ->
  MapF k' v' r' ->
  Ordering
compareMapF compareK compareV compareR = Tuple.curry $ \case
  (TipF, TipF) -> EQ
  (TipF, BinF {}) -> LT
  (BinF {}, TipF) -> GT
  (BinF size k v l r, BinF size' k' v' l' r') ->
    compare size size'
      <> compareK k k'
      <> compareV v v'
      <> compareR l l'
      <> compareR r r'

readMapFPrec :: ReadPrec k -> ReadPrec v -> ReadPrec r -> ReadPrec (MapF k v r)
readMapFPrec readPrecK readPrecV readPrecR =
  let appPrec = 10
   in parens . prec appPrec $
        TipF
          <$ expectP (Lex.Ident "TipF")
          <|> expectP (Lex.Ident "BinF")
            *> ( BinF
                   <$> step readPrec
                   <*> step readPrecK
                   <*> step readPrecV
                   <*> step readPrecR
                   <*> step readPrecR
               )

showsMapFPrec ::
  (Int -> k -> ShowS) ->
  (Int -> v -> ShowS) ->
  (Int -> r -> ShowS) ->
  Int ->
  MapF k v r ->
  ShowS
showsMapFPrec showsPrecK showsPrecV showsPrecR p =
  let appPrec = 10
      nextPrec = appPrec + 1
   in \case
        TipF -> showString "TipF"
        BinF size k v l r ->
          showParen (nextPrec <= p) $
            showString "BinF "
              . showsPrec nextPrec size
              . showString " "
              . showsPrecK nextPrec k
              . showString " "
              . showsPrecV nextPrec v
              . showString " "
              . showsPrecR nextPrec l
              . showString " "
              . showsPrecR nextPrec r

instance (Eq k, Eq v) => Eq1 (MapF k v) where
  liftEq = liftEq2 (==)

instance (Eq k) => Eq2 (MapF k) where
  liftEq2 = eqMapF (==)

instance (Ord k, Ord v) => Ord1 (MapF k v) where
  liftCompare = liftCompare2 compare

instance (Ord k) => Ord2 (MapF k) where
  liftCompare2 = compareMapF compare

-- | @since 0.1.2.0
instance (Read k, Read v) => Read1 (MapF k v) where
  liftReadPrec = liftReadPrec2 readPrec readListPrec

-- | @since 0.1.2.0
instance (Read k) => Read2 (MapF k) where
  liftReadPrec2 readPrecV _ readPrecR _ =
    readMapFPrec readPrec readPrecV readPrecR

instance (Show k, Show v) => Show1 (MapF k v) where
  liftShowsPrec = liftShowsPrec2 showsPrec showList

instance (Show k) => Show2 (MapF k) where
  liftShowsPrec2 showsPrecV _ showsPrecR _ =
    showsMapFPrec showsPrec showsPrecV showsPrecR