Codebase list golang-github-vbauerster-mpb / ee9d54f
New types CounterKiB and CounterKB Vladimir Bauer 8 years ago
6 changed file(s) with 297 addition(s) and 149 deletion(s). Raw diff Collapse all Expand all
0 package decor
1
2 import (
3 "fmt"
4 "strconv"
5 "strings"
6 )
7
8 const (
9 _ = iota
10 KiB = 1 << (iota * 10)
11 MiB
12 GiB
13 TiB
14 )
15
16 const (
17 KB = 1000
18 MB = KB * 1000
19 GB = MB * 1000
20 TB = GB * 1000
21 )
22
23 const (
24 _ = iota
25 // Unit_KiB Kibibyte = 1024 b
26 Unit_KiB
27 // Unit_kB Kilobyte = 1000 b
28 Unit_kB
29 )
30
31 type Unit uint
32
33 type CounterKiB int64
34
35 func (c CounterKiB) Format(f fmt.State, r rune) {
36 prec, ok := f.Precision()
37
38 if r == 'd' || !ok {
39 prec = 0
40 }
41 if r == 'f' && !ok {
42 prec = 6
43 }
44 // retain old beahavior if s verb used
45 if r == 's' {
46 prec = 1
47 }
48
49 var res, unit string
50 switch {
51 case c >= TiB:
52 unit = "TiB"
53 res = strconv.FormatFloat(float64(c)/TiB, 'f', prec, 64)
54 case c >= GiB:
55 unit = "GiB"
56 res = strconv.FormatFloat(float64(c)/GiB, 'f', prec, 64)
57 case c >= MiB:
58 unit = "MiB"
59 res = strconv.FormatFloat(float64(c)/MiB, 'f', prec, 64)
60 case c >= KiB:
61 unit = "KiB"
62 res = strconv.FormatFloat(float64(c)/KiB, 'f', prec, 64)
63 default:
64 unit = "b"
65 res = strconv.FormatInt(int64(c), 10)
66 }
67
68 if f.Flag(int(' ')) {
69 res += " "
70 }
71 res += unit
72
73 if w, ok := f.Width(); ok {
74 if len(res) < w {
75 pad := strings.Repeat(" ", w-len(res))
76 if f.Flag(int('-')) {
77 res += pad
78 } else {
79 res = pad + res
80 }
81 }
82 }
83
84 f.Write([]byte(res))
85 }
86
87 type CounterKB int64
88
89 func (c CounterKB) Format(f fmt.State, r rune) {
90 prec, ok := f.Precision()
91
92 if r == 'd' || !ok {
93 prec = 0
94 }
95 if r == 'f' && !ok {
96 prec = 6
97 }
98 // retain old beahavior if s verb used
99 if r == 's' {
100 prec = 1
101 }
102
103 var res, unit string
104 switch {
105 case c >= TB:
106 unit = "TB"
107 res = strconv.FormatFloat(float64(c)/TB, 'f', prec, 64)
108 case c >= GB:
109 unit = "GB"
110 res = strconv.FormatFloat(float64(c)/GB, 'f', prec, 64)
111 case c >= MB:
112 unit = "MB"
113 res = strconv.FormatFloat(float64(c)/MB, 'f', prec, 64)
114 case c >= KB:
115 unit = "kB"
116 res = strconv.FormatFloat(float64(c)/KB, 'f', prec, 64)
117 default:
118 unit = "b"
119 res = strconv.FormatInt(int64(c), 10)
120 }
121
122 if f.Flag(int(' ')) {
123 res += " "
124 }
125 res += unit
126
127 if w, ok := f.Width(); ok {
128 if len(res) < w {
129 pad := strings.Repeat(" ", w-len(res))
130 if f.Flag(int('-')) {
131 res += pad
132 } else {
133 res = pad + res
134 }
135 }
136 }
137
138 f.Write([]byte(res))
139 }
0 package decor
1
2 import (
3 "fmt"
4 "testing"
5 )
6
7 func TestCounterKiB(t *testing.T) {
8 cases := map[string]struct {
9 value int64
10 verb, expected string
11 }{
12 "verb %f": {12345678, "%f", "11.773756MiB"},
13 "verb %.0f": {12345678, "%.0f", "12MiB"},
14 "verb %.1f": {12345678, "%.1f", "11.8MiB"},
15 "verb %.2f": {12345678, "%.2f", "11.77MiB"},
16 "verb %.3f": {12345678, "%.3f", "11.774MiB"},
17
18 "verb % f": {12345678, "% f", "11.773756 MiB"},
19 "verb % .0f": {12345678, "% .0f", "12 MiB"},
20 "verb % .1f": {12345678, "% .1f", "11.8 MiB"},
21 "verb % .2f": {12345678, "% .2f", "11.77 MiB"},
22 "verb % .3f": {12345678, "% .3f", "11.774 MiB"},
23
24 "verb %8.f": {12345678, "%8.f", " 12MiB"},
25 "verb %8.0f": {12345678, "%8.0f", " 12MiB"},
26 "verb %8.1f": {12345678, "%8.1f", " 11.8MiB"},
27 "verb %8.2f": {12345678, "%8.2f", "11.77MiB"},
28 "verb %8.3f": {12345678, "%8.3f", "11.774MiB"},
29
30 "verb % 8.f": {12345678, "% 8.f", " 12 MiB"},
31 "verb % 8.0f": {12345678, "% 8.0f", " 12 MiB"},
32 "verb % 8.1f": {12345678, "% 8.1f", "11.8 MiB"},
33
34 "verb %-8.f": {12345678, "%-8.f", "12MiB "},
35 "verb %-8.0f": {12345678, "%-8.0f", "12MiB "},
36 "verb %-8.1f": {12345678, "%-8.1f", "11.8MiB "},
37 "verb %-8.2f": {12345678, "%8.2f", "11.77MiB"},
38 "verb %-8.3f": {12345678, "%8.3f", "11.774MiB"},
39
40 "verb % -8.f": {12345678, "% -8.f", "12 MiB "},
41 "verb % -8.0f": {12345678, "% -8.0f", "12 MiB "},
42 "verb % -8.1f": {12345678, "% -8.1f", "11.8 MiB"},
43
44 "1000b %f": {1000, "%f", "1000b"},
45 "1000b %d": {1000, "%d", "1000b"},
46 "1000b %s": {1000, "%d", "1000b"},
47 "1024 %f": {1024, "%f", "1.000000KiB"},
48 "1024 %d": {1024, "%d", "1KiB"},
49 "1024 %.1f": {1024, "%.1f", "1.0KiB"},
50 "1024 %s": {1024, "%s", "1.0KiB"},
51 "3*MiB+140KiB %f": {3*MiB + 140*KiB, "%f", "3.136719MiB"},
52 "3*MiB+140KiB %d": {3*MiB + 140*KiB, "%d", "3MiB"},
53 "3*MiB+140KiB %.1f": {3*MiB + 140*KiB, "%.1f", "3.1MiB"},
54 "3*MiB+140KiB %s": {3*MiB + 140*KiB, "%s", "3.1MiB"},
55 "2*GiB %f": {2 * GiB, "%f", "2.000000GiB"},
56 "2*GiB %d": {2 * GiB, "%d", "2GiB"},
57 "2*GiB %.1f": {2 * GiB, "%.1f", "2.0GiB"},
58 "2*GiB %s": {2 * GiB, "%s", "2.0GiB"},
59 "4*TiB %f": {4 * TiB, "%f", "4.000000TiB"},
60 "4*TiB %d": {4 * TiB, "%d", "4TiB"},
61 "4*TiB %.1f": {4 * TiB, "%.1f", "4.0TiB"},
62 "4*TiB %s": {4 * TiB, "%s", "4.0TiB"},
63 }
64 for k, tc := range cases {
65 got := fmt.Sprintf(tc.verb, CounterKiB(tc.value))
66 if got != tc.expected {
67 t.Errorf("%s: Expected: %q, got: %q\n", k, tc.expected, got)
68 }
69 }
70 }
71
72 func TestCounterKB(t *testing.T) {
73 cases := map[string]struct {
74 value int64
75 verb, expected string
76 }{
77 "verb %f": {12345678, "%f", "12.345678MB"},
78 "verb %.0f": {12345678, "%.0f", "12MB"},
79 "verb %.1f": {12345678, "%.1f", "12.3MB"},
80 "verb %.2f": {12345678, "%.2f", "12.35MB"},
81 "verb %.3f": {12345678, "%.3f", "12.346MB"},
82
83 "verb % f": {12345678, "% f", "12.345678 MB"},
84 "verb % .0f": {12345678, "% .0f", "12 MB"},
85 "verb % .1f": {12345678, "% .1f", "12.3 MB"},
86 "verb % .2f": {12345678, "% .2f", "12.35 MB"},
87 "verb % .3f": {12345678, "% .3f", "12.346 MB"},
88
89 "verb %8.f": {12345678, "%8.f", " 12MB"},
90 "verb %8.0f": {12345678, "%8.0f", " 12MB"},
91 "verb %8.1f": {12345678, "%8.1f", " 12.3MB"},
92 "verb %8.2f": {12345678, "%8.2f", " 12.35MB"},
93 "verb %8.3f": {12345678, "%8.3f", "12.346MB"},
94
95 "verb % 8.f": {12345678, "% 8.f", " 12 MB"},
96 "verb % 8.0f": {12345678, "% 8.0f", " 12 MB"},
97 "verb % 8.1f": {12345678, "% 8.1f", " 12.3 MB"},
98
99 "verb %-8.f": {12345678, "%-8.f", "12MB "},
100 "verb %-8.0f": {12345678, "%-8.0f", "12MB "},
101 "verb %-8.1f": {12345678, "%-8.1f", "12.3MB "},
102 "verb %-8.2f": {12345678, "%8.2f", " 12.35MB"},
103 "verb %-8.3f": {12345678, "%8.3f", "12.346MB"},
104
105 "verb % -8.f": {12345678, "% -8.f", "12 MB "},
106 "verb % -8.0f": {12345678, "% -8.0f", "12 MB "},
107 "verb % -8.1f": {12345678, "% -8.1f", "12.3 MB "},
108
109 "1000b %f": {1000, "%f", "1.000000kB"},
110 "1000b %d": {1000, "%d", "1kB"},
111 "1000b %s": {1000, "%d", "1kB"},
112 "1024 %f": {1024, "%f", "1.024000kB"},
113 "1024 %d": {1024, "%d", "1kB"},
114 "1024 %.1f": {1024, "%.1f", "1.0kB"},
115 "1024 %s": {1024, "%s", "1.0kB"},
116 "3*MB+140*KB %f": {3*MB + 140*KB, "%f", "3.140000MB"},
117 "3*MB+140*KB %d": {3*MB + 140*KB, "%d", "3MB"},
118 "3*MB+140*KB %.1f": {3*MB + 140*KB, "%.1f", "3.1MB"},
119 "3*MB+140*KB %s": {3*MB + 140*KB, "%s", "3.1MB"},
120 "2*GB %f": {2 * GB, "%f", "2.000000GB"},
121 "2*GB %d": {2 * GB, "%d", "2GB"},
122 "2*GB %.1f": {2 * GB, "%.1f", "2.0GB"},
123 "2*GB %s": {2 * GB, "%s", "2.0GB"},
124 "4*TB %f": {4 * TB, "%f", "4.000000TB"},
125 "4*TB %d": {4 * TB, "%d", "4TB"},
126 "4*TB %.1f": {4 * TB, "%.1f", "4.0TB"},
127 "4*TB %s": {4 * TB, "%s", "4.0TB"},
128 }
129 for k, tc := range cases {
130 got := fmt.Sprintf(tc.verb, CounterKB(tc.value))
131 if got != tc.expected {
132 t.Errorf("%s: Expected: %q, got: %q\n", k, tc.expected, got)
133 }
134 }
135 }
8585 }
8686
8787 // Counters provides basic counters decorator.
88 // Accepts pairFormat string, something like "%s / %s" to be used in
89 // fmt.Sprintf(pairFormat, current, total) and one of (Unit_KiB/Unit_kB)
90 // constant. If there're more than one bar, and you'd like to synchronize column
91 // width, conf param should have DwidthSync bit set.
92 func Counters(pairFormat string, unit Units, minWidth int, conf byte) DecoratorFunc {
93 format := "%%"
94 if (conf & DidentRight) != 0 {
95 format += "-"
96 }
97 format += "%ds"
98 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
99 current := Format(s.Current).To(unit)
100 total := Format(s.Total).To(unit)
101 str := fmt.Sprintf(pairFormat, current, total)
88 // pairFormat must contain two printf compatible verbs, like "%f" or "%d".
89 // First verb substituted with Current, second one with Total. For example (assuming decor.Unit_KiB used):
90 // "%.1f / %.1f" = "1.0MiB / 12.0MiB" or "% .1f / % .1f" = "1.0 MiB / 12.0 MiB"
91 // unit is one of decor.Unit_KiB/decor.Unit_kB or just zero if you need raw unitless numbers.
92 func Counters(pairFormat string, unit Unit, minWidth int, conf byte) DecoratorFunc {
93 format := "%%"
94 if (conf & DidentRight) != 0 {
95 format += "-"
96 }
97 format += "%ds"
98 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
99 var str string
100 switch unit {
101 case Unit_KiB:
102 str = fmt.Sprintf(pairFormat, CounterKiB(s.Current), CounterKiB(s.Total))
103 case Unit_kB:
104 str = fmt.Sprintf(pairFormat, CounterKB(s.Current), CounterKB(s.Total))
105 default:
106 str = fmt.Sprintf(pairFormat, s.Current, s.Total)
107 }
102108 if (conf & DwidthSync) != 0 {
103109 myWidth <- utf8.RuneCountInString(str)
104110 max := <-maxWidth
+0
-91
decor/format.go less more
0 package decor
1
2 import "fmt"
3
4 const (
5 _ = iota
6 KiB = 1 << (iota * 10)
7 MiB
8 GiB
9 TiB
10 )
11
12 const (
13 KB = 1000
14 MB = KB * 1000
15 GB = MB * 1000
16 TB = GB * 1000
17 )
18
19 const (
20 _ = iota
21 // Unit_KiB Kibibyte = 1024 b
22 Unit_KiB
23 // Unit_kB Kilobyte = 1000 b
24 Unit_kB
25 )
26
27 type Units uint
28
29 func Format(i int64) *formatter {
30 return &formatter{n: i}
31 }
32
33 type formatter struct {
34 n int64
35 unit Units
36 width int
37 }
38
39 func (f *formatter) To(unit Units) *formatter {
40 f.unit = unit
41 return f
42 }
43
44 func (f *formatter) Width(width int) *formatter {
45 f.width = width
46 return f
47 }
48
49 func (f *formatter) String() string {
50 switch f.unit {
51 case Unit_KiB:
52 return formatKiB(f.n)
53 case Unit_kB:
54 return formatKB(f.n)
55 default:
56 return fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
57 }
58 }
59
60 func formatKiB(i int64) (result string) {
61 switch {
62 case i >= TiB:
63 result = fmt.Sprintf("%.1fTiB", float64(i)/TiB)
64 case i >= GiB:
65 result = fmt.Sprintf("%.1fGiB", float64(i)/GiB)
66 case i >= MiB:
67 result = fmt.Sprintf("%.1fMiB", float64(i)/MiB)
68 case i >= KiB:
69 result = fmt.Sprintf("%.1fKiB", float64(i)/KiB)
70 default:
71 result = fmt.Sprintf("%db", i)
72 }
73 return
74 }
75
76 func formatKB(i int64) (result string) {
77 switch {
78 case i >= TB:
79 result = fmt.Sprintf("%.1fTB", float64(i)/TB)
80 case i >= GB:
81 result = fmt.Sprintf("%.1fGB", float64(i)/GB)
82 case i >= MB:
83 result = fmt.Sprintf("%.1fMB", float64(i)/MB)
84 case i >= KB:
85 result = fmt.Sprintf("%.1fkB", float64(i)/KB)
86 default:
87 result = fmt.Sprintf("%db", i)
88 }
89 return
90 }
+0
-43
decor/format_test.go less more
0 package decor_test
1
2 import (
3 "testing"
4
5 "github.com/vbauerster/mpb/decor"
6 )
7
8 func TestFormatNoUnits(t *testing.T) {
9 actual := decor.Format(1234567).String()
10 expected := "1234567"
11 if actual != expected {
12 t.Errorf("Expected %q but found %q", expected, actual)
13 }
14 }
15
16 func TestFormatWidth(t *testing.T) {
17 actual := decor.Format(1234567).Width(10).String()
18 expected := " 1234567"
19 if actual != expected {
20 t.Errorf("Expected %q but found %q", expected, actual)
21 }
22 }
23
24 func TestFormatToBytes(t *testing.T) {
25 inputs := []struct {
26 v int64
27 e string
28 }{
29 {v: 1000, e: "1000b"},
30 {v: 1024, e: "1.0KiB"},
31 {v: 3*decor.MiB + 140*decor.KiB, e: "3.1MiB"},
32 {v: 2 * decor.GiB, e: "2.0GiB"},
33 {v: 4 * decor.TiB, e: "4.0TiB"},
34 }
35
36 for _, input := range inputs {
37 actual := decor.Format(input.v).To(decor.Unit_KiB).String()
38 if actual != input.e {
39 t.Errorf("Expected %q but found %q", input.e, actual)
40 }
41 }
42 }
6161 bar := p.AddBar(size,
6262 mpb.PrependDecorators(
6363 decor.StaticName(name, 0, 0),
64 decor.Counters("%3s / %3s", decor.Unit_KiB, 18, 0),
64 decor.Counters("%6.1f / %6.1f", decor.Unit_KiB, 18, 0),
6565 ),
6666 mpb.AppendDecorators(decor.ETA(5, decor.DwidthSync)),
6767 )