-- | A vector representation of 'M.Map'.

module Data.DAWG.VMap
( VMap (unVMap)
, mkVMap
, empty
, lookup
, insert
) where

import Prelude hiding (lookup)
import Control.Applicative ((<$>))
import Data.Binary (Binary, put, get)
import Data.Vector.Binary ()
import qualified Data.Map as M
import qualified Data.Vector.Unboxed as U

-- | A strictly ascending vector of distinct elements with respect
-- to 'fst' values.
newtype VMap a = VMap { unVMap :: U.Vector (Char, a) }
    deriving (Show, Eq, Ord)

instance (Binary a, U.Unbox a) => Binary (VMap a) where
    put v = put (unVMap v)
    get = VMap <$> get

-- | Smart VMap constructor which ensures that the underlying vector is
-- strictly ascending with respect to 'fst' values.
mkVMap :: U.Unbox a => [(Char, a)] -> VMap a
mkVMap = VMap . U.fromList . M.toAscList  . M.fromList 
{-# INLINE mkVMap #-}

-- | Empty map.
empty :: U.Unbox a => VMap a
empty = VMap U.empty
{-# INLINE empty #-}

-- | Lookup the character in the map.
lookup :: U.Unbox a => Char -> VMap a -> Maybe a
lookup x = fmap snd . U.find ((==x) . fst) . unVMap
{-# INLINE lookup #-}

-- | Insert the (character, value) pair into the map.
-- TODO: Optimize!  Use the invariant, that VMap is
-- kept in an ascending vector.
insert :: U.Unbox a => Char -> a -> VMap a -> VMap a
insert x y
    = VMap . U.fromList . M.toAscList
    . M.insert x y
    . M.fromList . U.toList . unVMap
{-# INLINE insert #-}