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

msakai / data-interval / 80

30 Aug 2025 08:23PM UTC coverage: 86.789% (+0.09%) from 86.702%
80

push

github

Bodigrim
Fix warnings

1 of 4 new or added lines in 4 files covered. (25.0%)

87 existing lines in 4 files now uncovered.

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

82.93
/src/Data/IntervalMap/Base.hs
1
{-# OPTIONS_GHC -Wall #-}
2
{-# LANGUAGE CPP, LambdaCase, ScopedTypeVariables, TypeFamilies, MultiWayIf, GeneralizedNewtypeDeriving #-}
3
{-# LANGUAGE Trustworthy #-}
4
{-# LANGUAGE RoleAnnotations #-}
5
-----------------------------------------------------------------------------
6
-- |
7
-- Module      :  Data.IntervalMap.Base
8
-- Copyright   :  (c) Masahiro Sakai 2016
9
-- License     :  BSD-style
10
--
11
-- Maintainer  :  masahiro.sakai@gmail.com
12
-- Stability   :  provisional
13
--
14
-- Interval datatype and interval arithmetic.
15
--
16
-----------------------------------------------------------------------------
17
module Data.IntervalMap.Base
18
  (
19
  -- * IntervalMap type
20
    IntervalMap (..)
21
  , module Data.ExtendedReal
22

23
  -- * Operators
24
  , (!)
25
  , (\\)
26

27
  -- * Query
28
  , null
29
  , member
30
  , notMember
31
  , lookup
32
  , findWithDefault
33
  , span
34

35
  -- * Construction
36
  , whole
37
  , empty
38
  , singleton
39

40
  -- ** Insertion
41
  , insert
42
  , insertWith
43

44
  -- ** Delete\/Update
45
  , delete
46
  , adjust
47
  , update
48
  , alter
49

50
  -- * Combine
51
  , union
52
  , unionWith
53
  , unions
54
  , unionsWith
55
  , intersection
56
  , intersectionWith
57
  , difference
58

59
  -- * Traversal
60
  , map
61
  , mapKeysMonotonic
62

63
  -- * Conversion
64
  , elems
65
  , keys
66
  , assocs
67
  , keysSet
68

69
  -- ** List
70
  , fromList
71
  , fromListWith
72
  , toList
73

74
  -- ** Ordered List
75
  , toAscList
76
  , toDescList
77

78
  -- * Filter
79
  , filter
80
  , split
81

82
  -- * Submap
83
  , isSubmapOf
84
  , isSubmapOfBy
85
  , isProperSubmapOf
86
  , isProperSubmapOfBy
87
  )
88
  where
89

90
import Prelude hiding (null, lookup, map, filter, span, and)
91
import Control.DeepSeq
92
import Data.Data
93
import Data.ExtendedReal
94
import Data.Hashable
95
import Data.Foldable hiding (null, toList)
96
import Data.Map (Map)
97
import qualified Data.Map as Map
98
import Data.Maybe
99
import qualified Data.Semigroup as Semigroup
100
import Data.Interval (Interval)
101
import qualified Data.Interval as Interval
102
import Data.IntervalSet (IntervalSet)
103
import qualified Data.IntervalSet as IntervalSet
104
import qualified GHC.Exts as GHCExts
105

106
-- ------------------------------------------------------------------------
107
-- The IntervalMap type
108

109
-- | A Map from non-empty, disjoint intervals over k to values a.
110
--
111
-- Unlike 'IntervalSet', 'IntervalMap' never merge adjacent mappings,
112
-- even if adjacent intervals are connected and mapped to the same value.
113
newtype IntervalMap r a = IntervalMap (Map (LB r) (Interval r, a))
114
  deriving
UNCOV
115
    ( Eq
×
116
    , Ord
×
117
      -- ^ Note that this Ord is derived and not semantically meaningful.
118
      -- The primary intended use case is to allow using 'IntervalSet'
119
      -- in maps and sets that require ordering.
120
    )
121

122
type role IntervalMap nominal representational
123

124
instance (Ord k, Show k, Show a) => Show (IntervalMap k a) where
125
  showsPrec p (IntervalMap m) = showParen (p > appPrec) $
1✔
126
    showString "fromList " .
1✔
UNCOV
127
    showsPrec (appPrec+1) (Map.elems m)
×
128

129
instance (Ord k, Read k, Read a) => Read (IntervalMap k a) where
130
  readsPrec p =
1✔
131
    (readParen (p > appPrec) $ \s0 -> do
1✔
132
      ("fromList",s1) <- lex s0
1✔
UNCOV
133
      (xs,s2) <- readsPrec (appPrec+1) s1
×
134
      return (fromList xs, s2))
1✔
135

136
appPrec :: Int
137
appPrec = 10
1✔
138

139
-- This instance preserves data abstraction at the cost of inefficiency.
140
-- We provide limited reflection services for the sake of data abstraction.
141

142
instance (Data k, Data a, Ord k) => Data (IntervalMap k a) where
143
  gfoldl k z x   = z fromList `k` toList x
1✔
UNCOV
144
  toConstr _     = fromListConstr
×
145
  gunfold k z c  = case constrIndex c of
×
146
    1 -> k (z fromList)
×
147
    _ -> error "gunfold"
×
148
  dataTypeOf _   = mapDataType
×
149
  dataCast1 f    = gcast1 f
×
150

151
fromListConstr :: Constr
UNCOV
152
fromListConstr = mkConstr mapDataType "fromList" [] Prefix
×
153

154
mapDataType :: DataType
UNCOV
155
mapDataType = mkDataType "Data.IntervalMap.Base.IntervalMap" [fromListConstr]
×
156

157
instance (NFData k, NFData a) => NFData (IntervalMap k a) where
158
  rnf (IntervalMap m) = rnf m
1✔
159

160
instance (Hashable k, Hashable a) => Hashable (IntervalMap k a) where
161
  hashWithSalt s m = hashWithSalt s (toList m)
1✔
162

163
instance Ord k => Monoid (IntervalMap k a) where
UNCOV
164
  mempty = empty
×
165
  mappend = (Semigroup.<>)
×
166
  mconcat = unions
×
167

168
instance Ord k => Semigroup.Semigroup (IntervalMap k a) where
169
  (<>)   = union
1✔
UNCOV
170
  stimes = Semigroup.stimesIdempotentMonoid
×
171

172
instance Ord k => GHCExts.IsList (IntervalMap k a) where
173
  type Item (IntervalMap k a) = (Interval k, a)
UNCOV
174
  fromList = fromList
×
175
  toList = toList
×
176

177
-- ------------------------------------------------------------------------
178

179
newtype LB r = LB (Extended r, Interval.Boundary)
NEW
180
  deriving (Eq, NFData)
×
181

182
instance Ord r => Ord (LB r) where
183
  compare (LB (lb1, lb1in)) (LB (lb2, lb2in)) =
1✔
184
    -- inclusive lower endpoint shuold be considered smaller
185
    (lb1 `compare` lb2) `mappend` (lb2in `compare` lb1in)
1✔
186

187
-- ------------------------------------------------------------------------
188
-- Operators
189

190
infixl 9 !,\\ --
191

192
-- | Find the value at a key. Calls 'error' when the element can not be found.
193
(!) :: Ord k => IntervalMap k a -> k -> a
194
IntervalMap m ! k =
1✔
195
  case Map.lookupLE (LB (Finite k, Interval.Closed)) m of
1✔
UNCOV
196
    Just (_, (i, a)) | k `Interval.member` i -> a
×
197
    _ -> error "IntervalMap.!: given key is not an element in the map"
×
198

199
-- | Same as 'difference'.
200
(\\) :: Ord k => IntervalMap k a -> IntervalMap k b -> IntervalMap k a
201
m1 \\ m2 = difference m1 m2
1✔
202

203
-- ------------------------------------------------------------------------
204
-- Query
205

206
-- | Is the map empty?
207
null :: Ord k => IntervalMap k a -> Bool
208
null (IntervalMap m) = Map.null m
1✔
209

210
-- | Is the key a member of the map? See also 'notMember'.
211
member :: Ord k => k -> IntervalMap k a -> Bool
212
member k (IntervalMap m) =
1✔
213
  case Map.lookupLE (LB (Finite k, Interval.Closed)) m of
1✔
214
    Just (_, (i, _)) -> k `Interval.member` i
1✔
215
    Nothing -> False
1✔
216

217
-- | Is the key not a member of the map? See also 'member'.
218
notMember :: Ord k => k -> IntervalMap k a -> Bool
219
notMember k m = not $ member k m
1✔
220

221
-- | Lookup the value at a key in the map.
222
--
223
-- The function will return the corresponding value as @('Just' value)@,
224
-- or 'Nothing' if the key isn't in the map.
225
lookup :: Ord k => k -> IntervalMap k a -> Maybe a
226
lookup k (IntervalMap m) =
1✔
227
  case Map.lookupLE (LB (Finite k, Interval.Closed)) m of
1✔
228
    Just (_, (i, a)) | k `Interval.member` i -> Just a
1✔
229
    _ -> Nothing
1✔
230

231
-- | The expression @('findWithDefault' def k map)@ returns
232
-- the value at key @k@ or returns default value @def@
233
-- when the key is not in the map.
234
findWithDefault :: Ord k => a -> k -> IntervalMap k a -> a
235
findWithDefault def k (IntervalMap m) =
1✔
236
  case Map.lookupLE (LB (Finite k, Interval.Closed)) m of
1✔
237
    Just (_, (i, a)) | k `Interval.member` i -> a
1✔
238
    _ -> def
1✔
239

240
lookupInterval :: Ord k => Interval k -> IntervalMap k a -> Maybe a
241
lookupInterval i (IntervalMap m) =
1✔
242
  case Map.lookupLE (LB (Interval.lowerBound' i)) m of
1✔
243
    Just (_, (j, a)) | i `Interval.isSubsetOf` j -> Just a
1✔
244
    _ -> Nothing
1✔
245

246
-- | convex hull of key intervals.
247
span :: Ord k => IntervalMap k a -> Interval k
248
span = IntervalSet.span . keysSet
1✔
249

250
-- ------------------------------------------------------------------------
251
-- Construction
252

253
-- | The empty map.
254
empty :: Ord k => IntervalMap k a
255
empty = IntervalMap Map.empty
1✔
256

257
-- | The map that maps whole range of k to a.
258
whole :: Ord k => a -> IntervalMap k a
259
whole a = IntervalMap $ Map.singleton (LB (Interval.lowerBound' i)) (i, a)
1✔
260
  where
261
    i = Interval.whole
1✔
262

263
-- | A map with a single interval.
264
singleton :: Ord k => Interval k -> a -> IntervalMap k a
265
singleton i a
1✔
266
  | Interval.null i = empty
1✔
267
  | otherwise = IntervalMap $ Map.singleton (LB (Interval.lowerBound' i)) (i, a)
1✔
268

269
-- ------------------------------------------------------------------------
270
-- Insertion
271

272
-- | insert a new key and value in the map.
273
-- If the key is already present in the map, the associated value is
274
-- replaced with the supplied value.
275
insert :: Ord k => Interval k -> a -> IntervalMap k a -> IntervalMap k a
276
insert i _ m | Interval.null i = m
1✔
277
insert i a m =
278
  case split i m of
1✔
279
    (IntervalMap m1, _, IntervalMap m2) ->
280
      IntervalMap $ Map.union m1 (Map.insert (LB (Interval.lowerBound' i)) (i,a) m2)
1✔
281

282

283
-- | Insert with a function, combining new value and old value.
284
-- @'insertWith' f key value mp@ will insert the pair (interval, value) into @mp@.
285
-- If the interval overlaps with existing entries, the value for the entry is replace
286
-- with @(f new_value old_value)@.
287
insertWith :: Ord k => (a -> a -> a) -> Interval k -> a -> IntervalMap k a -> IntervalMap k a
288
insertWith _ i _ m | Interval.null i = m
1✔
289
insertWith f i a m = alter g i m
1✔
290
  where
291
    g Nothing = Just a
1✔
292
    g (Just a') = Just $ f a a'
1✔
293

294
-- ------------------------------------------------------------------------
295
-- Delete/Update
296

297
-- | Delete an interval and its value from the map.
298
-- When the interval does not overlap with the map, the original map is returned.
299
delete :: Ord k => Interval k -> IntervalMap k a -> IntervalMap k a
300
delete i m | Interval.null i = m
1✔
301
delete i m =
302
  case split i m of
1✔
303
    (IntervalMap m1, _, IntervalMap m2) ->
304
      IntervalMap $ Map.union m1 m2
1✔
305

306
-- | Update a value at a specific interval with the result of the provided function.
307
-- When the interval does not overlatp with the map, the original map is returned.
308
adjust :: Ord k => (a -> a) -> Interval k -> IntervalMap k a -> IntervalMap k a
309
adjust f = update (Just . f)
1✔
310

311
-- | The expression (@'update' f i map@) updates the value @x@
312
-- at @i@ (if it is in the map). If (@f x@) is 'Nothing', the element is
313
-- deleted. If it is (@'Just' y@), the key @i@ is bound to the new value @y@.
314
update :: Ord k => (a -> Maybe a) -> Interval k -> IntervalMap k a -> IntervalMap k a
315
update _ i m | Interval.null i = m
1✔
316
update f i m =
317
  case split i m of
1✔
318
    (IntervalMap m1, IntervalMap m2, IntervalMap m3) ->
319
      IntervalMap $ Map.unions [m1, Map.mapMaybe (\(j,a) -> (\b -> (j,b)) <$> f a) m2, m3]
1✔
320

321
-- | The expression (@'alter' f i map@) alters the value @x@ at @i@, or absence thereof.
322
-- 'alter' can be used to insert, delete, or update a value in a 'IntervalMap'.
323
alter :: Ord k => (Maybe a -> Maybe a) -> Interval k -> IntervalMap k a -> IntervalMap k a
324
alter _ i m | Interval.null i = m
1✔
325
alter f i m =
326
  case split i m of
1✔
327
    (IntervalMap m1, IntervalMap m2, IntervalMap m3) ->
328
      let m2' = Map.mapMaybe (\(j,a) -> (\b -> (j,b)) <$> f (Just a)) m2
1✔
329
          js = IntervalSet.singleton i `IntervalSet.difference` keysSet (IntervalMap m2)
1✔
330
          IntervalMap m2'' =
331
            case f Nothing of
1✔
332
              Nothing -> empty
1✔
333
              Just a -> fromList [(j,a) | j <- IntervalSet.toList js]
1✔
334
      in IntervalMap $ Map.unions [m1, m2', m2'', m3]
1✔
335

336
-- ------------------------------------------------------------------------
337
-- Combine
338

339
-- | The expression (@'union' t1 t2@) takes the left-biased union of @t1@ and @t2@.
340
-- It prefers @t1@ when overlapping keys are encountered,
341
union :: Ord k => IntervalMap k a -> IntervalMap k a -> IntervalMap k a
342
union m1 m2 =
1✔
343
  foldl' (\m (i,a) -> insert i a m) m2 (toList m1)
1✔
344

345
-- | Union with a combining function.
346
unionWith :: Ord k => (a -> a -> a) -> IntervalMap k a -> IntervalMap k a -> IntervalMap k a
347
unionWith f m1 m2 =
1✔
348
  foldl' (\m (i,a) -> insertWith f i a m) m2 (toList m1)
1✔
349

350
-- | The union of a list of maps:
351
--   (@'unions' == 'Prelude.foldl' 'union' 'empty'@).
352
unions :: Ord k => [IntervalMap k a] -> IntervalMap k a
353
unions = foldl' union empty
1✔
354

355
-- | The union of a list of maps, with a combining operation:
356
--   (@'unionsWith' f == 'Prelude.foldl' ('unionWith' f) 'empty'@).
357
unionsWith :: Ord k => (a -> a -> a) -> [IntervalMap k a] -> IntervalMap k a
UNCOV
358
unionsWith f = foldl' (unionWith f) empty
×
359

360
-- | Return elements of the first map not existing in the second map.
361
difference :: Ord k => IntervalMap k a -> IntervalMap k b -> IntervalMap k a
362
difference m1 m2 = foldl' (\m i -> delete i m) m1 (IntervalSet.toList (keysSet m2))
1✔
363

364
-- | Intersection of two maps.
365
-- Return data in the first map for the keys existing in both maps.
366
intersection :: Ord k => IntervalMap k a -> IntervalMap k a -> IntervalMap k a
367
intersection = intersectionWith const
1✔
368

369
-- | Intersection with a combining function.
370
intersectionWith :: Ord k => (a -> b -> c) -> IntervalMap k a -> IntervalMap k b -> IntervalMap k c
371
intersectionWith f im1@(IntervalMap m1) im2@(IntervalMap m2)
1✔
372
  | Map.size m1 >= Map.size m2 = g f im1 im2
1✔
373
  | otherwise = g (flip f) im2 im1
1✔
374
  where
375
    g :: Ord k => (a -> b -> c) -> IntervalMap k a -> IntervalMap k b -> IntervalMap k c
376
    g h jm1 (IntervalMap m3) = IntervalMap $ Map.unions $ go jm1 (Map.elems m3)
1✔
377
      where
378
        go _ [] = []
1✔
379
        go im ((i,b) : xs) =
380
          case split i im of
1✔
381
            (_, IntervalMap m, jm2) ->
382
              Map.map (\(j, a) -> (j, h a b)) m : go jm2 xs
1✔
383

384
-- ------------------------------------------------------------------------
385
-- Traversal
386

387
instance Ord k => Functor (IntervalMap k) where
388
  fmap = map
1✔
389

390
instance Ord k => Foldable (IntervalMap k) where
391
  foldMap f (IntervalMap m) = foldMap (\(_,a) -> f a) m
1✔
392

393
instance Ord k => Traversable (IntervalMap k) where
394
  traverse f (IntervalMap m) = IntervalMap <$> traverse (\(i,a) -> (\b -> (i,b)) <$> f a) m
1✔
395

396
-- | Map a function over all values in the map.
397
map :: (a -> b) -> IntervalMap k a -> IntervalMap k b
398
map f (IntervalMap m) = IntervalMap $ Map.map (\(i, a) -> (i, f a)) m
1✔
399

400
-- | @'mapKeysMonotonic' f s@ is the map obtained by applying @f@ to each key of @s@.
401
-- @f@ must be strictly monotonic.
402
-- That is, for any values @x@ and @y@, if @x@ < @y@ then @f x@ < @f y@.
403
mapKeysMonotonic :: forall k1 k2 a. (Ord k1, Ord k2) => (k1 -> k2) -> IntervalMap k1 a -> IntervalMap k2 a
404
mapKeysMonotonic f = fromList . fmap g . toList
1✔
405
  where
406
    g :: (Interval k1, a) -> (Interval k2, a)
407
    g (i, a) = (Interval.mapMonotonic f i, a)
1✔
408

409
-- ------------------------------------------------------------------------
410

411
-- | Return all elements of the map in the ascending order of their keys.
412
elems :: IntervalMap k a -> [a]
UNCOV
413
elems (IntervalMap m) = [a | (_,a) <- Map.elems m]
×
414

415
-- | Return all keys of the map in ascending order. Subject to list
416
keys :: IntervalMap k a -> [Interval k]
417
keys (IntervalMap m) = [i | (i,_) <- Map.elems m]
1✔
418

419
-- | An alias for 'toAscList'. Return all key\/value pairs in the map
420
-- in ascending key order.
421
assocs :: IntervalMap k a -> [(Interval k, a)]
UNCOV
422
assocs = toAscList
×
423

424
-- | The set of all keys of the map.
425
keysSet :: Ord k => IntervalMap k a -> IntervalSet k
426
keysSet (IntervalMap m) = IntervalSet.fromAscList [i | (i,_) <- Map.elems m]
1✔
427

428
-- | Convert the map to a list of key\/value pairs.
429
toList :: IntervalMap k a -> [(Interval k, a)]
430
toList = toAscList
1✔
431

432
-- | Convert the map to a list of key/value pairs where the keys are in ascending order.
433
toAscList :: IntervalMap k a -> [(Interval k, a)]
434
toAscList (IntervalMap m) = Map.elems m
1✔
435

436
-- | Convert the map to a list of key/value pairs where the keys are in descending order.
437
toDescList :: IntervalMap k a -> [(Interval k, a)]
438
toDescList (IntervalMap m) = fmap snd $ Map.toDescList m
1✔
439

440
-- | Build a map from a list of key\/value pairs.
441
-- If the list contains more than one value for the same key, the last value
442
-- for the key is retained.
443
fromList :: Ord k => [(Interval k, a)] -> IntervalMap k a
444
fromList = foldl' (\m (i,a) -> insert i a m) empty
1✔
445

446
-- | Build a map from a list of key\/value pairs with a combining function.
447
fromListWith :: Ord k => (a -> a -> a) -> [(Interval k, a)] -> IntervalMap k a
448
fromListWith f = foldl' (\m (i,a) -> insertWith f i a m) empty
1✔
449

450
-- ------------------------------------------------------------------------
451
-- Filter
452

453
-- | Filter all values that satisfy some predicate.
454
filter :: Ord k => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
455
filter p (IntervalMap m) = IntervalMap $ Map.filter (\(_,a) -> p a) m
1✔
456

457
-- | The expression (@'split' i map@) is a triple @(map1,map2,map3)@ where
458
-- the keys in @map1@ are smaller than @i@, the keys in @map2@ are included in @i@, and the keys in @map3@ are larger than @i@.
459
split :: Ord k => Interval k -> IntervalMap k a -> (IntervalMap k a, IntervalMap k a, IntervalMap k a)
460
split i (IntervalMap m) =
1✔
461
  case splitLookupLE (LB (Interval.lowerBound' i)) m of
1✔
462
    (smaller, m1, xs) ->
463
      case splitLookupLE (LB (Interval.upperBound i, Interval.Closed)) xs of
1✔
464
        (middle, m2, larger) ->
465
          ( IntervalMap $
1✔
466
              case m1 of
1✔
467
                Nothing -> Map.empty
1✔
468
                Just (j,b) ->
469
                  let k = Interval.intersection (upTo i) j
1✔
470
                  in if Interval.null k
1✔
471
                     then smaller
1✔
472
                     else Map.insert (LB (Interval.lowerBound' k)) (k,b) smaller
1✔
473
          , IntervalMap $ Map.unions $ middle :
1✔
474
              [ Map.singleton (LB (Interval.lowerBound' k)) (k, b)
1✔
475
              | (j, b) <- maybeToList m1 ++ maybeToList m2
1✔
476
              , let k = Interval.intersection i j
1✔
477
              , not (Interval.null k)
1✔
478
              ]
479
          , IntervalMap $ Map.unions $ larger :
1✔
480
              [ Map.singleton (LB (Interval.lowerBound' k)) (k, b)
1✔
481
              | (j, b) <- maybeToList m1 ++ maybeToList m2
1✔
482
              , let k = Interval.intersection (downTo i) j
1✔
483
              , not (Interval.null k)
1✔
484
              ]
485
          )
486

487
-- ------------------------------------------------------------------------
488
-- Submap
489

490
-- | This function is defined as (@'isSubmapOf' = 'isSubmapOfBy' (==)@).
491
isSubmapOf :: (Ord k, Eq a) => IntervalMap k a -> IntervalMap k a -> Bool
492
isSubmapOf = isSubmapOfBy (==)
1✔
493

494
-- |  The expression (@'isSubmapOfBy' f t1 t2@) returns 'True' if
495
-- all keys in @t1@ are in tree @t2@, and when @f@ returns 'True' when
496
-- applied to their respective values.
497
isSubmapOfBy :: Ord k => (a -> b -> Bool) -> IntervalMap k a -> IntervalMap k b -> Bool
498
isSubmapOfBy f m1 m2 = and $
1✔
499
  [ case lookupInterval i m2 of
1✔
500
      Nothing -> False
1✔
501
      Just b -> f a b
1✔
502
  | (i,a) <- toList m1 ]
1✔
503

504
-- |  Is this a proper submap? (ie. a submap but not equal).
505
-- Defined as (@'isProperSubmapOf' = 'isProperSubmapOfBy' (==)@).
506
isProperSubmapOf :: (Ord k, Eq a) => IntervalMap k a -> IntervalMap k a -> Bool
507
isProperSubmapOf = isProperSubmapOfBy (==)
1✔
508

509
-- | Is this a proper submap? (ie. a submap but not equal).
510
-- The expression (@'isProperSubmapOfBy' f m1 m2@) returns 'True' when
511
-- @m1@ and @m2@ are not equal,
512
-- all keys in @m1@ are in @m2@, and when @f@ returns 'True' when
513
-- applied to their respective values.
514
isProperSubmapOfBy :: Ord k => (a -> b -> Bool) -> IntervalMap k a -> IntervalMap k b -> Bool
515
isProperSubmapOfBy f m1 m2 =
1✔
516
  isSubmapOfBy f m1 m2 &&
1✔
517
  keysSet m1 `IntervalSet.isProperSubsetOf` keysSet m2
1✔
518

519
-- ------------------------------------------------------------------------
520

521
splitLookupLE :: Ord k => k -> Map k v -> (Map k v, Maybe v, Map k v)
522
splitLookupLE k m =
1✔
523
  case Map.splitLookup k m of
1✔
524
    (smaller, Just v, larger) -> (smaller, Just v, larger)
1✔
525
    (smaller, Nothing, larger) ->
526
      case Map.maxView smaller of
1✔
527
        Just (v, smaller') -> (smaller', Just v, larger)
1✔
528
        Nothing -> (smaller, Nothing, larger)
1✔
529

530
upTo :: Ord r => Interval r -> Interval r
531
upTo i =
1✔
532
  case Interval.lowerBound' i of
1✔
533
    (NegInf, _) -> Interval.empty
1✔
UNCOV
534
    (PosInf, _) -> Interval.whole
×
535
    (Finite lb, incl) ->
UNCOV
536
      Interval.interval (NegInf, Interval.Open) (Finite lb, notB incl)
×
537

538
downTo :: Ord r => Interval r -> Interval r
539
downTo i =
1✔
540
  case Interval.upperBound' i of
1✔
541
    (PosInf, _) -> Interval.empty
1✔
UNCOV
542
    (NegInf, _) -> Interval.whole
×
543
    (Finite ub, incl) ->
UNCOV
544
      Interval.interval (Finite ub, notB incl) (PosInf, Interval.Open)
×
545

546
notB :: Interval.Boundary -> Interval.Boundary
547
notB = \case
1✔
548
  Interval.Open   -> Interval.Closed
1✔
549
  Interval.Closed -> Interval.Open
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

© 2025 Coveralls, Inc