1 module dud.semver.versionunion;
2 
3 import std.algorithm.sorting : sort;
4 import std.array : empty, front, popFront;
5 import std.format : format, formattedWrite;
6 import dud.semver.versionrange;
7 import dud.semver.semver;
8 
9 @safe pure:
10 
11 struct VersionUnion {
12 @safe pure:
13 	VersionRange[] ranges;
14 
15 	this(const(VersionRange)[] rng) {
16 		foreach(it; rng) {
17 			this.insert(it);
18 		}
19 	}
20 
21 	void insert(const(VersionRange) nvu) {
22 		this.ranges = merge(this.ranges, nvu);
23 	}
24 
25 	VersionUnion dup() const {
26 		import std.array : array;
27 		import std.algorithm.iteration : map;
28 		VersionUnion ret;
29 		ret.ranges = this.ranges.map!(it => it.dup).array;
30 		return ret;
31 	}
32 }
33 
34 VersionRange merge(const(VersionRange) a, const(VersionRange) b) {
35 	const SemVer low = a.low < b.low ? a.low : b.low;
36 	const Inclusive lowInc = low == a.low ? a.inclusiveLow : b.inclusiveLow;
37 
38 	const SemVer high = a.high > b.high ? a.high : b.high;
39 	const Inclusive highInc = high == a.high ? a.inclusiveHigh : b.inclusiveHigh;
40 
41 	const bool notIntersect =
42 		(a.high == b.low
43 			&& (a.inclusiveHigh == false || b.inclusiveLow == false))
44 		|| (a.low == b.high
45 			&& (a.inclusiveLow == false || b.inclusiveHigh == false))
46 		|| (a.high < b.low)
47 		|| (a.low > b.high);
48 
49 	return notIntersect
50 		? VersionRange.init
51 		: VersionRange(low, lowInc, high, highInc);
52 }
53 
54 package VersionRange[] merge(const(VersionRange)[] old,
55 		const(VersionRange) nvu)
56 {
57 	VersionRange[] ret;
58 	if(old.empty) {
59 		return [ nvu.dup() ];
60 	}
61 
62 	ret ~= nvu.dup;
63 
64 	foreach(it; old) {
65 		VersionRange top = ret.front();
66 		ret.popFront();
67 
68 		VersionRange m = merge(top, it);
69 		if(m == VersionRange.init) {
70 			ret ~= top;
71 			ret ~= it.dup();
72 		} else {
73 			ret ~= m;
74 		}
75 	}
76 
77 	ret.sort();
78 
79 	return ret;
80 }