{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE CPP #-}
#if MIN_VERSION_base(4,9,0)
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
#endif
module Foundation.Collection.Indexed
( IndexedCollection(..)
) where
import Basement.Compat.Base
import Basement.Numerical.Additive ((+))
import Basement.Types.OffsetSize
import Foundation.Collection.Element
import qualified Data.List
import qualified Basement.Block as BLK
import qualified Basement.UArray as UV
import qualified Basement.BoxedArray as BA
import qualified Basement.Exception as A
import qualified Basement.String as S
#if MIN_VERSION_base(4,9,0)
import qualified Basement.Sized.Block as BLKN
import qualified Basement.Sized.List as LN
import Basement.Nat
#endif
class IndexedCollection c where
(!) :: c -> Offset (Element c) -> Maybe (Element c)
findIndex :: (Element c -> Bool) -> c -> Maybe (Offset (Element c))
instance IndexedCollection [a] where
(!) l (Offset n)
| n < 0 = Nothing
| otherwise = case Data.List.drop n l of
[] -> Nothing
x:_ -> Just x
findIndex predicate = fmap Offset . Data.List.findIndex predicate
instance UV.PrimType ty => IndexedCollection (BLK.Block ty) where
(!) l n
| A.isOutOfBound n (BLK.length l) = Nothing
| otherwise = Just $ BLK.index l n
findIndex predicate c = loop 0
where
!len = BLK.length c
loop i
| i .==# len = Nothing
| predicate (BLK.unsafeIndex c i) = Just i
| otherwise = loop (i + 1)
instance UV.PrimType ty => IndexedCollection (UV.UArray ty) where
(!) l n
| A.isOutOfBound n (UV.length l) = Nothing
| otherwise = Just $ UV.index l n
findIndex predicate c = loop 0
where
!len = UV.length c
loop i
| i .==# len = Nothing
| predicate (UV.unsafeIndex c i) = Just i
| otherwise = Nothing
instance IndexedCollection (BA.Array ty) where
(!) l n
| A.isOutOfBound n (BA.length l) = Nothing
| otherwise = Just $ BA.index l n
findIndex predicate c = loop 0
where
!len = BA.length c
loop i
| i .==# len = Nothing
| otherwise =
if predicate (BA.unsafeIndex c i) then Just i else Nothing
instance IndexedCollection S.String where
(!) = S.index
findIndex = S.findIndex
#if MIN_VERSION_base(4,9,0)
instance (NatWithinBound Int n, KnownNat n) => IndexedCollection (LN.ListN n a) where
(!) c off
| A.isOutOfBound off (LN.length c) = Nothing
| otherwise = Just $ LN.index c off
findIndex predicate c = loop 0
where
!len = LN.length c
loop i
| i .==# len = Nothing
| predicate (LN.index c i) = Just i
| otherwise = loop (i + 1)
instance (NatWithinBound (CountOf ty) n, KnownNat n, UV.PrimType ty) => IndexedCollection (BLKN.BlockN n ty) where
(!) c off
| A.isOutOfBound off (BLKN.length c) = Nothing
| otherwise = Just $ BLKN.index c off
findIndex predicate c = loop 0
where
!len = BLKN.length c
loop i
| i .==# len = Nothing
| predicate (BLKN.index c i) = Just i
| otherwise = loop (i + 1)
#endif