Skip to content

Commit e5e320e

Browse files
method to_string for all units (#504)
close #501 --------- Co-authored-by: Павел Ральников <112890673+PaulRalnikov@users.noreply.github.com>
1 parent fa307e1 commit e5e320e

14 files changed

Lines changed: 242 additions & 16 deletions

source/parser/parse_utils.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ utils::StrExpected<SpeedGbps> parse_speed(const std::string &throughput) {
4545
}
4646

4747
auto [value, unit] = maybe_value_unit.value();
48-
if (unit == "Mbps") {
48+
if (unit == Speed<MBit, Second>::get_suffix()) {
4949
return SpeedGbps(Speed<MBit, Second>(value));
5050
}
51-
if (unit == "Gbps") {
51+
if (unit == Speed<GBit, Second>::get_suffix()) {
5252
return SpeedGbps(value);
5353
}
5454
return std::unexpected("Unsupported throughput unit: " + unit);
@@ -62,16 +62,16 @@ utils::StrExpected<TimeNs> parse_time(const std::string &time) {
6262
}
6363

6464
auto [value, unit] = maybe_value_unit.value();
65-
if (unit == "ns") {
65+
if (unit == Nanosecond::suffix) {
6666
return TimeNs(value);
6767
}
68-
if (unit == "us") {
68+
if (unit == Microsecond::suffix) {
6969
return TimeNs(Time<Microsecond>(value));
7070
}
71-
if (unit == "ms") {
71+
if (unit == Millisecond::suffix) {
7272
return TimeNs(Time<Millisecond>(value));
7373
}
74-
if (unit == "s") {
74+
if (unit == Second::suffix) {
7575
return TimeNs(Time<Second>(value));
7676
}
7777
return std::unexpected("Unsupported time unit: " + unit);
@@ -85,28 +85,28 @@ utils::StrExpected<SizeByte> parse_size(const std::string &size) {
8585
}
8686

8787
auto [value, unit] = maybe_value_unit.value();
88-
if (unit == "b") {
88+
if (unit == Bit::suffix) {
8989
return SizeByte(Size<Bit>(value));
9090
}
91-
if (unit == "B") {
91+
if (unit == Byte::suffix) {
9292
return SizeByte(value);
9393
}
94-
if (unit == "Kb") {
94+
if (unit == KBit::suffix) {
9595
return SizeByte(Size<KBit>(value));
9696
}
97-
if (unit == "KB") {
97+
if (unit == KByte::suffix) {
9898
return SizeByte(Size<KByte>(value));
9999
}
100-
if (unit == "Mb") {
100+
if (unit == MBit::suffix) {
101101
return SizeByte(Size<MBit>(value));
102102
}
103-
if (unit == "MB") {
103+
if (unit == MByte::suffix) {
104104
return SizeByte(Size<MByte>(value));
105105
}
106-
if (unit == "Gb") {
106+
if (unit == GBit::suffix) {
107107
return SizeByte(Size<GBit>(value));
108108
}
109-
if (unit == "GB") {
109+
if (unit == GByte::suffix) {
110110
return SizeByte(Size<GByte>(value));
111111
}
112112
return std::unexpected("Unsupported size unit: " + unit);

source/types.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <memory>
55
#include <string>
66

7-
#include "units/time.hpp"
87
#include "units/units.hpp"
98

109
using TimeNs = Time<Nanosecond>;

source/units/default_formatter.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <spdlog/fmt/bundled/format.h>
4+
5+
template<typename T, typename Char>
6+
requires fmt::formattable<T, Char>
7+
struct DefaultFormatter: fmt::formatter<T, Char>{
8+
9+
template <typename ParseContext>
10+
constexpr auto parse(ParseContext& ctx) {
11+
auto it = ctx.begin();
12+
if (it == ctx.end() || *it == '}') {
13+
// empty format string;
14+
is_empty_format = true;
15+
return it;
16+
}
17+
is_empty_format = false;
18+
return fmt::formatter<T, Char>::parse(ctx);
19+
}
20+
21+
protected:
22+
bool is_empty_format = false;
23+
};

source/units/size.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include <iomanip>
23
#include <concepts>
34
#include <cstdint>
45
#include <iostream>
@@ -7,40 +8,49 @@
78

89
struct Bit {
910
static constexpr uint64_t to_bit_multiplier = 1;
11+
static constexpr std::string_view suffix = "b";
1012
};
1113

1214
struct Byte {
1315
static constexpr uint64_t to_bit_multiplier = (1ull << 3);
16+
static constexpr std::string_view suffix = "B";
1417
};
1518

1619
struct KBit {
1720
static constexpr uint64_t to_bit_multiplier = (1ull << 10);
21+
static constexpr std::string_view suffix = "Kb";
1822
};
1923

2024
struct KByte {
2125
static constexpr uint64_t to_bit_multiplier = (1ull << 13);
26+
static constexpr std::string_view suffix = "KB";
2227
};
2328

2429
struct MBit {
2530
static constexpr uint64_t to_bit_multiplier = (1ull << 20);
31+
static constexpr std::string_view suffix = "Mb";
2632
};
2733

2834
struct MByte {
2935
static constexpr uint64_t to_bit_multiplier = (1ull << 23);
36+
static constexpr std::string_view suffix = "MB";
3037
};
3138

3239
struct GBit {
3340
static constexpr uint64_t to_bit_multiplier = (1ull << 30);
41+
static constexpr std::string_view suffix = "Gb";
3442
};
3543

3644
struct GByte {
3745
static constexpr uint64_t to_bit_multiplier = (1ull << 33);
46+
static constexpr std::string_view suffix = "GB";
3847
};
3948

4049
// Concept for all types that might be the base for Size
4150
template <typename T>
4251
concept IsSizeBase = requires {
4352
{ T::to_bit_multiplier } -> std::convertible_to<uint64_t>;
53+
{ T::suffix } -> std::convertible_to<std::string_view>;
4454
};
4555

4656
template <IsSizeBase TSizeBase>
@@ -117,6 +127,14 @@ class Size {
117127
return m_value_bits != size.m_value_bits;
118128
}
119129

130+
// Outputs the Size with the specified precision and with suffix.
131+
// For example: 1.53 Kb
132+
std::string constexpr to_string(int precision = 2) const{
133+
std::stringstream ss;
134+
ss << std::fixed << std::setprecision(precision) << value() << TSizeBase::suffix;
135+
return ss.str();
136+
}
137+
120138
private:
121139
uint64_t m_value_bits; // Size in bits
122140
};

source/units/size_fmt.hpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include <spdlog/fmt/bundled/format.h>
4+
#include <cstdlib>
5+
6+
#include "size.hpp"
7+
8+
template <IsSizeBase TSizeBase, typename Char>
9+
struct fmt::formatter<Size<TSizeBase>, Char>
10+
: fmt::formatter<uint64_t, Char>
11+
{
12+
using Base = fmt::formatter<uint64_t, Char>;
13+
14+
template <typename ParseContext>
15+
constexpr auto parse(ParseContext& ctx) {
16+
return Base::parse(ctx);
17+
}
18+
19+
template <typename FormatContext>
20+
auto format(const Size<TSizeBase>& t, FormatContext& ctx) const {
21+
auto out = Base::format(t.value(), ctx);
22+
23+
for (auto c : TSizeBase::suffix) {
24+
*out++ = static_cast<Char>(c);
25+
}
26+
27+
return out;
28+
}
29+
};

source/units/speed.hpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
2+
23
#include "size.hpp"
3-
#include "speed.hpp"
4+
#include "time.hpp"
45

56
template <IsSizeBase TSizeBase, IsTimeBase TTimeBase>
67
class Speed {
@@ -71,6 +72,20 @@ class Speed {
7172
return !(*this == speed);
7273
}
7374

75+
// Outputs the Speed with the specified precision and with suffix.
76+
// For example: 3.35 Mb/ms
77+
std::string constexpr to_string(int precision = 2) const{
78+
std::stringstream ss;
79+
ss << std::fixed << std::setprecision(precision) << value() << TSizeBase::suffix << m_separator << TTimeBase::suffix;
80+
return ss.str();
81+
}
82+
83+
static constexpr std::string get_suffix() {
84+
return std::string(TSizeBase::suffix) + std::string(m_separator) + std::string(TTimeBase::suffix);
85+
}
86+
87+
static constexpr std::string_view m_separator = "p";
88+
7489
private:
7590
double m_value_bit_per_ns; // value in bit per nanosecond
7691
};

source/units/speed_fmt.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include <spdlog/fmt/bundled/format.h>
4+
#include <cstdlib>
5+
6+
#include "speed.hpp"
7+
#include "default_formatter.hpp"
8+
9+
template <IsSizeBase TSizeBase, IsTimeBase TTimeBase, typename Char>
10+
struct fmt::formatter<Speed<TSizeBase, TTimeBase>, Char> : DefaultFormatter<double, Char>{
11+
12+
template <typename FormatContext>
13+
auto format(const Speed<TSizeBase, TTimeBase>& t, FormatContext& ctx) const {
14+
auto out = ctx.out();
15+
if (this->is_empty_format) {
16+
out = fmt::format_to(out, this->default_precision_format_str, t.value());
17+
} else {
18+
out = fmt::formatter<double, Char>::format(t.value(), ctx);
19+
}
20+
for (auto c: Speed<TSizeBase, TTimeBase>::get_suffix()){
21+
*out++ = static_cast<Char>(c);
22+
}
23+
return out;
24+
}
25+
private:
26+
static constexpr std::string_view default_precision_format_str = "{:.1f}";
27+
};

source/units/time.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <iomanip>
34
#include <concepts>
45
#include <cstdint>
56
#include <iostream>
@@ -9,24 +10,29 @@
910

1011
struct Nanosecond {
1112
static constexpr uint64_t to_nanoseconds_multiplier = 1;
13+
static constexpr std::string suffix = "ns";
1214
};
1315

1416
struct Microsecond {
1517
static constexpr uint64_t to_nanoseconds_multiplier = 1'000;
18+
static constexpr std::string_view suffix = "us";
1619
};
1720

1821
struct Millisecond {
1922
static constexpr uint64_t to_nanoseconds_multiplier = 1'000'000;
23+
static constexpr std::string_view suffix = "ms";
2024
};
2125

2226
struct Second {
2327
static constexpr uint64_t to_nanoseconds_multiplier = 1'000'000'000;
28+
static constexpr std::string_view suffix = "s";
2429
};
2530

2631
// Concept for all types that might be the base for Time
2732
template <typename T>
2833
concept IsTimeBase = requires {
2934
{ T::to_nanoseconds_multiplier } -> std::convertible_to<uint64_t>;
35+
{ T::suffix } -> std::convertible_to<std::string_view>;
3036
};
3137

3238
template <IsTimeBase TTimeBase>
@@ -98,6 +104,14 @@ class Time {
98104

99105
bool constexpr operator!=(ThisTime time) const { return !operator==(time); }
100106

107+
// Outputs the Time with the specified precision and with suffix.
108+
// For example: 2.37 Ns
109+
std::string constexpr to_string(int precision = 2) const{
110+
std::stringstream ss;
111+
ss << std::fixed << std::setprecision(precision) << value() << TTimeBase::suffix;
112+
return ss.str();
113+
}
114+
101115
private:
102116
double m_value_ns; // Time in nanoseconds
103117
};

source/units/time_fmt.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include <spdlog/fmt/bundled/format.h>
4+
#include <cstdlib>
5+
6+
#include "time.hpp"
7+
#include "default_formatter.hpp"
8+
9+
template <IsTimeBase TTimeBase, typename Char>
10+
struct fmt::formatter<Time<TTimeBase>, Char> : DefaultFormatter<double, Char> {
11+
12+
template <typename FormatContext>
13+
auto format(const Time<TTimeBase>& t, FormatContext& ctx) const {
14+
auto out = ctx.out();
15+
if (this->is_empty_format) {
16+
out = fmt::format_to(out, default_precision_format_str, t.value());
17+
} else {
18+
out = fmt::formatter<double, Char>::format(t.value(), ctx);
19+
}
20+
for (auto c : TTimeBase::suffix) {
21+
*out++ = static_cast<Char>(c);
22+
}
23+
return out;
24+
}
25+
private:
26+
static constexpr std::string_view default_precision_format_str = "{:.1f}";
27+
};

source/units/units.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#include "size.hpp"
44
#include "speed.hpp"
55
#include "time.hpp"
6+
#include "size_fmt.hpp"
7+
#include "speed_fmt.hpp"
8+
#include "time_fmt.hpp"
69

710
template <IsSizeBase TSizeBase, IsTimeBase TTimeBase>
811
constexpr Speed<TSizeBase, TTimeBase> operator/(Size<TSizeBase> size,

0 commit comments

Comments
 (0)