-
Notifications
You must be signed in to change notification settings - Fork 9
/
Intervals.hs
115 lines (95 loc) · 3.39 KB
/
Intervals.hs
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
115
{-# LANGUAGE LambdaCase, DeriveGeneric #-}
module Intervals where
--import qualified Data.ByteString.Lazy as BS
--import Text.Printf
import Data.List hiding (union, intersect)
import Data.Monoid ((<>))
--import Data.Yaml (ToJSON, FromJSON)
--import GHC.Generics (Generic)
import Data.Function
import Data.Int
import Prelude hiding (subtract)
type Offset = Int64
data Interval = I { from :: Offset, to :: Offset }
-- deriving (Show,Generic)
newtype Intervals = Intervals [Interval]
-- deriving (Show,Generic)
mkInterval :: Offset -> Offset -> Intervals
mkInterval f t | f < t = Intervals [I f t]
| otherwise = Intervals []
fullIntervals :: Offset -> Intervals
fullIntervals len = mkInterval 0 len
nullInterval :: Intervals
nullInterval = Intervals []
size :: Intervals -> Offset
size (Intervals is) = sum [ t - f | I f t <- is ]
isEmpty :: Intervals -> Bool
isEmpty (Intervals is) = null is
subSetOf :: Intervals -> Intervals -> Bool
subSetOf a b = isEmpty (a `subtract` b)
intersects :: Intervals -> Intervals -> Bool
intersects a b = not $ isEmpty (a `intersect` b)
intersect :: Intervals -> Intervals -> Intervals
intersect (Intervals is1) (Intervals is2) = Intervals $ go is1 is2
where
go _ [] = []
go [] _ = []
go (i1:is1) (i2:is2)
-- reorder for symmetry
| to i1 < to i2 = go (i2:is2) (i1:is1)
-- disjoint
| from i1 >= to i2 = go (i1:is1) is2
-- subset
| to i1 == to i2 = I f' (to i2) : go is1 is2
-- overlapping
| otherwise = I f' (to i2) : go (i1 { from = to i2} : is1) is2
where f' = max (from i1) (from i2)
union :: Intervals -> Intervals -> Intervals
union (Intervals is1) (Intervals is2) = Intervals $ go is1 is2
where
go is [] = is
go [] is = is
go (i1:is1) (i2:is2)
-- reorder for symmetry
| to i1 < to i2 = go (i2:is2) (i1:is1)
-- disjoint
| from i1 > to i2 = i2 : go (i1:is1) is2
-- overlapping
| otherwise = go (i1 { from = f'} : is1) is2
where f' = min (from i1) (from i2)
subtract :: Intervals -> Intervals -> Intervals
subtract (Intervals is1) (Intervals is2) = Intervals $ go is1 is2
where
go is [] = is
go [] _ = []
go (i1:is1) (i2:is2)
-- i2 past i1
| to i1 <= from i2 = i1 : go is1 (i2:is2)
-- i1 past i2
| to i2 <= from i1 = go (i1:is1) is2
-- i1 contained in i2
| from i2 <= from i1 , to i1 <= to i2 = go is1 (i2:is2)
-- i2 covers beginning of i1
| from i1 >= from i2 = go (i1 { from = to i2} : is1) is2
-- i2 covers end of i1
| to i1 <= to i2 = i1 { to = from i2} : go is1 (i2:is2)
-- i2 in the middle of i1
| otherwise = I (from i1) (from i2) :
go (I (to i2) (to i1) : is1) is2
-- setZeros :: BS.ByteString -> Intervals -> BS.ByteString
-- setZeros s (Intervals is) = foldl' go s is
-- where
-- go s (I f t) = prefix <> zeroes <> postfix
-- where
-- (tmp, postfix) = BS.splitAt t s
-- (prefix, _discard) = BS.splitAt f tmp
-- zeroes = BS.replicate (t-f) 0
-- ppInterval :: Interval -> String
-- ppInterval (I f t) = printf "0x%04X-0x%04X" f t
--
-- ppIntervals :: Intervals -> String
-- ppIntervals (Intervals xs) = intercalate " " (map ppInterval xs)
--instance FromJSON Interval
--instance ToJSON Interval
--instance FromJSON Intervals
--instance ToJSON Intervals