packages feed

liquidhaskell-0.8.10.7: benchmarks/text-0.11.2.3/Data/Text/Fusion/Size.hs

{-@ LIQUID "--no-totality" @-}
{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -fno-warn-missing-methods #-}
-- |
-- Module      : Data.Text.Fusion.Internal
-- Copyright   : (c) Roman Leshchinskiy 2008,
--               (c) Bryan O'Sullivan 2009
--
-- License     : BSD-style
-- Maintainer  : bos@serpentine.com, rtomharper@googlemail.com,
--               duncan@haskell.org
-- Stability   : experimental
-- Portability : portable
--
-- Size hints.

module Data.Text.Fusion.Size
    (
      Size(..)
    , exactly
    , exactSize
    , maxSize
    , unknownSize
    , smaller
    , larger
    , upperBound
    , isEmpty
    ) where

import Language.Haskell.Liquid.Prelude

#if defined(ASSERTS)
import Control.Exception (assert)
#endif

data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.
          | Max   {-# UNPACK #-} !Int -- ^ Upper bound on size.
          | Unknown                   -- ^ Unknown size.
            deriving (Eq, Show)

{-@
data Size = Exact { getExact :: Nat }
          | Max   { getMax   :: Nat } 
          | Unknown
@-}

{-@ type SizeN N = {v:Size | (((getSize v) = n) && (not (isUnknown v)))} @-}

{-@ measure getSize @-}
{-@ getSize :: Size -> Nat @-}
getSize :: Size -> Int
getSize (Data.Text.Fusion.Size.Exact n) = n
getSize (Data.Text.Fusion.Size.Max   n) = n

{-@ measure isUnknown @-}
isUnknown :: Size -> Bool
isUnknown (Data.Text.Fusion.Size.Exact n) = False
isUnknown (Data.Text.Fusion.Size.Max   n) = False
isUnknown (Data.Text.Fusion.Size.Unknown) = True

{-@ qualif IsUnknown(v:Data.Text.Fusion.Size.Size) : (isUnknown v) @-}
{-@ qualif IsKnown(v:Data.Text.Fusion.Size.Size) : not (isUnknown v) @-}

{-@ invariant {v:Data.Text.Fusion.Size.Size | (getSize v) >= 0} @-}

exactly :: Size -> Maybe Int
exactly (Exact n) = Just n
exactly _         = Nothing
{-# INLINE exactly #-}

{-@ exactSize :: n:Nat -> SizeN n @-}
exactSize :: Int -> Size
exactSize n =
#if defined(ASSERTS)
    assert (n >= 0)
#endif
    Exact n
{-# INLINE exactSize #-}

{-@ maxSize :: n:Nat -> SizeN n @-}
maxSize :: Int -> Size
maxSize n =
#if defined(ASSERTS)
    assert (n >= 0)
#endif
    Max n
{-# INLINE maxSize #-}

{-@ unknownSize :: {v:Size | (isUnknown v)} @-}
unknownSize :: Size
unknownSize = Unknown
{-# INLINE unknownSize #-}

--LIQUID: need intersection types for type-classes here..
instance Num Size where
    (+) = addSize
    (-) = \x y -> let y' = (le y x) in subtractSize x y'
    (*) = \x y -> let y' = n0 y in mulSize x y'

    fromInteger = f where f = Exact . g0 . fromInteger
                          {-# INLINE f #-}

{-@ assume le :: y:Size -> x:Size -> {v:Size | getSize v <= getSize x} @-}
le :: Size -> Size -> Size
le y x = y

{-@ assume n0 :: Size -> {v:Size | getSize v /= 0} @-}
n0 :: Size -> Size
n0 x = x

{-@ assume g0 :: Int -> Nat @-}
g0 :: Int -> Int
g0 x = x

add :: Int -> Int -> Int
add m n | mn >=   0 = mn
        | otherwise = overflowError
  where mn = m + n
{-# INLINE add #-}

addSize :: Size -> Size -> Size
addSize (Exact m) (Exact n) = Exact (add m n)
addSize (Exact m) (Max   n) = Max   (add m n)
addSize (Max   m) (Exact n) = Max   (add m n)
addSize (Max   m) (Max   n) = Max   (add m n)
addSize _          _       = Unknown
{-# INLINE addSize #-}

{-@ subtractSize :: x:Size -> {v:Size | getSize v <= getSize x} -> Size @-}
subtractSize :: Size -> Size -> Size
subtractSize   (Exact m) (Exact n) = Exact (max (m-n) 0)
subtractSize   (Exact m) (Max   _) = Max   m
subtractSize   (Max   m) (Exact n) = Max   (max (m-n) 0)
subtractSize a@(Max   _) (Max   _) = a
subtractSize a@(Max   _) Unknown   = a
subtractSize _         _           = Unknown
{-# INLINE subtractSize #-}

{-@ mul :: Nat -> {v:Nat | v > 0} -> Nat @-}
mul :: Int -> Int -> Int
mul m n
    | m <= maxBound `div` n = m * n
    | otherwise             = overflowError
{-# INLINE mul #-}

{-@ mulSize :: Size -> {v:Size | getSize v /= 0} -> Size @-}
mulSize :: Size -> Size -> Size
mulSize (Exact m) (Exact n) = Exact (mul m n)
mulSize (Exact m) (Max   n) = Max   (mul m n)
mulSize (Max   m) (Exact n) = Max   (mul m n)
mulSize (Max   m) (Max   n) = Max   (mul m n)
mulSize _          _        = Unknown
{-# INLINE mulSize #-}

-- | Minimum of two size hints.
smaller :: Size -> Size -> Size
smaller   (Exact m) (Exact n) = Exact (m `min` n)
smaller   (Exact m) (Max   n) = Max   (m `min` n)
smaller   (Exact m) Unknown   = Max   m
smaller   (Max   m) (Exact n) = Max   (m `min` n)
smaller   (Max   m) (Max   n) = Max   (m `min` n)
smaller a@(Max   _) Unknown   = a
smaller   Unknown   (Exact n) = Max   n
smaller   Unknown   (Max   n) = Max   n
smaller   Unknown   Unknown   = Unknown
{-# INLINE smaller #-}


{-@ predicate MyMax V X Y = if X > Y then V = X else V = Y @-}

-- | Maximum of two size hints.
{-@ larger :: s1:Size -> s2:Size 
           -> {v:Size | ((not ((isUnknown s1) || (isUnknown s2))) => (MyMax (getSize v) (getSize s1) (getSize s2)))}
  @-}

larger :: Size -> Size -> Size
larger   (Exact m)   (Exact n)             = Exact (m `max` n)
larger a@(Exact m) b@(Max   n) | m >= n    = a
                               | otherwise = b
larger a@(Max   m) b@(Exact n) | n >= m    = b
                               | otherwise = a
larger   (Max   m)   (Max   n)             = Max   (m `max` n)
larger _             _                     = Unknown
{-# INLINE larger #-}

-- | Compute the maximum size from a size hint, if possible.
{-@ upperBound :: k:Nat -> s:Size -> {v:Nat | v = if (isUnknown s) then k else (getSize s) } @-}
upperBound :: Int -> Size -> Int
upperBound _ (Exact n) = n
upperBound _ (Max   n) = n
upperBound k _         = k
{-# INLINE upperBound #-}

{-@ isEmpty :: s:Size
            -> {v:Bool | v <=> ((not (isUnknown s) && (getSize s = 0))) }
  @-}
isEmpty :: Size -> Bool
isEmpty (Exact n) = n <= 0
isEmpty (Max   n) = n <= 0
isEmpty _         = False
{-# INLINE isEmpty #-}

{-@ overflowError :: Nat @-}
overflowError :: Int
overflowError = unsafeError "Data.Text.Fusion.Size: size overflow"