module Data.Raz.Core.Internal where
import Control.Monad.Random hiding (fromList)
import Data.Bits
import Data.Foldable (toList)
import Data.Function
import Prelude hiding (tail)
import System.IO.Unsafe
import Text.Read
import Data.Raz.Util
type Lev = Int
type Cnt = Int
data Dir = L | R deriving (Eq, Ord, Show, Read)
data Tree a
= Empty
| Leaf a
| Bin !Lev !Cnt !(Tree a) !(Tree a)
deriving (Functor, Foldable, Traversable)
data TList a
= Nil
| Cons a !(TList a)
| Level Lev !(TList a)
| Tree !(Tree a) !(TList a)
deriving (Eq, Ord, Functor, Foldable, Traversable)
type Raz a = (TList a, a, TList a)
instance Eq a => Eq (Tree a) where
(==) = (==) `on` toList
instance Ord a => Ord (Tree a) where
compare = compare `on` toList
instance Show a => Show (Tree a) where
showsPrec d t = showParen (d > 10) $
showString "fromList " . shows (toList t)
instance Read a => Read (Tree a) where
readPrec = parens . prec 10 $ do
Ident "fromList" <- lexP
m <- step readListPrec
return (evalRand (fromList m) (unsafePerformIO newStdGen))
readListPrec = readListPrecDefault
randomLevel :: MonadRandom m => m Lev
randomLevel = fmap (\n -> countTrailingZeros (n :: Word)) getRandom
singleton :: a -> Raz a
singleton a = (Nil, a, Nil)
empty :: MonadRandom m => a -> m (Raz a)
empty a = randomLevel <&> \lv ->
(Level lv (Cons a Nil), a, Nil)
size :: Tree a -> Cnt
size Empty = 0
size (Leaf _) = 1
size (Bin _ c _ _) = c
trim :: Dir -> TList a -> TList a
trim d (Tree t rest) = trim' d t rest
trim' :: Dir -> Tree a -> TList a -> TList a
trim' _ (Leaf a) tl = Cons a tl
trim' d (Bin lv _ l r) tl =
case d of
L -> trim' d r (Level lv (Tree l tl))
R -> trim' d l (Level lv (Tree r tl))
viewC :: Raz a -> a
viewC (_, a, _) = a
view :: Dir -> Raz a -> a
view L (l, _, _) = view' L l
view R (_, _, r) = view' R r
view' :: Dir -> TList a -> a
view' d Nil = error "view past end of seq"
view' d (Cons a _) = a
view' d (Level _ rest) = view' d rest
view' d t = view' d $ trim d t
alterC :: a -> Raz a -> Raz a
alterC a (l, _, r) = (l, a, r)
adjustC :: (a -> a) -> Raz a -> Raz a
adjustC f (l, a, r) = (l, f a, r)
adjustC' :: (a -> a) -> Raz a -> Raz a
adjustC' f (l, a, r) = let a' = f a in a' `seq` (l, a', r)
alter :: Dir -> a -> Raz a -> Raz a
alter L a (l, e, r) = (alter' L a l, e, r)
alter R a (l, e, r) = (l, e, alter' R a r)
alter' :: Dir -> a -> TList a -> TList a
alter' d a Nil = error "alter past end of seq"
alter' d a (Cons _ rest) = Cons a rest
alter' d a (Level lv rest) = Level lv $ alter' d a rest
alter' d a t = alter' d a (trim d t)
insert :: MonadRandom m => Dir -> a -> Raz a -> m (Raz a)
insert L a' (l, a, r) = randomLevel <&> \lv -> (Level lv (Cons a' l), a, r)
insert R a' (l, a, r) = randomLevel <&> \lv -> (l, a, Level lv (Cons a' r))
remove :: Dir -> Raz a -> Raz a
remove L (l, e, r) = (snd $ remove' L l, e, r)
remove R (l, e, r) = (l, e, snd $ remove' R r)
remove' :: Dir -> TList a -> (a, TList a)
remove' d Nil = error "remove past end of seq"
remove' d (Cons a rest) = (a, rest)
remove' d (Level lv rest) = remove' d rest
remove' d t = remove' d (trim d t)
removeC :: Dir -> Raz a -> Raz a
removeC L (l, _, r) = (l', a, r)
where
(a, l') = remove' L l
removeC R (l, _, r) = (l, a, r')
where
(a, r') = remove' R r
move :: Dir -> Raz a -> Raz a
move L (l, e, r) = move' L l (Cons e r)
move R (l, e, r) = move' R r (Cons e l)
move' :: Dir -> TList a -> TList a -> Raz a
move' d Nil s = error "move past end of seq"
move' L (Cons a rest) s = (rest, a, s)
move' R (Cons a rest) s = (s, a, rest)
move' d (Level lv rest) s = move' d rest (Level lv s)
move' d f s = move' d (trim d f) s
focus :: Int -> Tree a -> Raz a
focus p t | p < 0 || p >= size t = error "focus out of bounds"
focus p t = focus' p Nil Nil t
focus' :: Int -> TList a -> TList a -> Tree a -> Raz a
focus' _ _ _ Empty = error "internal Empty"
focus' p l r (Leaf a) = (l, a, r)
focus' p l r (Bin lv _ bl br)
| p < c = focus' p l (Level lv (Tree br r)) bl
| otherwise = focus' (p c) (Level lv (Tree bl l)) r br
where c = size bl
focusL :: Tree a -> Raz a
focusL = focusL' Nil
focusL' :: TList a -> Tree a -> Raz a
focusL' _ Empty = error "internal Empty"
focusL' r (Leaf a) = (Nil, a, r)
focusL' r (Bin lv _ bl br) = focusL' (Level lv (Tree br r)) bl
focusR :: Tree a -> Raz a
focusR = focusR' Nil
focusR' :: TList a -> Tree a -> Raz a
focusR' _ Empty = error "internal Empty"
focusR' l (Leaf a) = (l, a, Nil)
focusR' l (Bin lv _ bl br) = focusR' (Level lv (Tree bl l)) br
joinSides :: Tree a -> Tree a -> Tree a
joinSides t1 t2 =
case (t1, t2) of
(Empty, _) -> t2
(_, Empty) -> t1
(Leaf _, Leaf _) -> error "leaf-leaf: full trees shouldn't be joined"
(Leaf _, Bin lv _ l r) -> Bin lv tot (joinSides t1 l) r
(Bin lv _ l r, Leaf _) -> Bin lv tot l (joinSides r t2)
(Bin lv1 _ l1 r1, Bin lv2 _ l2 r2)
| lv1 >= lv2 -> Bin lv1 tot l1 (joinSides r1 t2)
| otherwise -> Bin lv2 tot (joinSides t1 l2) r2
where tot = size t1 + size t2
headAsTree :: TList a -> Tree a
headAsTree Nil = Empty
headAsTree (Cons s _) = Leaf s
headAsTree (Level l _) = Bin l 0 Empty Empty
headAsTree (Tree t _) = t
tail :: TList a -> TList a
tail Nil = Nil
tail (Cons _ r) = r
tail (Level _ r) = r
tail (Tree _ r) = r
grow :: Dir -> TList a -> Tree a
grow d t = grow' d (headAsTree t) (tail t)
grow' :: Dir -> Tree a -> TList a -> Tree a
grow' _ h Nil = h
grow' d h t =
case d of
L -> grow' d (joinSides h' h) t'
R -> grow' d (joinSides h h') t'
where
h' = headAsTree t
t' = tail t
unfocus :: Raz a -> Tree a
unfocus (l, a, r) = joinSides (grow L l) . joinSides (Leaf a) $ grow R r
fromList :: MonadRandom m => [a] -> m (Tree a)
fromList [] = return Empty
fromList (a : as) =
fromList' (Tree (Leaf a) Nil) as
fromList'
:: MonadRandom m => TList a -> [a] -> m (Tree a)
fromList' !ls [] = return (fold ls)
fromList' !ls (a : as) =
randomLevel >>= \lv ->
fromList' (Tree (Leaf a) (push lv ls)) as
push :: Lev -> TList a -> TList a
push lv (Tree t (Level lv' (Tree t' ls)))
| lv > lv' = push lv (Tree (bin lv' t' t) ls)
push lv ls = Level lv ls
fold :: TList a -> Tree a
fold (Tree t (Level lv (Tree t' ls))) = fold (Tree (bin lv t' t) ls)
fold (Tree t _) = t
fold _ = error "internal error"
bin :: Lev -> Tree a -> Tree a -> Tree a
bin lv l r = Bin lv tot l r
where
tot = size l + size r
insertAt' :: MonadRandom m => Dir -> Int -> a -> Tree a -> m (Tree a)
insertAt' d i a = fmap unfocus . insert d a . focus i
showRaz :: (a -> String) -> Raz a -> String
showRaz show (l', a, r') =
let
l = halfToList L l' []
r = reverse (halfToList R r' [])
in
(foldl stringify `flip` r) .
(\as -> as ++ ":" ++ show a ++ ":,") $
foldl stringify "" l
where
stringify as a = as ++ show a ++ ", "
treeToList :: Dir -> Tree a -> [a] -> [a]
treeToList d Empty = id
treeToList d (Leaf a) = (a :)
treeToList L (Bin _ _ l r) = treeToList L l . treeToList L r
treeToList R (Bin _ _ l r) = treeToList R r . treeToList R l
halfToList :: Dir -> TList a -> [a] -> [a]
halfToList d Nil = id
halfToList d (Cons a rest) = halfToList d rest . (a :)
halfToList d (Level _ rest) = halfToList d rest
halfToList d (Tree t rest) = halfToList d rest . treeToList d t
showTree :: (a -> String) -> Tree a -> String
showTree show' Empty = "Empty"
showTree show' (Leaf a) = show' a
showTree show' (Bin lv _ l r) =
"(" ++ showTree show' l ++ ") " ++
show lv ++
" (" ++ showTree show' r ++ ")"