{-# LANGUAGE CPP #-}
module CHR.Data.FastSeq
( FastSeq((:++:),(::+:),(:+::))
, Seq
, isEmpty, null
, empty
, size
, singleton
, toList, fromList
, map
, union, unions
, firstNotEmpty
)
where
import Prelude hiding (null,map)
import Data.Monoid
import qualified Data.List as L
import qualified CHR.Utils as U
infixr 5 :++:, :+::
infixl 5 ::+:
data FastSeq a
= !(FastSeq a) :++: !(FastSeq a)
| !a :+:: !(FastSeq a)
| !(FastSeq a) ::+: !a
| FSeq !a
| FSeqL ![a]
| FSeqNil
type Seq a = FastSeq a
empty :: FastSeq a
empty = FSeqNil
#if __GLASGOW_HASKELL__ >= 804
instance Semigroup (FastSeq a) where
(<>) = union
#endif
instance Monoid (FastSeq a) where
mempty = empty
mappend = union
mconcat = unions
isEmpty, null :: FastSeq a -> Bool
isEmpty FSeqNil = True
isEmpty (FSeqL x ) = L.null x
isEmpty (FSeq _ ) = False
isEmpty (x1 :++: x2) = isEmpty x1 && isEmpty x2
isEmpty (x1 :+:: x2) = False
isEmpty (x1 ::+: x2) = False
null = isEmpty
size :: FastSeq a -> Int
size FSeqNil = 0
size (FSeqL x ) = length x
size (FSeq _ ) = 1
size (x1 :++: x2) = size x1 + size x2
size (x1 :+:: x2) = 1 + size x2
size (x1 ::+: x2) = size x1 + 1
singleton :: a -> FastSeq a
singleton = FSeq
viewMbCons :: FastSeq a -> Maybe (a, FastSeq a)
viewMbCons FSeqNil = Nothing
viewMbCons (FSeq x) = Just (x, FSeqNil)
viewMbCons (FSeqL (h:t)) = Just (h, FSeqL t)
viewMbCons (FSeqL [] ) = Nothing
viewMbCons (h :+:: t ) = Just (h, t)
viewMbCons (i ::+: l ) = maybe (Just (l, FSeqNil)) (\(h,t) -> Just (h, t ::+: l)) $ viewMbCons i
viewMbCons (s1 :++: s2) = maybe (viewMbCons s2) (\(h,t) -> Just (h, t :++: s2)) $ viewMbCons s1
fromList :: [a] -> FastSeq a
fromList [] = FSeqNil
fromList l = FSeqL l
toList :: FastSeq a -> [a]
toList s
= a s []
where a FSeqNil l = l
a (FSeq x ) l = x : l
a (FSeqL x ) l = x L.++ l
a (x1 :++: x2) l = a x1 (a x2 l)
a (x1 :+:: x2) l = x1 : a x2 l
a (x1 ::+: x2) l = a x1 (x2 : l)
map :: (a->b) -> FastSeq a -> FastSeq b
map f FSeqNil = FSeqNil
map f (FSeq x ) = FSeq $ f x
map f (FSeqL x ) = FSeqL $ L.map f x
map f (x1 :++: x2) = map f x1 :++: map f x2
map f (x1 :+:: x2) = f x1 :+:: map f x2
map f (x1 ::+: x2) = map f x1 ::+: f x2
union :: FastSeq a -> FastSeq a -> FastSeq a
union FSeqNil FSeqNil = FSeqNil
union FSeqNil s2 = s2
union s1 FSeqNil = s1
union s1 s2 = s1 :++: s2
unions :: [FastSeq a] -> FastSeq a
unions [s] = s
unions s = L.foldr ( (:++:)) FSeqNil s
firstNotEmpty :: [FastSeq x] -> FastSeq x
firstNotEmpty = U.maybeHd empty id . filter (not . isEmpty)