-- | This module exports everything that @Data.PrimitiveArray@ exports, but
-- it will do some bounds-checking on certain operations.
--
-- Checked are: @(!)@

module Data.PrimitiveArray.Checked
  ( module Data.PrimitiveArray
  , (!)
  ) where

import qualified Data.Vector.Generic as VG

import           Data.PrimitiveArray hiding ((!))

-- | Bounds-checked version of indexing.
--
-- First, we check via @inBounds@, second we check if the linear index is
-- outside of the allocated area.

--(!) :: PrimArrayOps arr sh elm => arr sh elm -> sh -> elm
(!) arr :: Dense v sh p
arr@(Dense LimitType sh
h v p
v) sh
idx
  | Bool -> Bool
not (LimitType sh -> sh -> Bool
forall i. Index i => LimitType i -> i -> Bool
inBounds (Dense v sh p -> LimitType sh
forall (arr :: * -> * -> *) sh elm.
PrimArrayOps arr sh elm =>
arr sh elm -> LimitType sh
upperBound Dense v sh p
arr) sh
idx) = [Char] -> p
forall a. HasCallStack => [Char] -> a
error ([Char] -> p) -> [Char] -> p
forall a b. (a -> b) -> a -> b
$ [Char]
"(!) / inBounds: out of bounds! " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ (LimitType sh, sh) -> [Char]
forall a. Show a => a -> [Char]
show (LimitType sh
h,sh
idx)
  | Int
li Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
li Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
len = [Char] -> p
forall a. HasCallStack => [Char] -> a
error ([Char] -> p) -> [Char] -> p
forall a b. (a -> b) -> a -> b
$ [Char]
"(!) / linearIndex: out of bounds! " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ (LimitType sh, Int, Int, sh) -> [Char]
forall a. Show a => a -> [Char]
show (LimitType sh
h,Int
li,Int
len,sh
idx)
  | Bool
otherwise = Dense v sh p -> sh -> p
forall (arr :: * -> * -> *) sh elm.
PrimArrayOps arr sh elm =>
arr sh elm -> sh -> elm
unsafeIndex Dense v sh p
arr sh
idx
  where li :: Int
li  = LimitType sh -> sh -> Int
forall i. Index i => LimitType i -> i -> Int
linearIndex LimitType sh
h sh
idx
        len :: Int
len = v p -> Int
forall (v :: * -> *) a. Vector v a => v a -> Int
VG.length v p
v
{-# Inline (!) #-}