packages feed

nonempty-containers-0.4.0.0: src/Data/IntMap/NonEmpty/Strict/Internal.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE PatternSynonyms #-}
{-# OPTIONS_HADDOCK not-home #-}

-- |
-- Module      : Data.IntMap.NonEmpty.Strict.Internal
-- Copyright   : (c) Justin Le 2018
-- License     : BSD3
--
-- Maintainer  : justin@jle.im
-- Stability   : experimental
-- Portability : non-portable
--
-- Strict internal-use functions used in the implementation of
-- "Data.IntMap.NonEmpty.Strict".  These share the same 'NEIntMap' type as
-- the lazy modules; only construction is strict in the value.
module Data.IntMap.NonEmpty.Strict.Internal (
  -- * Non-Empty IntMap type
  NEIntMap,
  pattern NEIntMap,
  neimIntMap,
  Key,
  singleton,
  nonEmptyMap,
  withNonEmpty,
  fromList,
  toList,
  map,
  insertWith,
  union,
  unions,
  elems,
  size,
  toMap,

  -- * Folds
  foldr,
  foldr',
  foldr1,
  foldl,
  foldl',
  foldl1,

  -- * Traversals
  traverseWithKey,
  traverseWithKey1,
  foldMapWithKey,

  -- * Unsafe IntMap Functions
  insertMinMap,
  insertMaxMap,

  -- * Debug
  valid,
) where

import Control.Applicative
import qualified Data.Foldable as F
import Data.Functor.Apply (Apply, MaybeApply (..), (<.>))
import Data.IntMap.Internal (IntMap, Key)
import qualified Data.IntMap.NonEmpty.Lazy.Internal as L
import qualified Data.IntMap.Strict as M
import Data.List.NonEmpty (NonEmpty (..))
import Data.Semigroup.Foldable (Foldable1)
import qualified Data.Semigroup.Foldable as F1
import Prelude hiding (Foldable (..), foldl, foldl1, foldr, foldr1, map)

type NEIntMap = L.NEIntMap

pattern NEIntMap :: Key -> a -> IntMap a -> NEIntMap a
pattern NEIntMap k v m <- L.NEIntMap k v m
  where
    NEIntMap k !v m = L.NEIntMap k v m

{-# COMPLETE NEIntMap #-}

neimIntMap :: NEIntMap a -> IntMap a
neimIntMap (NEIntMap _ _ m) = m
{-# INLINE neimIntMap #-}

singleton :: Key -> a -> NEIntMap a
singleton k !v = L.NEIntMap k v M.empty
{-# INLINE singleton #-}

nonEmptyMap :: IntMap a -> Maybe (NEIntMap a)
nonEmptyMap = L.nonEmptyMap
{-# INLINE nonEmptyMap #-}

withNonEmpty :: b -> (NEIntMap a -> b) -> IntMap a -> b
withNonEmpty = L.withNonEmpty
{-# INLINE withNonEmpty #-}

fromList :: NonEmpty (Key, a) -> NEIntMap a
fromList ((k, v) :| xs) = F.foldl' (\m (k', v') -> insertWith const k' v' m) (singleton k v) xs
{-# INLINE fromList #-}

toList :: NEIntMap a -> NonEmpty (Key, a)
toList = L.toList
{-# INLINE toList #-}

map :: (a -> b) -> NEIntMap a -> NEIntMap b
map f (NEIntMap k v m) = NEIntMap k (f v) (M.map f m)
{-# INLINE map #-}

insertWith :: (a -> a -> a) -> Key -> a -> NEIntMap a -> NEIntMap a
insertWith f k !v n@(NEIntMap k0 v0 m) = case compare k k0 of
  LT -> NEIntMap k v (toMap n)
  EQ -> NEIntMap k0 (f v v0) m
  GT -> NEIntMap k0 v0 (M.insertWith f k v m)
{-# INLINE insertWith #-}

union :: NEIntMap a -> NEIntMap a -> NEIntMap a
union n1@(NEIntMap k1 v1 m1) n2@(NEIntMap k2 v2 m2) = case compare k1 k2 of
  LT -> NEIntMap k1 v1 . M.union m1 . toMap $ n2
  EQ -> NEIntMap k1 v1 . M.union m1 $ m2
  GT -> NEIntMap k2 v2 . M.union (toMap n1) $ m2
{-# INLINE union #-}

unions :: Foldable1 f => f (NEIntMap a) -> NEIntMap a
unions ns = case F1.toNonEmpty ns of
  m :| ms -> F.foldl' union m ms
{-# INLINE unions #-}

elems :: NEIntMap a -> NonEmpty a
elems = fmap snd . toList
{-# INLINE elems #-}

size :: NEIntMap a -> Int
size = L.size
{-# INLINE size #-}

toMap :: NEIntMap a -> IntMap a
toMap (NEIntMap k v m) = insertMinMap k v m
{-# INLINE toMap #-}

foldr :: (a -> b -> b) -> b -> NEIntMap a -> b
foldr = L.foldr
{-# INLINE foldr #-}

foldr' :: (a -> b -> b) -> b -> NEIntMap a -> b
foldr' = L.foldr'
{-# INLINE foldr' #-}

foldr1 :: (a -> a -> a) -> NEIntMap a -> a
foldr1 = L.foldr1
{-# INLINE foldr1 #-}

foldl :: (b -> a -> b) -> b -> NEIntMap a -> b
foldl = L.foldl
{-# INLINE foldl #-}

foldl' :: (b -> a -> b) -> b -> NEIntMap a -> b
foldl' = L.foldl'
{-# INLINE foldl' #-}

foldl1 :: (a -> a -> a) -> NEIntMap a -> a
foldl1 = L.foldl1
{-# INLINE foldl1 #-}

traverseWithKey :: Applicative f => (Key -> a -> f b) -> NEIntMap a -> f (NEIntMap b)
traverseWithKey f (NEIntMap k v m) = NEIntMap k <$> f k v <*> M.traverseWithKey f m
{-# INLINE traverseWithKey #-}

traverseWithKey1 :: Apply f => (Key -> a -> f b) -> NEIntMap a -> f (NEIntMap b)
traverseWithKey1 f (NEIntMap k0 v m0) = case runMaybeApply m1 of
  Left m2 -> NEIntMap k0 <$> f k0 v <.> m2
  Right m2 -> flip (NEIntMap k0) m2 <$> f k0 v
  where
    m1 = M.traverseWithKey (\k -> MaybeApply . Left . f k) m0
{-# INLINE traverseWithKey1 #-}

foldMapWithKey :: Monoid m => (Key -> a -> m) -> NEIntMap a -> m
foldMapWithKey = L.foldMapWithKey
{-# INLINE foldMapWithKey #-}

valid :: NEIntMap a -> Bool
valid (NEIntMap k _ m) =
  all ((k <) . fst . fst) (M.minViewWithKey m)

insertMinMap :: Key -> a -> IntMap a -> IntMap a
insertMinMap k !v = M.insert k v
{-# INLINE insertMinMap #-}

insertMaxMap :: Key -> a -> IntMap a -> IntMap a
insertMaxMap k !v = M.insert k v
{-# INLINE insertMaxMap #-}