{-# LANGUAGE KindSignatures #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -O2 #-} module Data.Map.Unboxed.Unlifted ( Map , singleton , lookup , size -- * List Conversion , fromList , fromListAppend , fromListN , fromListAppendN ) where import Prelude hiding (lookup) import Data.Semigroup (Semigroup) import Data.Primitive.Types (Prim) import Data.Primitive.UnliftedArray (PrimUnlifted,UnliftedArray) import Data.Primitive (PrimArray) import qualified GHC.Exts as E import qualified Data.Semigroup as SG import qualified Data.Map.Internal as I -- | A map from keys @k@ to values @v@. The key type and the value -- type must both have 'Prim' instances. newtype Map k v = Map (I.Map PrimArray UnliftedArray k v) instance (Prim k, Ord k, PrimUnlifted v, Semigroup v) => Semigroup (Map k v) where Map x <> Map y = Map (I.append x y) instance (Prim k, Ord k, PrimUnlifted v, Semigroup v) => Monoid (Map k v) where mempty = Map I.empty mappend = (SG.<>) mconcat = Map . I.concat . E.coerce instance (Prim k, Eq k, PrimUnlifted v, Eq v) => Eq (Map k v) where Map x == Map y = I.equals x y instance (Prim k, Ord k, PrimUnlifted v, Ord v) => Ord (Map k v) where compare (Map x) (Map y) = I.compare x y instance (Prim k, Ord k, PrimUnlifted v) => E.IsList (Map k v) where type Item (Map k v) = (k,v) fromListN n = Map . I.fromListN n fromList = Map . I.fromList toList (Map s) = I.toList s instance (Prim k, Show k, PrimUnlifted v, Show v) => Show (Map k v) where showsPrec p (Map s) = I.showsPrec p s -- | /O(log n)/ Lookup the value at a key in the map. lookup :: (Prim k, Ord k, PrimUnlifted v) => k -> Map k v -> Maybe v lookup a (Map s) = I.lookup a s -- | /O(1)/ Create a map with a single element. singleton :: (Prim k, PrimUnlifted v) => k -> v -> Map k v singleton k v = Map (I.singleton k v) -- | /O(n*log n)/ Create a map from a list of key-value pairs. -- If the list contains more than one value for the same key, -- the last value is retained. If the keys in the argument are -- in nondescending order, this algorithm runs in /O(n)/ time instead. fromList :: (Prim k, Ord k, PrimUnlifted v) => [(k,v)] -> Map k v fromList = Map . I.fromList -- | /O(n*log n)/ This function has the same behavior as 'fromList' -- regardless of whether or not the expected size is accurate. Additionally, -- negative sizes are handled correctly. The expected size is used as the -- size of the initially allocated buffer when building the 'Map'. If the -- keys in the argument are in nondescending order, this algorithm runs -- in /O(n)/ time. fromListN :: (Prim k, Ord k, PrimUnlifted v) => Int -- ^ expected size of resulting 'Map' -> [(k,v)] -- ^ key-value pairs -> Map k v fromListN n = Map . I.fromListN n -- | /O(n*log n)/ This function has the same behavior as 'fromList', -- but it combines values with the 'Semigroup' instances instead of -- choosing the last occurrence. fromListAppend :: (Prim k, Ord k, PrimUnlifted v, Semigroup v) => [(k,v)] -> Map k v fromListAppend = Map . I.fromListAppend -- | /O(n*log n)/ This function has the same behavior as 'fromListN', -- but it combines values with the 'Semigroup' instances instead of -- choosing the last occurrence. fromListAppendN :: (Prim k, Ord k, PrimUnlifted v, Semigroup v) => Int -- ^ expected size of resulting 'Map' -> [(k,v)] -- ^ key-value pairs -> Map k v fromListAppendN n = Map . I.fromListAppendN n -- | /O(1)/ The number of elements in the map. size :: PrimUnlifted v => Map k v -> Int size (Map m) = I.size m