]> gitweb.factorcode.org Git - factor.git/blob - basis/interval-maps/interval-maps.factor
0b63f2815b94de5a13f0cd0fde187e5bf0f7b96d
[factor.git] / basis / interval-maps / interval-maps.factor
1 ! Copyright (C) 2008 Daniel Ehrenberg.\r
2 ! See http://factorcode.org/license.txt for BSD license.\r
3 USING: accessors arrays assocs binary-search grouping kernel\r
4 locals make math math.order sequences sequences.private sorting ;\r
5 IN: interval-maps\r
6 \r
7 TUPLE: interval-map { array array read-only } ;\r
8 \r
9 <PRIVATE\r
10 \r
11 ALIAS: start first-unsafe\r
12 ALIAS: end second-unsafe\r
13 ALIAS: value third-unsafe\r
14 \r
15 : find-interval ( key interval-map -- interval-node )\r
16     array>> [ start <=> ] with search nip ; inline\r
17 \r
18 : interval-contains? ( key interval-node -- ? )\r
19     first2-unsafe between? ; inline\r
20 \r
21 : all-intervals ( sequence -- intervals )\r
22     [ [ dup number? [ dup 2array ] when ] dip ] { } assoc-map-as ;\r
23 \r
24 : disjoint? ( node1 node2 -- ? )\r
25     [ end ] [ start ] bi* < ;\r
26 \r
27 : ensure-disjoint ( intervals -- intervals )\r
28     dup [ disjoint? ] monotonic?\r
29     [ "Intervals are not disjoint" throw ] unless ;\r
30 \r
31 : >intervals ( specification -- intervals )\r
32     [ suffix ] { } assoc>map concat 3 group ;\r
33 \r
34 ERROR: not-an-interval-map obj ;\r
35 \r
36 : check-interval-map ( map -- map )\r
37     dup interval-map? [ not-an-interval-map ] unless ; inline\r
38 \r
39 PRIVATE>\r
40 \r
41 : interval-at* ( key map -- value ? )\r
42     check-interval-map\r
43     [ drop ] [ find-interval ] 2bi\r
44     [ nip ] [ interval-contains? ] 2bi\r
45     [ value t ] [ drop f f ] if ; inline\r
46 \r
47 : interval-at ( key map -- value ) interval-at* drop ; inline\r
48 \r
49 : interval-key? ( key map -- ? ) interval-at* nip ; inline\r
50 \r
51 : interval-values ( map -- values )\r
52     check-interval-map array>> [ value ] map ;\r
53 \r
54 : <interval-map> ( specification -- map )\r
55     all-intervals [ first-unsafe second-unsafe ] sort-with\r
56     >intervals ensure-disjoint interval-map boa ;\r
57 \r
58 : <interval-set> ( specification -- map )\r
59     dup zip <interval-map> ;\r
60 \r
61 :: coalesce ( alist -- specification )\r
62     ! Only works with integer keys, because they're discrete\r
63     ! Makes 2array keys\r
64     [\r
65         alist sort-keys unclip swap [ first2 dupd ] dip\r
66         [| oldkey oldval key val | ! Underneath is start\r
67             oldkey 1 + key =\r
68             oldval val = and\r
69             [ oldkey 2array oldval 2array , key ] unless\r
70             key val\r
71         ] assoc-each [ 2array ] bi@ ,\r
72     ] { } make ;\r