• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

msakai / data-interval / 74

07 Jun 2025 02:12PM UTC coverage: 86.789% (-0.05%) from 86.837%
74

push

github

web-flow
Merge 0e36d5686 into 8f4ec0ead

992 of 1143 relevant lines covered (86.79%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.88
/src/Data/IntervalMap/Strict.hs
1
{-# OPTIONS_GHC -Wall #-}
2
{-# LANGUAGE BangPatterns, TupleSections #-}
3
{-# LANGUAGE Safe #-}
4
-----------------------------------------------------------------------------
5
-- |
6
-- Module      :  Data.IntervalMap.Base
7
-- Copyright   :  (c) Masahiro Sakai 2016
8
-- License     :  BSD-style
9
--
10
-- Maintainer  :  masahiro.sakai@gmail.com
11
-- Stability   :  provisional
12
-- Portability :  non-portable (BangPatterns, TupleSections)
13
--
14
-- Mapping from intervals to values.
15
--
16
-- API of this module is strict in both the keys and the values.
17
-- If you need value-lazy maps, use "Data.IntervalMap.Lazy" instead.
18
-- The 'IntervalMap' type itself is shared between the lazy and strict modules,
19
-- meaning that the same 'IntervalMap' value can be passed to functions in
20
-- both modules (although that is rarely needed).
21
--
22
-- These modules are intended to be imported qualified, to avoid name
23
-- clashes with Prelude functions, e.g.
24
--
25
-- >  import Data.IntervalMap.Strict (IntervalMap)
26
-- >  import qualified Data.IntervalMap.Strict as IntervalMap
27
--
28
-----------------------------------------------------------------------------
29
module Data.IntervalMap.Strict
30
  (
31
  -- * Strictness properties
32
  -- $strictness
33

34
  -- * IntervalMap type
35
    IntervalMap
36
  , module Data.ExtendedReal
37

38
  -- * Operators
39
  , (!)
40
  , (\\)
41

42
  -- * Query
43
  , null
44
  , member
45
  , notMember
46
  , lookup
47
  , findWithDefault
48
  , span
49

50
  -- * Construction
51
  , whole
52
  , empty
53
  , singleton
54

55
  -- ** Insertion
56
  , insert
57
  , insertWith
58

59
  -- ** Delete\/Update
60
  , delete
61
  , adjust
62
  , update
63
  , alter
64

65
  -- * Combine
66
  , union
67
  , unionWith
68
  , unions
69
  , unionsWith
70
  , intersection
71
  , intersectionWith
72
  , difference
73

74
  -- * Traversal
75
  , map
76
  , mapKeysMonotonic
77

78
  -- * Conversion
79
  , elems
80
  , keys
81
  , assocs
82
  , keysSet
83

84
  -- ** List
85
  , fromList
86
  , fromListWith
87
  , toList
88

89
  -- ** Ordered List
90
  , toAscList
91
  , toDescList
92

93
  -- * Filter
94
  , filter
95
  , split
96

97
  -- * Submap
98
  , isSubmapOf
99
  , isSubmapOfBy
100
  , isProperSubmapOf
101
  , isProperSubmapOfBy
102
  )
103
  where
104

105

106
import Prelude hiding (null, lookup, map, filter, span)
107
import Data.ExtendedReal
108
import Data.Interval (Interval)
109
import qualified Data.Interval as Interval
110
import Data.IntervalMap.Base hiding
111
  ( whole
112
  , singleton
113
  , insert
114
  , insertWith
115
  , adjust
116
  , update
117
  , alter
118
  , unionWith
119
  , unionsWith
120
  , intersectionWith
121
  , map
122
  , fromList
123
  , fromListWith
124
  )
125
import qualified Data.IntervalMap.Base as B
126
import qualified Data.IntervalSet as IntervalSet
127
import Data.List (foldl')
128
import qualified Data.Map.Strict as Map
129

130
-- $strictness
131
--
132
-- This module satisfies the following strictness properties:
133
--
134
-- 1. Key arguments are evaluated to WHNF;
135
--
136
-- 2. Keys and values are evaluated to WHNF before they are stored in
137
--    the map.
138
--
139
-- Here's an example illustrating the first property:
140
--
141
-- > delete undefined m  ==  undefined
142
--
143
-- Here are some examples that illustrate the second property:
144
--
145
-- > map (\ v -> undefined) m  ==  undefined      -- m is not empty
146
-- > mapKeysMonotonic (\ k -> undefined) m  ==  undefined  -- m is not empty
147

148
-- | The map that maps whole range of k to a.
149
whole :: Ord k => a -> IntervalMap k a
150
whole !a = B.whole a
1✔
151

152
-- | A map with a single interval.
153
singleton :: Ord k => Interval k -> a -> IntervalMap k a
154
singleton i !a = B.singleton i a
1✔
155

156
-- | insert a new key and value in the map.
157
-- If the key is already present in the map, the associated value is
158
-- replaced with the supplied value.
159
insert :: Ord k => Interval k -> a -> IntervalMap k a -> IntervalMap k a
160
insert i !a m = B.insert i a m
1✔
161

162
-- | Insert with a function, combining new value and old value.
163
-- @'insertWith' f key value mp@ will insert the pair (interval, value) into @mp@.
164
-- If the interval overlaps with existing entries, the value for the entry is replace
165
-- with @(f new_value old_value)@.
166
insertWith :: Ord k => (a -> a -> a) -> Interval k -> a -> IntervalMap k a -> IntervalMap k a
167
insertWith _ i _ m | Interval.null i = m
1✔
168
insertWith f i !a m = alter g i m
1✔
169
  where
170
    g Nothing = Just a
1✔
171
    g (Just a') = Just $! f a a'
1✔
172

173
-- | Update a value at a specific interval with the result of the provided function.
174
-- When the interval does not overlatp with the map, the original map is returned.
175
adjust :: Ord k => (a -> a) -> Interval k -> IntervalMap k a -> IntervalMap k a
176
adjust f = update (Just . f)
1✔
177

178
-- | The expression (@'update' f i map@) updates the value @x@
179
-- at @i@ (if it is in the map). If (@f x@) is 'Nothing', the element is
180
-- deleted. If it is (@'Just' y@), the key @i@ is bound to the new value @y@.
181
update :: Ord k => (a -> Maybe a) -> Interval k -> IntervalMap k a -> IntervalMap k a
182
update _ i m | Interval.null i = m
1✔
183
update f i m =
184
  case split i m of
1✔
185
    (IntervalMap m1, IntervalMap m2, IntervalMap m3) ->
186
      IntervalMap $ Map.unions [m1, Map.mapMaybe (\(j,a) -> (\b -> seq b (j,b)) <$> f a) m2, m3]
1✔
187

188
-- | The expression (@'alter' f i map@) alters the value @x@ at @i@, or absence thereof.
189
-- 'alter' can be used to insert, delete, or update a value in a 'IntervalMap'.
190
alter :: Ord k => (Maybe a -> Maybe a) -> Interval k -> IntervalMap k a -> IntervalMap k a
191
alter _ i m | Interval.null i = m
1✔
192
alter f i m =
193
  case split i m of
1✔
194
    (IntervalMap m1, IntervalMap m2, IntervalMap m3) ->
195
      let m2' = Map.mapMaybe (\(j,a) -> (\b -> seq b (j,b)) <$> f (Just a)) m2
1✔
196
          js = IntervalSet.singleton i `IntervalSet.difference` keysSet (IntervalMap m2)
1✔
197
          IntervalMap m2'' =
198
            case f Nothing of
1✔
199
              Nothing -> empty
1✔
200
              Just !a -> B.fromList [(j,a) | j <- IntervalSet.toList js]
1✔
201
      in seq m2' $ IntervalMap $ Map.unions [m1, m2', m2'', m3]
1✔
202

203
-- ------------------------------------------------------------------------
204
-- Combine
205

206
-- | Union with a combining function.
207
unionWith :: Ord k => (a -> a -> a) -> IntervalMap k a -> IntervalMap k a -> IntervalMap k a
208
unionWith f m1 m2 =
1✔
209
  foldl' (\m (i,a) -> insertWith f i a m) m2 (toList m1)
1✔
210

211
-- | The union of a list of maps, with a combining operation:
212
--   (@'unionsWith' f == 'Prelude.foldl' ('unionWith' f) 'empty'@).
213
unionsWith :: Ord k => (a -> a -> a) -> [IntervalMap k a] -> IntervalMap k a
214
unionsWith f = foldl' (unionWith f) empty
×
215

216
-- | Intersection with a combining function.
217
intersectionWith :: Ord k => (a -> b -> c) -> IntervalMap k a -> IntervalMap k b -> IntervalMap k c
218
intersectionWith f im1@(IntervalMap m1) im2@(IntervalMap m2)
1✔
219
  | Map.size m1 >= Map.size m2 = g f im1 im2
1✔
220
  | otherwise = g (flip f) im2 im1
1✔
221
  where
222
    g :: Ord k => (a -> b -> c) -> IntervalMap k a -> IntervalMap k b -> IntervalMap k c
223
    g h jm1 (IntervalMap m3) = IntervalMap $ Map.unions $ go jm1 (Map.elems m3)
1✔
224
      where
225
        go _ [] = []
1✔
226
        go im ((i,b) : xs) =
227
          case split i im of
1✔
228
            (_, IntervalMap m, jm2) ->
229
              Map.map (\(j, a) -> (j,) $! h a b) m : go jm2 xs
1✔
230

231
-- ------------------------------------------------------------------------
232
-- Traversal
233

234
-- | Map a function over all values in the map.
235
map :: (a -> b) -> IntervalMap k a -> IntervalMap k b
236
map f (IntervalMap m) = IntervalMap $ Map.map (\(i, a) -> (i,) $! f a) m
1✔
237

238
-- ------------------------------------------------------------------------
239
-- Conversion
240

241
-- | Build a map from a list of key\/value pairs.
242
-- If the list contains more than one value for the same key, the last value
243
-- for the key is retained.
244
fromList :: Ord k => [(Interval k, a)] -> IntervalMap k a
245
fromList = foldl' (\m (i,a) -> insert i a m) empty
1✔
246

247
-- | Build a map from a list of key\/value pairs with a combining function.
248
fromListWith :: Ord k => (a -> a -> a) -> [(Interval k, a)] -> IntervalMap k a
249
fromListWith f = foldl' (\m (i,a) -> insertWith f i a m) empty
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc