@@ -3,33 +3,71 @@ namespace Spectre.Console;
3
3
internal struct FileSize
4
4
{
5
5
public double Bytes { get ; }
6
- public FileSizeUnit Unit { get ; }
6
+ public double Bits => Bytes * 8 ;
7
+
8
+ public FileSizePrefix Prefix { get ; } = FileSizePrefix . None ;
9
+
10
+ private readonly FileSizeBase _prefixBase = FileSizeBase . Binary ;
11
+
12
+ /// <summary>
13
+ /// If enabled, will display the output in bits, rather than bytes.
14
+ /// </summary>
15
+ private readonly bool _showBits = false ;
16
+
7
17
public string Suffix => GetSuffix ( ) ;
8
18
9
19
public FileSize ( double bytes )
10
20
{
11
21
Bytes = bytes ;
12
- Unit = Detect ( bytes ) ;
22
+ Prefix = DetectPrefix ( bytes ) ;
23
+ }
24
+
25
+ public FileSize ( double bytes , FileSizeBase @base )
26
+ {
27
+ Bytes = bytes ;
28
+ _prefixBase = @base ;
29
+ Prefix = DetectPrefix ( bytes ) ;
30
+ }
31
+
32
+ public FileSize ( double bytes , FileSizeBase @base , bool showBits )
33
+ {
34
+ Bytes = bytes ;
35
+ _showBits = showBits ;
36
+
37
+ _prefixBase = @base ;
38
+ Prefix = DetectPrefix ( bytes ) ;
39
+ }
40
+
41
+ public FileSize ( double bytes , FileSizePrefix prefix )
42
+ {
43
+ Bytes = bytes ;
44
+ Prefix = prefix ;
13
45
}
14
46
15
- public FileSize ( double bytes , FileSizeUnit unit )
47
+ public FileSize ( double bytes , FileSizePrefix prefix , FileSizeBase @base , bool showBits )
16
48
{
17
49
Bytes = bytes ;
18
- Unit = unit ;
50
+ _showBits = showBits ;
51
+
52
+ _prefixBase = @base ;
53
+ Prefix = prefix ;
19
54
}
20
55
21
56
public string Format ( CultureInfo ? culture = null )
22
57
{
23
- var @base = GetBase ( Unit ) ;
24
- if ( @base == 0 )
58
+ var unitBase = Math . Pow ( ( int ) _prefixBase , ( int ) Prefix ) ;
59
+
60
+ if ( _showBits )
25
61
{
26
- @base = 1 ;
62
+ var bits = Bits / unitBase ;
63
+ return Prefix == FileSizePrefix . None ?
64
+ ( ( int ) bits ) . ToString ( culture ?? CultureInfo . InvariantCulture )
65
+ : bits . ToString ( "F1" , culture ?? CultureInfo . InvariantCulture ) ;
27
66
}
28
67
29
- var bytes = Bytes / @base ;
30
-
31
- return Unit == FileSizeUnit . Byte
32
- ? ( ( int ) bytes ) . ToString ( culture ?? CultureInfo . InvariantCulture )
68
+ var bytes = Bytes / unitBase ;
69
+ return Prefix == FileSizePrefix . None ?
70
+ ( ( int ) bytes ) . ToString ( culture ?? CultureInfo . InvariantCulture )
33
71
: bytes . ToString ( "F1" , culture ?? CultureInfo . InvariantCulture ) ;
34
72
}
35
73
@@ -50,36 +88,67 @@ public string ToString(bool suffix = true, CultureInfo? culture = null)
50
88
51
89
private string GetSuffix ( )
52
90
{
53
- return ( Bytes , Unit ) switch
91
+ return ( Bytes , Unit : Prefix , PrefixBase : _prefixBase , ShowBits : _showBits ) switch
54
92
{
55
- ( _, FileSizeUnit . KiloByte ) => "KB" ,
56
- ( _, FileSizeUnit . MegaByte ) => "MB" ,
57
- ( _, FileSizeUnit . GigaByte ) => "GB" ,
58
- ( _, FileSizeUnit . TeraByte ) => "TB" ,
59
- ( _, FileSizeUnit . PetaByte ) => "PB" ,
60
- ( _, FileSizeUnit . ExaByte ) => "EB" ,
61
- ( _, FileSizeUnit . ZettaByte ) => "ZB" ,
62
- ( _, FileSizeUnit . YottaByte ) => "YB" ,
63
- ( 1 , _ ) => "byte" ,
64
- ( _, _) => "bytes" ,
93
+ ( _, FileSizePrefix . Kilo , FileSizeBase . Binary , false ) => "KiB" ,
94
+ ( _, FileSizePrefix . Mega , FileSizeBase . Binary , false ) => "MiB" ,
95
+ ( _, FileSizePrefix . Giga , FileSizeBase . Binary , false ) => "GiB" ,
96
+ ( _, FileSizePrefix . Tera , FileSizeBase . Binary , false ) => "TiB" ,
97
+ ( _, FileSizePrefix . Peta , FileSizeBase . Binary , false ) => "PiB" ,
98
+ ( _, FileSizePrefix . Exa , FileSizeBase . Binary , false ) => "EiB" ,
99
+ ( _, FileSizePrefix . Zetta , FileSizeBase . Binary , false ) => "ZiB" ,
100
+ ( _, FileSizePrefix . Yotta , FileSizeBase . Binary , false ) => "YiB" ,
101
+
102
+ ( _, FileSizePrefix . Kilo , FileSizeBase . Binary , true ) => "Kibit" ,
103
+ ( _, FileSizePrefix . Mega , FileSizeBase . Binary , true ) => "Mibit" ,
104
+ ( _, FileSizePrefix . Giga , FileSizeBase . Binary , true ) => "Gibit" ,
105
+ ( _, FileSizePrefix . Tera , FileSizeBase . Binary , true ) => "Tibit" ,
106
+ ( _, FileSizePrefix . Peta , FileSizeBase . Binary , true ) => "Pibit" ,
107
+ ( _, FileSizePrefix . Exa , FileSizeBase . Binary , true ) => "Eibit" ,
108
+ ( _, FileSizePrefix . Zetta , FileSizeBase . Binary , true ) => "Zibit" ,
109
+ ( _, FileSizePrefix . Yotta , FileSizeBase . Binary , true ) => "Yibit" ,
110
+
111
+ ( _, FileSizePrefix . Kilo , FileSizeBase . Decimal , false ) => "KB" ,
112
+ ( _, FileSizePrefix . Mega , FileSizeBase . Decimal , false ) => "MB" ,
113
+ ( _, FileSizePrefix . Giga , FileSizeBase . Decimal , false ) => "GB" ,
114
+ ( _, FileSizePrefix . Tera , FileSizeBase . Decimal , false ) => "TB" ,
115
+ ( _, FileSizePrefix . Peta , FileSizeBase . Decimal , false ) => "PB" ,
116
+ ( _, FileSizePrefix . Exa , FileSizeBase . Decimal , false ) => "EB" ,
117
+ ( _, FileSizePrefix . Zetta , FileSizeBase . Decimal , false ) => "ZB" ,
118
+ ( _, FileSizePrefix . Yotta , FileSizeBase . Decimal , false ) => "YB" ,
119
+
120
+ ( _, FileSizePrefix . Kilo , FileSizeBase . Decimal , true ) => "Kbit" ,
121
+ ( _, FileSizePrefix . Mega , FileSizeBase . Decimal , true ) => "Mbit" ,
122
+ ( _, FileSizePrefix . Giga , FileSizeBase . Decimal , true ) => "Gbit" ,
123
+ ( _, FileSizePrefix . Tera , FileSizeBase . Decimal , true ) => "Tbit" ,
124
+ ( _, FileSizePrefix . Peta , FileSizeBase . Decimal , true ) => "Pbit" ,
125
+ ( _, FileSizePrefix . Exa , FileSizeBase . Decimal , true ) => "Ebit" ,
126
+ ( _, FileSizePrefix . Zetta , FileSizeBase . Decimal , true ) => "Zbit" ,
127
+ ( _, FileSizePrefix . Yotta , FileSizeBase . Decimal , true ) => "Ybit" ,
128
+
129
+ ( 1 , _ , _ , true ) => "bit" ,
130
+ ( _, _, _, true ) => "bits" ,
131
+ ( 1 , _ , _ , false ) => "byte" ,
132
+ ( _, _, _, false ) => "bytes" ,
65
133
} ;
66
134
}
67
135
68
- private static FileSizeUnit Detect ( double bytes )
136
+ private FileSizePrefix DetectPrefix ( double bytes )
69
137
{
70
- foreach ( var unit in ( FileSizeUnit [ ] ) Enum . GetValues ( typeof ( FileSizeUnit ) ) )
138
+ if ( _showBits )
139
+ {
140
+ bytes *= 8 ;
141
+ }
142
+
143
+ foreach ( var prefix in ( FileSizePrefix [ ] ) Enum . GetValues ( typeof ( FileSizePrefix ) ) )
71
144
{
72
- if ( bytes < ( GetBase ( unit ) * 1024 ) )
145
+ // Trying to find the largest unit, that the number of bytes can fit under. Ex. 40kb < 1mb
146
+ if ( bytes < Math . Pow ( ( int ) _prefixBase , ( int ) prefix + 1 ) )
73
147
{
74
- return unit ;
148
+ return prefix ;
75
149
}
76
150
}
77
151
78
- return FileSizeUnit . Byte ;
79
- }
80
-
81
- private static double GetBase ( FileSizeUnit unit )
82
- {
83
- return Math . Pow ( 1024 , ( int ) unit ) ;
152
+ return FileSizePrefix . None ;
84
153
}
85
154
}
0 commit comments