radix-tree-1.0.0.2: src/Data/Zebra/Word/Debug.hs
{-# LANGUAGE BangPatterns #-}
{-|
Safe functions for datatype introspection.
-}
module Data.Zebra.Word.Debug
( -- * Show
showsTree
-- * Validate
, Validity (..)
, Reason (..)
, validate
) where
import Data.Zebra.Word.Internal
import Numeric.Long
import Radix.Word.Foundation
import Radix.Word.Debug
-- | \(\mathcal{O}(n)\).
-- Shows the internal structure of the tree.
showsTree :: Zebra -> ShowS
showsTree = go 0
where
go i t =
mappend (replicate i ' ') .
case t of
Bin p l r ->
showString "Bin " . showPrefix p . showChar '\n'
. go (i + 2) l . showChar '\n'
. go (i + 2) r
Bla k -> goTip Black k
Whi k -> goTip White k
Nil c -> showString "Nil " . showChar (color c)
goTip c k =
showString "Tip " . showLongBin k . showString " => " . showChar (color c)
color Black = 'B'
color White = 'W'
-- | Whether the tree is well-formed.
data Validity = Valid
| Invalid Reason
deriving Show
-- | Reason for why the tree is considered malformed.
data Reason = -- | Prefix is @0@.
ZeroPrefix
-- | Prefix below diverges from the prefix above
| PrefixBelow Prefix Prefix
-- | Key diverges the prefix above
| KeyBelow Prefix Key
-- | Nil is in the tree.
| FoundNil
-- | Tip has a value of zero despite not being the root.
| ZeroKey
-- | Key has the same color as the key to the left of it.
| NoSwitch Color Key
deriving Show
data Carry = Carry Color
| Break Reason
-- | \(\mathcal{O}(n)\).
-- Checks whether the tree is well-formed.
validate :: Zebra -> Validity
validate t0 =
case go0 t0 of
Carry _ -> Valid
Break r -> Invalid r
where
go0 t =
case t of
Bin p l r
| p == 0 -> Break ZeroPrefix
| otherwise ->
case go L p l Nothing of
Carry cR -> go R p r (Just cR)
err -> err
Bla _ -> Carry Black
Whi _ -> Carry White
Nil _ -> Break FoundNil
go s q x cL =
case x of
Bin p l r
| p == 0 -> Break ZeroPrefix
| not $ validPrefix q s p -> Break $ PrefixBelow q p
| otherwise ->
case go L p l cL of
Carry cR -> go R p r (Just cR)
err -> err
Bla k -> goTip s q k cL Black
Whi k -> goTip s q k cL White
Nil _ -> Break FoundNil
goTip s q k cL c
| k == 0 = Break ZeroKey
| not $ validKey q s k = Break $ KeyBelow q k
| Just x <- cL, x == c = Break $ NoSwitch c k
| otherwise = Carry c