packages feed

reactive-banana-0.9.0.0: src/Reactive/Banana/Prim/OrderedBag.hs

{-----------------------------------------------------------------------------
    reactive-banana
    
    Implementation of a bag whose elements are ordered by arrival time.
------------------------------------------------------------------------------}
{-# LANGUAGE TupleSections #-}
module Reactive.Banana.Prim.OrderedBag where

import           Data.Functor
import qualified Data.HashMap.Strict as Map
import           Data.Hashable
import           Data.List
import           Data.Maybe
import           Data.Ord

{-----------------------------------------------------------------------------
    Ordered Bag
------------------------------------------------------------------------------}
type Position = Integer

data OrderedBag a = OB !(Map.HashMap a Position) !Position

empty :: OrderedBag a
empty = OB Map.empty 0

-- | Add an element to an ordered bag after all the others.
-- Does nothing if the element is already in the bag.
insert :: (Eq a, Hashable a) => a -> OrderedBag a -> OrderedBag a
insert x (OB xs n) = OB (Map.insertWith (\new old -> old) x n xs) (n+1)

-- | Reorder a list of elements to appear as they were inserted into the bag.
-- Remove any elements from the list that do not appear in the bag.
inOrder :: (Eq a, Hashable a) => [(a,b)] -> OrderedBag a -> [(a,b)]
inOrder xs (OB bag _) = map snd $ sortBy (comparing fst) $
    mapMaybe (\x -> (,x) <$> Map.lookup (fst x) bag) xs