1 /** Computer Science Units.
2 	Copyright: Per Nordlöw 2022-.
3 	License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 	Authors: $(WEB Per Nordlöw)
5  */
6 module nxt.csunits;
7 
8 /** Prefix Multipliers.
9 	See_Also: http://searchstorage.techtarget.com/definition/Kilo-mega-giga-tera-peta-and-all-that
10 */
11 enum PrefixMultipliers
12 {
13 	yocto = -24, // y
14 	zepto = -21, // z
15 	atto  = -18, // a
16 	femto = -15, // f
17 	pico  = -12, // p
18 	nano  =  -9, // n
19 	micro =  -6, // m
20 	milli =  -3, // m
21 	centi =  -2, // c
22 	deci  =  -1, // d
23 	none  =   0,
24 	deka  =   1, // D
25 	hecto =   2, // h
26 	kilo  =   3, // k
27 	mega  =   6, // M
28 	giga  =   9, // G
29 	tera  =  12, // T
30 	peta  =  15, // P
31 	exa   =  18, // E
32 	zetta =  21, // Z
33 	yotta =  24, // Y
34 }
35 
36 /** Bytes (Count) Unit. */
37 struct Bytes(T: ulong) {
38 	alias _value this;
39 
40 	inout(T) value() @property inout @safe pure nothrow => _value;
41 
42 	/**
43 	   See_Also: http://searchstorage.techtarget.com/definition/Kilo-mega-giga-tera-peta-and-all-that
44 	   See_Also: https://en.wikipedia.org/wiki/Exabyte
45 	 */
46 	string toString(bool inBits = false) const @property @trusted /* pure nothrow */
47 	{
48 		// import core.internal.traits : Unqual;
49 
50 		string name = void;
51 		T val = void;
52 		if (inBits) {
53 			name = "Bits"; // Unqual!(typeof(this)).stringof; // Unqual: "const(Bytes)" => "Bytes"
54 			val = 8*_value;
55 		}
56 		else
57 		{
58 			name = "Bytes"; // Unqual!(typeof(this)).stringof; // Unqual: "const(Bytes)" => "Bytes"
59 			val = _value;
60 		}
61 
62 		import std.conv : to;
63 		if	  (val < 1024^^1) { return to!string(val) ~ " " ~ name; }
64 		else if (val < 1024^^2) { return to!string(cast(real)val / 1024^^1) ~ " kilo" ~ name; }
65 		else if (val < 1024^^3) { return to!string(cast(real)val / 1024^^2) ~ " Mega" ~ name; }
66 		else if (val < 1024^^4) { return to!string(cast(real)val / 1024^^3) ~ " Giga" ~ name; }
67 		else if (val < 1024^^5) { return to!string(cast(real)val / 1024^^4) ~ " Tera" ~ name; }
68 		else if (val < 1024^^6) { return to!string(cast(real)val / 1024^^5) ~ " Peta" ~ name; }
69 		else if (val < 1024^^7) { return to!string(cast(real)val / 1024^^6) ~ " Exa" ~ name; }
70 		else if (val < 1024^^8) { return to!string(cast(real)val / 1024^^7) ~ " Zetta" ~ name; }
71 		else /* if (val < 1024^^9) */ { return to!string(cast(real)val / 1024^^8) ~ " Yotta" ~ name;
72 		/* } else { */
73 		/*	 return to!string(val) ~ " " ~ name; */
74 		}
75 	}
76 
77 	T opUnary(string op, string file = __FILE__, int line = __LINE__)() {
78 		T tmp = void; mixin("tmp = " ~ op ~ " _value;"); return tmp;
79 	}
80 
81 	T opBinary(string op, string file = __FILE__, int line = __LINE__)(T rhs) {
82 		T tmp = void; mixin("tmp = _value " ~ op ~ "rhs;"); return tmp;
83 	}
84 
85 	T opOpAssign(string op, string file = __FILE__, int line = __LINE__)(T rhs) {
86 		mixin("_value = _value " ~ op ~ "rhs;"); return _value;
87 	}
88 
89 	T opAssign(T rhs, string file = __FILE__, int line = __LINE__) {
90 		return _value = rhs;
91 	}
92 
93 /* private: */
94 	T _value;
95 }
96 
97 /** $(D Bytes) Instantiator. */
98 auto bytes(T)(T value) => Bytes!T(value);
99 
100 pure nothrow @safe @nogc unittest {
101 	immutable a = bytes(1);
102 	immutable b = bytes(1);
103 	immutable c = a + b;
104 	assert(c == 2);
105 	assert(1.bytes == 1);
106 }
107 
108 auto inPercent	   (T)(T a) => to!string(a * 1e2) ~ " \u0025";
109 auto inPerMille	  (T)(T a) => to!string(a * 1e3) ~ " \u2030";
110 auto inPerTenThousand(T)(T a) => to!string(a * 1e4) ~ " \u2031";
111 auto inDegrees	   (T)(T a) => to!string(a	  ) ~ " \u00B0";