• 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

82.93
/src/Data/IntervalMap/Base.hs
1
{-# OPTIONS_GHC -Wall #-}
2
{-# LANGUAGE CPP, LambdaCase, ScopedTypeVariables, TypeFamilies, DeriveDataTypeable, 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
-- Portability :  non-portable (CPP, ScopedTypeVariables, TypeFamilies, DeriveDataTypeable, MultiWayIf, GeneralizedNewtypeDeriving)
14
--
15
-- Interval datatype and interval arithmetic.
16
--
17
-----------------------------------------------------------------------------
18
module Data.IntervalMap.Base
19
  (
20
  -- * IntervalMap type
21
    IntervalMap (..)
22
  , module Data.ExtendedReal
23

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

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

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

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

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

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

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

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

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

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

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

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

91
import Prelude hiding (null, lookup, map, filter, span, and)
92
import Control.DeepSeq
93
import Data.Data
94
import Data.ExtendedReal
95
import Data.Hashable
96
import Data.Foldable hiding (null, toList)
97
import Data.Map (Map)
98
import qualified Data.Map as Map
99
import Data.Maybe
100
import qualified Data.Semigroup as Semigroup
101
import Data.Interval (Interval)
102
import qualified Data.Interval as Interval
103
import Data.IntervalSet (IntervalSet)
104
import qualified Data.IntervalSet as IntervalSet
105
#if __GLASGOW_HASKELL__ < 804
106
import Data.Monoid (Monoid(..))
107
#endif
108
import qualified GHC.Exts as GHCExts
109

110
-- ------------------------------------------------------------------------
111
-- The IntervalMap type
112

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

127
type role IntervalMap nominal representational
128

129
instance (Ord k, Show k, Show a) => Show (IntervalMap k a) where
130
  showsPrec p (IntervalMap m) = showParen (p > appPrec) $
1✔
131
    showString "fromList " .
1✔
132
    showsPrec (appPrec+1) (Map.elems m)
×
133

134
instance (Ord k, Read k, Read a) => Read (IntervalMap k a) where
135
  readsPrec p =
1✔
136
    (readParen (p > appPrec) $ \s0 -> do
1✔
137
      ("fromList",s1) <- lex s0
1✔
138
      (xs,s2) <- readsPrec (appPrec+1) s1
×
139
      return (fromList xs, s2))
1✔
140

141
appPrec :: Int
142
appPrec = 10
1✔
143

144
-- This instance preserves data abstraction at the cost of inefficiency.
145
-- We provide limited reflection services for the sake of data abstraction.
146

147
instance (Data k, Data a, Ord k) => Data (IntervalMap k a) where
148
  gfoldl k z x   = z fromList `k` toList x
1✔
149
  toConstr _     = fromListConstr
×
150
  gunfold k z c  = case constrIndex c of
×
151
    1 -> k (z fromList)
×
152
    _ -> error "gunfold"
×
153
  dataTypeOf _   = mapDataType
×
154
  dataCast1 f    = gcast1 f
×
155

156
fromListConstr :: Constr
157
fromListConstr = mkConstr mapDataType "fromList" [] Prefix
×
158

159
mapDataType :: DataType
160
mapDataType = mkDataType "Data.IntervalMap.Base.IntervalMap" [fromListConstr]
×
161

162
instance (NFData k, NFData a) => NFData (IntervalMap k a) where
163
  rnf (IntervalMap m) = rnf m
1✔
164

165
instance (Hashable k, Hashable a) => Hashable (IntervalMap k a) where
166
  hashWithSalt s m = hashWithSalt s (toList m)
1✔
167

168
instance Ord k => Monoid (IntervalMap k a) where
169
  mempty = empty
×
170
  mappend = (Semigroup.<>)
×
171
  mconcat = unions
×
172

173
instance Ord k => Semigroup.Semigroup (IntervalMap k a) where
174
  (<>)   = union
1✔
175
  stimes = Semigroup.stimesIdempotentMonoid
×
176

177
instance Ord k => GHCExts.IsList (IntervalMap k a) where
178
  type Item (IntervalMap k a) = (Interval k, a)
179
  fromList = fromList
×
180
  toList = toList
×
181

182
-- ------------------------------------------------------------------------
183

184
newtype LB r = LB (Extended r, Interval.Boundary)
185
  deriving (Eq, NFData, Typeable)
×
186

187
instance Ord r => Ord (LB r) where
188
  compare (LB (lb1, lb1in)) (LB (lb2, lb2in)) =
1✔
189
    -- inclusive lower endpoint shuold be considered smaller
190
    (lb1 `compare` lb2) `mappend` (lb2in `compare` lb1in)
1✔
191

192
-- ------------------------------------------------------------------------
193
-- Operators
194

195
infixl 9 !,\\ --
196

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

204
-- | Same as 'difference'.
205
(\\) :: Ord k => IntervalMap k a -> IntervalMap k b -> IntervalMap k a
206
m1 \\ m2 = difference m1 m2
1✔
207

208
-- ------------------------------------------------------------------------
209
-- Query
210

211
-- | Is the map empty?
212
null :: Ord k => IntervalMap k a -> Bool
213
null (IntervalMap m) = Map.null m
1✔
214

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

222
-- | Is the key not a member of the map? See also 'member'.
223
notMember :: Ord k => k -> IntervalMap k a -> Bool
224
notMember k m = not $ member k m
1✔
225

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

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

245
lookupInterval :: Ord k => Interval k -> IntervalMap k a -> Maybe a
246
lookupInterval i (IntervalMap m) =
1✔
247
  case Map.lookupLE (LB (Interval.lowerBound' i)) m of
1✔
248
    Just (_, (j, a)) | i `Interval.isSubsetOf` j -> Just a
1✔
249
    _ -> Nothing
1✔
250

251
-- | convex hull of key intervals.
252
span :: Ord k => IntervalMap k a -> Interval k
253
span = IntervalSet.span . keysSet
1✔
254

255
-- ------------------------------------------------------------------------
256
-- Construction
257

258
-- | The empty map.
259
empty :: Ord k => IntervalMap k a
260
empty = IntervalMap Map.empty
1✔
261

262
-- | The map that maps whole range of k to a.
263
whole :: Ord k => a -> IntervalMap k a
264
whole a = IntervalMap $ Map.singleton (LB (Interval.lowerBound' i)) (i, a)
1✔
265
  where
266
    i = Interval.whole
1✔
267

268
-- | A map with a single interval.
269
singleton :: Ord k => Interval k -> a -> IntervalMap k a
270
singleton i a
1✔
271
  | Interval.null i = empty
1✔
272
  | otherwise = IntervalMap $ Map.singleton (LB (Interval.lowerBound' i)) (i, a)
1✔
273

274
-- ------------------------------------------------------------------------
275
-- Insertion
276

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

287

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

299
-- ------------------------------------------------------------------------
300
-- Delete/Update
301

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

311
-- | Update a value at a specific interval with the result of the provided function.
312
-- When the interval does not overlatp with the map, the original map is returned.
313
adjust :: Ord k => (a -> a) -> Interval k -> IntervalMap k a -> IntervalMap k a
314
adjust f = update (Just . f)
1✔
315

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

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

341
-- ------------------------------------------------------------------------
342
-- Combine
343

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

350
-- | Union with a combining function.
351
unionWith :: Ord k => (a -> a -> a) -> IntervalMap k a -> IntervalMap k a -> IntervalMap k a
352
unionWith f m1 m2 =
1✔
353
  foldl' (\m (i,a) -> insertWith f i a m) m2 (toList m1)
1✔
354

355
-- | The union of a list of maps:
356
--   (@'unions' == 'Prelude.foldl' 'union' 'empty'@).
357
unions :: Ord k => [IntervalMap k a] -> IntervalMap k a
358
unions = foldl' union empty
1✔
359

360
-- | The union of a list of maps, with a combining operation:
361
--   (@'unionsWith' f == 'Prelude.foldl' ('unionWith' f) 'empty'@).
362
unionsWith :: Ord k => (a -> a -> a) -> [IntervalMap k a] -> IntervalMap k a
363
unionsWith f = foldl' (unionWith f) empty
×
364

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

369
-- | Intersection of two maps.
370
-- Return data in the first map for the keys existing in both maps.
371
intersection :: Ord k => IntervalMap k a -> IntervalMap k a -> IntervalMap k a
372
intersection = intersectionWith const
1✔
373

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

389
-- ------------------------------------------------------------------------
390
-- Traversal
391

392
instance Ord k => Functor (IntervalMap k) where
393
  fmap = map
1✔
394

395
instance Ord k => Foldable (IntervalMap k) where
396
  foldMap f (IntervalMap m) = foldMap (\(_,a) -> f a) m
1✔
397

398
instance Ord k => Traversable (IntervalMap k) where
399
  traverse f (IntervalMap m) = IntervalMap <$> traverse (\(i,a) -> (\b -> (i,b)) <$> f a) m
1✔
400

401
-- | Map a function over all values in the map.
402
map :: (a -> b) -> IntervalMap k a -> IntervalMap k b
403
map f (IntervalMap m) = IntervalMap $ Map.map (\(i, a) -> (i, f a)) m
1✔
404

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

414
-- ------------------------------------------------------------------------
415

416
-- | Return all elements of the map in the ascending order of their keys.
417
elems :: IntervalMap k a -> [a]
418
elems (IntervalMap m) = [a | (_,a) <- Map.elems m]
×
419

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

424
-- | An alias for 'toAscList'. Return all key\/value pairs in the map
425
-- in ascending key order.
426
assocs :: IntervalMap k a -> [(Interval k, a)]
427
assocs = toAscList
×
428

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

433
-- | Convert the map to a list of key\/value pairs.
434
toList :: IntervalMap k a -> [(Interval k, a)]
435
toList = toAscList
1✔
436

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

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

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

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

455
-- ------------------------------------------------------------------------
456
-- Filter
457

458
-- | Filter all values that satisfy some predicate.
459
filter :: Ord k => (a -> Bool) -> IntervalMap k a -> IntervalMap k a
460
filter p (IntervalMap m) = IntervalMap $ Map.filter (\(_,a) -> p a) m
1✔
461

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

492
-- ------------------------------------------------------------------------
493
-- Submap
494

495
-- | This function is defined as (@'isSubmapOf' = 'isSubmapOfBy' (==)@).
496
isSubmapOf :: (Ord k, Eq a) => IntervalMap k a -> IntervalMap k a -> Bool
497
isSubmapOf = isSubmapOfBy (==)
1✔
498

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

509
-- |  Is this a proper submap? (ie. a submap but not equal).
510
-- Defined as (@'isProperSubmapOf' = 'isProperSubmapOfBy' (==)@).
511
isProperSubmapOf :: (Ord k, Eq a) => IntervalMap k a -> IntervalMap k a -> Bool
512
isProperSubmapOf = isProperSubmapOfBy (==)
1✔
513

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

524
-- ------------------------------------------------------------------------
525

526
splitLookupLE :: Ord k => k -> Map k v -> (Map k v, Maybe v, Map k v)
527
splitLookupLE k m =
1✔
528
  case Map.splitLookup k m of
1✔
529
    (smaller, Just v, larger) -> (smaller, Just v, larger)
1✔
530
    (smaller, Nothing, larger) ->
531
      case Map.maxView smaller of
1✔
532
        Just (v, smaller') -> (smaller', Just v, larger)
1✔
533
        Nothing -> (smaller, Nothing, larger)
1✔
534

535
upTo :: Ord r => Interval r -> Interval r
536
upTo i =
1✔
537
  case Interval.lowerBound' i of
1✔
538
    (NegInf, _) -> Interval.empty
1✔
539
    (PosInf, _) -> Interval.whole
×
540
    (Finite lb, incl) ->
541
      Interval.interval (NegInf, Interval.Open) (Finite lb, notB incl)
×
542

543
downTo :: Ord r => Interval r -> Interval r
544
downTo i =
1✔
545
  case Interval.upperBound' i of
1✔
546
    (PosInf, _) -> Interval.empty
1✔
547
    (NegInf, _) -> Interval.whole
×
548
    (Finite ub, incl) ->
549
      Interval.interval (Finite ub, notB incl) (PosInf, Interval.Open)
×
550

551
notB :: Interval.Boundary -> Interval.Boundary
552
notB = \case
1✔
553
  Interval.Open   -> Interval.Closed
1✔
554
  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