1 // SemiTwist D Tools: Library
2 // Written in the D programming language.
3 
4 module semitwist.util.ver;
5 
6 import std.compiler;
7 import std.conv;
8 import std.math;
9 import std.stdio;
10 import std..string;
11 
12 import semitwist.util.all;
13 
14 //TODO: Support versions that have different semantics
15 //TODO: Document ordering semantics of this
16 //TODO: This should all work at compile-time
17 struct Ver
18 {
19 	uint[] ver;
20 	
21 	//TODO: Get rid of this "static if" (but not the func) after dropping support for DMD 2.058
22 	static if(vendor != Vendor.digitalMars || version_minor >= 59)
23 	const int opCmp(const(Ver) v)
24 	{
25 		return opCmp(v);
26 	}
27 
28 	const int opCmp(ref const(Ver) v)
29 	{
30 		for(int i=0; i < reduce!"a<b?a:b"([this.ver.length, v.ver.length]); i++)
31 		{
32 			if(this.ver[i] != v.ver[i])
33 				return this.ver[i] - v.ver[i];
34 		}
35 		
36 		if(this.ver.length > v.ver.length)
37 			return 1;
38 		else if(this.ver.length < v.ver.length)
39 			return -1;
40 		
41 		return 0;
42 	}
43 	
44 	//TODO: Get rid of this "static if" (but not the func) after dropping support for DMD 2.058
45 	static if(vendor != Vendor.digitalMars || version_minor >= 59)
46 	const bool opEquals(const(Ver) v)
47 	{
48 		return opEquals(v);
49 	}
50 
51 	const bool opEquals(ref const(Ver) v)
52 	{
53 		return this.opCmp(v) == 0;
54 	}
55 	
56 	static if(useNoThrowSafeToHash)
57 	{
58 		const nothrow @trusted hash_t toHash()
59 		{
60 			string str;
61 			try
62 				str = toString();
63 			catch(Exception e)
64 				{} // Yes, that's right, I actually have to pull a Java
65 				// and squelch exceptions for the time being. *$^@&!#
66 			return typeid(string).getHash(&str);
67 		}
68 	}
69 	else
70 	{
71 		const hash_t toHash()
72 		{
73 			auto str = toString();
74 			return typeid(string).getHash(&str);
75 		}
76 	}
77 
78 	const string toString()
79 	{
80 		return join(to!(string[])(ver), ".");
81 	}
82 }
83 
84 Ver toVer(string str)
85 {
86 	auto strParts = str.ctfe_split(".");
87 	uint[] verParts;
88 	verParts.length = strParts.length;
89 	
90 	foreach(i, strPart; strParts)
91 		verParts[i] = ctfe_to!uint(strPart);
92 		
93 	return Ver(verParts);
94 }
95 
96 mixin(unittestSemiTwistDLib(q{
97 	mixin(deferAssert!(`Ver([5,5,5])  == Ver([5,5,5])`));
98 	mixin(deferAssert!(`Ver([5,5,0])  != Ver([5,5,5])`));
99 	mixin(deferAssert!(`Ver([5,5])    != Ver([5,5,5])`));
100 	mixin(deferAssert!(`Ver([2,10,3]) == Ver([2,10,3])`));
101 
102 	mixin(deferAssert!(`Ver([5,5,5]) > Ver([5,5,1])`));
103 	mixin(deferAssert!(`Ver([5,5,5]) > Ver([5,1,5])`));
104 	mixin(deferAssert!(`Ver([5,5,5]) > Ver([1,5,5])`));
105 
106 	mixin(deferAssert!(`Ver([5,5,0]) < Ver([5,5,5])`));
107 
108 	mixin(deferAssert!(`Ver([5,5,0]) > Ver([5,5])`));
109 	mixin(deferAssert!(`Ver([5,5])   < Ver([5,5,0])`));
110 
111 	mixin(deferAssert!(`Ver([1,10]) > Ver([1,1])`));
112 
113 	mixin(deferEnsure!(`"2.10.3".toVer().ver`, `_ == [cast(uint)2,10,3]`));
114 	mixin(deferEnsure!(`"2.10.3".toVer()`, `_ == Ver([2,10,3])`));
115 	mixin(deferEnsure!(`Ver([2,10,3]).toString()`, `_ == "2.10.3"`));
116 }));