File: extentlistSet.ml

package info (click to toggle)
xen-api-libs 0.5.2-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 1,940 kB
  • sloc: ml: 13,925; sh: 2,930; ansic: 1,699; makefile: 1,240; python: 83
file content (106 lines) | stat: -rw-r--r-- 2,813 bytes parent folder | download
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

module type Number = sig
	type t
	val zero: t
	val add : t -> t -> t
	val sub : t -> t -> t
end

module ExtentlistSet (A : Number) =
struct
	type extent = A.t * A.t
	type t = extent list

	let ($+) = A.add
	let ($-) = A.sub

	let empty = []

	let sort list : t =
		List.sort (fun x y -> compare (fst x) (fst y)) list

	let remove_zeroes = List.filter (fun (_, y) -> y <> A.zero)

	let union (list1: t) (list2: t) : t =
		let combined = sort (list1 @ list2) in
		let rec inner l acc =
			match l with
				| (s1,e1)::(s2,e2)::ls ->
					let extent1_end = s1 $+ e1 in
					if extent1_end < s2 then
						inner ((s2,e2)::ls) ((s1,e1)::acc)
					else
						let extent2_end = s2 $+ e2 in
						if extent1_end > extent2_end then
							inner ((s1,e1)::ls) acc
						else
							inner ((s1,s2 $+ e2 $- s1)::ls) acc
				| (s1,e1)::[] -> (s1,e1)::acc
				| [] -> []
		in List.rev (inner combined [])

	let intersection (list1: t) (list2: t) =
		let rec inner l1 l2 acc =
			match (l1,l2) with
				| (s1,e1)::l1s , (s2,e2)::l2s ->
					if s1 > s2 then inner l2 l1 acc else
						if s1 $+ e1 < s2 then inner l1s l2 acc else
							if s1 < s2 then inner ((s2,e1 $+ s1 $- s2)::l1s) l2 acc else
								(* s1=s2 *)
								if e1 < e2 then
									inner l1s ((s2 $+ e1,e2 $- e1)::l2s) ((s1,e1)::acc)
								else if e1 > e2 then
									inner ((s1 $+ e2,e1 $- e2)::l1s) l2s ((s2,e2)::acc)
								else (* e1=e2 *)
									inner l1s l2s ((s1,e1)::acc)
				| _ -> List.rev acc
		in
		remove_zeroes(inner list1 list2 [])

	let difference (list1: t) (list2: t) : t =
		let rec inner l1 l2 acc =
			match (l1,l2) with
				| (s1,e1)::l1s , (s2,e2)::l2s ->
					if s1<s2 then begin
						if s1 $+ e1 > s2 then
							inner ((s2,s1 $+ e1 $- s2)::l1s) l2 ((s1,s2 $- s1)::acc)
						else
							inner l1s l2 ((s1,e1)::acc)
					end else if s1>s2 then begin
						if s2 $+ e2 > s1 then
							inner l1 ((s1,s2 $+ e2 $- s1)::l2s) acc
						else
							inner l1 l2s acc
					end else begin
						(* s1=s2 *)
						if e1 > e2 then
							inner ((s1 $+ e2,e1 $- e2)::l1s) l2s acc
						else if e1 < e2 then
							inner l1s ((s2 $+ e1,e2 $- e1)::l2s) acc
						else
							inner l1s l2s acc
					end
				| l1s, [] -> (List.rev acc) @ l1s
				| [], _ -> List.rev acc
		in
		remove_zeroes(inner list1 list2 [])

	let of_list (list: extent list) : t =
		let l = sort list in
		let rec inner ls acc =
			match ls with
				| (s1,e1)::(s2,e2)::rest ->
					(* extents should be non-overlapping *)
					if s1 $+ e1 > s2 then failwith "Bad list"
					(* adjacent extents should be coalesced *)
					else if s1 $+ e1=s2 then inner ((s1,e1 $+ e2)::rest) acc
					else inner ((s2,e2)::rest) ((s1,e1)::acc)
				| (s1,e1)::[] -> List.rev ((s1,e1)::acc)
				| [] -> List.rev acc
		in
		inner l []

	let fold_left = List.fold_left

	let to_list x = x
end