-- | Debugging infrastructure for the parallel arrays library. module Data.Array.Parallel.Base.Debug ( check , checkCritical , checkLen , checkSlice , checkEq , checkNotEmpty , uninitialised) where import Data.Array.Parallel.Base.Config (debug, debugCritical) -- | Throw an index-out-of-bounds error. errorOfBounds :: String -> Int -> Int -> a errorOfBounds loc n i = error $ loc ++ ": Out of bounds " ++ "(vector length = " ++ show n ++ "; index = " ++ show i ++ ")" -- | Throw a bad slice error. errorBadSlice :: String -> Int -> Int -> Int -> a errorBadSlice loc vecLen sliceStart sliceLen = error $ loc ++ ": Bad slice " ++ "(vecLen = " ++ show vecLen ++ "; sliceStart = " ++ show sliceStart ++ "; sliceLen = " ++ show sliceLen ++ ")" -- | Bounds check, enabled when `debug` = `True`. -- -- The first integer is the length of the array, and the second -- is the index. The second must be greater or equal to '0' and less than -- the first integer. If the not then `error` with the `String`. -- check :: String -> Int -> Int -> a -> a check loc n i v | debug = if i >= 0 && i < n then v else errorOfBounds loc n i | otherwise = v {-# INLINE check #-} -- | Bounds check, enabled when `debugCritical` = `True`. -- -- This version is used to check operations that could corrupt the heap. -- -- The first integer is the length of the array, and the second -- is the index. The second must be greater or equal to '0' and less than -- the first integer. If the not then `error` with the `String`. -- checkCritical :: String -> Int -> Int -> a -> a checkCritical loc n i v | debugCritical = if i >= 0 && i < n then v else errorOfBounds loc n i | otherwise = v {-# INLINE checkCritical #-} -- | Length check, enabled when `debug` = `True`. -- -- Check that the second integer is greater or equal to `0' and less or equal -- than the first integer. If the not then `error` with the `String`. -- checkLen :: String -> Int -> Int -> a -> a checkLen loc n i v | debug = if i >= 0 && i <= n then v else errorOfBounds loc n i | otherwise = v {-# INLINE checkLen #-} -- | Slice check, enable when `debug` = `True`. -- -- The vector must contain at least `sliceStart` + `sliceLen` elements. -- checkSlice :: String -> Int -> Int -> Int -> a -> a checkSlice loc vecLen sliceStart sliceLen v | debug = if ( sliceStart >= 0 && sliceStart <= vecLen && sliceStart + sliceLen >= 0 && sliceStart + sliceLen <= vecLen ) then v else errorBadSlice loc vecLen sliceStart sliceLen | otherwise = v {-# INLINE checkSlice #-} -- | Equality check, enabled when `debug` = `True`. -- -- The two `a` values must be equal, else `error`. -- -- The first `String` gives the location of the error, -- and the second some helpful message. -- checkEq :: (Eq a, Show a) => String -> String -> a -> a -> b -> b checkEq loc msg x y v | debug = if x == y then v else error $ loc ++ ": " ++ msg ++ " (first = " ++ show x ++ "; second = " ++ show y ++ ")" | otherwise = v {-# INLINE checkEq #-} -- | Given an array length, check it is not zero. checkNotEmpty :: String -> Int -> a -> a checkNotEmpty loc n v | debug = if n /= 0 then v else error $ loc ++ ": Empty array" | otherwise = v {-# INLINE checkNotEmpty #-} -- | Throw an error saying something was not intitialised. -- -- The `String` must contain a helpful message saying what module -- the error occured in, and the possible reasons for it. -- If not then a puppy dies at compile time. -- uninitialised :: String -> a uninitialised loc = error $ loc ++ ": Touched an uninitialised value"