1 module parsing.data_sizes;
2 
3 import std.algorithm;
4 import std..string;
5 import std.conv;
6 import std.uni;
7 
8 class DataSizeParsing
9 {
10 	private ulong[string] unitsTableBin;
11 	private ulong[string] unitsTableDec;
12 	this()
13 	{
14 		// Init lookup tables for division and multiplication sizes
15 		unitsTableBin = [
16 			"b": 1,
17 			"kib": 1024,
18 			"mib": 1_048_576,
19 			"gib": 1_073_741_824,
20 			"tib": 1_099_511_627_776,
21 			"pib": 1_125_899_906_842_620,
22 		];
23 
24 		unitsTableDec = [
25 			"b": 1,
26 			"kb": 1000,
27 			"mb": 1_000_000,
28 			"gb": 1_000_000_000,
29 			"tb": 1_000_000_000_000,
30 			"pb": 1_000_000_000_000_000
31 		];
32 	}
33 
34 	/// Parse a string i.e 10MiB to a value in bytes, supported suffixes are B, KiB..PiB and KB..PB
35 	/// Params:
36 	///   input = string in the form ie `10MiB`
37 	/// Returns: ulong with the size in bytes based on the suffix
38 	ulong fromHumanToBytes(string input)
39 	{
40 		string rawNum;
41 		string suffix;
42 
43 		foreach (i, c; input)
44 		{
45 			// if we have anything in the suffix yet ignore the rest of the string
46 			if (c.isNumber && suffix.length == 0)
47 				rawNum ~= c;
48 			else
49 				suffix ~= c;
50 		}
51 		suffix = suffix.toLower;
52 		// Don't bother with lookup if the suffix is too large to exist in the table
53 		if (suffix.length <= 3 && suffix in unitsTableBin)
54 			return parse!ulong(rawNum) * unitsTableBin[suffix];
55 		else if(suffix.length <= 2 && suffix in unitsTableDec)
56 			return parse!ulong(rawNum) * unitsTableDec[suffix];
57 		else
58 			throw new Exception(format("Invalid suffix %s", suffix));
59 	}
60 
61 	unittest
62 	{
63 		DataSizeParsing dsp = new DataSizeParsing;
64 
65 		assert(dsp.fromHumanToBytes("100MiB") == 104_857_600);
66 	}
67 }