File: Indexed.hs

package info (click to toggle)
haskell-foundation 0.0.30-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 932 kB
  • sloc: haskell: 9,124; ansic: 570; makefile: 7
file content (114 lines) | stat: -rw-r--r-- 3,928 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
-- |
-- Module      : Foundation.Array.Indexed
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : portable
--
{-# 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

-- | Collection of elements that can indexed by int
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                      = loop (i + 1)

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 loop (i + 1)

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