content: {-# LANGUAGE DeriveGeneric #-}
  {-# LANGUAGE DeriveAnyClass #-}
  {-# LANGUAGE RecordWildCards #-}
  {-# LANGUAGE FlexibleInstances #-}
  module Data.Abstract.CallString(CallString,push,truncate) where
  
  import           Prelude hiding (truncate)
  
  import qualified Data.Foldable as F
  import           Data.Hashable
  import           Data.Sequence (Seq,(|>))
  import qualified Data.Sequence as S
  import           Data.Empty
  import           Prettyprinter
  
  import           Control.DeepSeq
  import           GHC.Generics(Generic)
  
  data CallString lab = CallString { callString :: Seq lab, size :: Int }
    deriving (Generic,NFData)
  
  instance Functor CallString where
    fmap f (CallString str s) = CallString (fmap f str) s
  
  instance Show lab => Show (CallString lab) where
    show = show . toList
  
  instance Pretty lab => Pretty (CallString lab) where
    pretty = pretty . toList
  
  instance Eq lab => Eq (CallString lab) where
    c1 == c2 = size c1 == size c2 && callString c1 == callString c2
    {-# INLINE (==) #-}
  
  instance Hashable lab => Hashable (CallString lab) where
    hashWithSalt s = hashWithSalt s . toList
    {-# INLINE hashWithSalt #-}
  
  instance IsEmpty (CallString lab) where
    empty = CallString S.empty 0
    {-# INLINE empty #-}
  
  push :: lab -> CallString lab -> CallString lab
  push l (CallString {..}) = CallString (callString |> l) (size + 1)
  {-# INLINE push #-}
  
  truncate :: Int -> CallString lab -> CallString lab
  truncate k cont@(CallString {..})
    | size > k = CallString (S.drop (size - k) callString) k
    | otherwise = cont
  
  toList :: CallString lab -> [lab]
  toList = F.toList . callString
  {-# INLINE toList #-}
  