module Utils.Test.EnforceRange
(enforceRange, CanEnforceRange)
where
import Numeric.MixedTypes.PreludeHiding
import Numeric.MixedTypes.Literals
import Numeric.MixedTypes.Bool
import Numeric.MixedTypes.Ord
import Numeric.MixedTypes.MinMaxAbs
import Numeric.MixedTypes.AddSub
import Numeric.MixedTypes.Ring
import Numeric.MixedTypes.Field
import Numeric.MixedTypes.Round
type CanEnforceRange t b =
(CanAddSubMulDivCNBy t Integer
, CanAddSameType t, CanSubSameType t, CanAbsSameType t
, CanDivIModIntegerSameType t
, ConvertibleExactly b t
, HasOrderCertainly t t)
enforceRange ::
(CanEnforceRange t b) => (Maybe b, Maybe b) -> t -> t
enforceRange (Just l_, Just u_) (a::t)
| not (l !<! u) = error "enforceRange: inconsistent range"
| l !<! a && a !<! u = a
| l !<! b && b !<! u = b
| otherwise = (u-l)/!2
where
l = convertExactly l_ :: t
u = convertExactly u_ :: t
b = l + ((abs a) `modNoCN` (u-l))
enforceRange (Just l_, _) (a::t)
| l !<! a = a
| otherwise = (2*l-a+1)
where
l = convertExactly l_ :: t
enforceRange (_, Just u_) (a::t)
| a !<! u = a
| otherwise = (2*u-a-1)
where
u = convertExactly u_ :: t
enforceRange _ a = a