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 	yocto = -24, // y
13 	zepto = -21, // z
14 	atto  = -18, // a
15 	femto = -15, // f
16 	pico  = -12, // p
17 	nano  =  -9, // n
18 	micro =  -6, // m
19 	milli =  -3, // m
20 	centi =  -2, // c
21 	deci  =  -1, // d
22 	none  =   0,
23 	deka  =   1, // D
24 	hecto =   2, // h
25 	kilo  =   3, // k
26 	mega  =   6, // M
27 	giga  =   9, // G
28 	tera  =  12, // T
29 	peta  =  15, // P
30 	exa   =  18, // E
31 	zetta =  21, // Z
32 	yotta =  24, // Y
33 }
34 
35 /** Bytes (Count) Unit. */
36 struct Bytes {
37 	alias T = size_t;
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 		} else {
56 			name = "Bytes"; // Unqual!(typeof(this)).stringof; // Unqual: "const(Bytes)" => "Bytes"
57 			val = _value;
58 		}
59 
60 		import std.conv : to;
61 		if	  (val < 1024^^1) { return to!string(val) ~ " " ~ name; }
62 		else if (val < 1024^^2) { return to!string(cast(real)val / 1024^^1) ~ " kilo" ~ name; }
63 		else if (val < 1024^^3) { return to!string(cast(real)val / 1024^^2) ~ " Mega" ~ name; }
64 		else if (val < 1024^^4) { return to!string(cast(real)val / 1024^^3) ~ " Giga" ~ name; }
65 		else if (val < 1024^^5) { return to!string(cast(real)val / 1024^^4) ~ " Tera" ~ name; }
66 		else if (val < 1024^^6) { return to!string(cast(real)val / 1024^^5) ~ " Peta" ~ name; }
67 		else if (val < 1024^^7) { return to!string(cast(real)val / 1024^^6) ~ " Exa" ~ name; }
68 		else if (val < 1024^^8) { return to!string(cast(real)val / 1024^^7) ~ " Zetta" ~ name; }
69 		else /* if (val < 1024^^9) */ { return to!string(cast(real)val / 1024^^8) ~ " Yotta" ~ name;
70 		/* } else { */
71 		/*	 return to!string(val) ~ " " ~ name; */
72 		}
73 	}
74 
75 	T opUnary(string op, string file = __FILE__, int line = __LINE__)() {
76 		T tmp = void; mixin("tmp = " ~ op ~ " _value;"); return tmp;
77 	}
78 
79 	T opBinary(string op, string file = __FILE__, int line = __LINE__)(T rhs) {
80 		T tmp = void; mixin("tmp = _value " ~ op ~ "rhs;"); return tmp;
81 	}
82 
83 	T opOpAssign(string op, string file = __FILE__, int line = __LINE__)(T rhs) {
84 		mixin("_value = _value " ~ op ~ "rhs;"); return _value;
85 	}
86 
87 	T opAssign(T rhs) {
88 		return _value = rhs;
89 	}
90 
91 	private T _value;
92 }
93 
94 /** $(D Bytes) Instantiator. */
95 auto bytes(size_t value) => Bytes(value);
96 
97 ///
98 pure nothrow @safe @nogc unittest {
99 	immutable a = bytes(1);
100 	immutable b = bytes(1);
101 	immutable c = a + b;
102 	assert(c == 2);
103 	assert(1.bytes == 1);
104 }
105 
106 auto inPercent	   (T)(T a) => to!string(a * 1e2) ~ " \u0025";
107 auto inPerMille	  (T)(T a) => to!string(a * 1e3) ~ " \u2030";
108 auto inPerTenThousand(T)(T a) => to!string(a * 1e4) ~ " \u2031";
109 auto inDegrees	   (T)(T a) => to!string(a	  ) ~ " \u00B0";